Merge pull request #45 from sartography/feature/form_carbon_theme
Feature/form carbon theme
This commit is contained in:
commit
7bd3ead772
|
@ -0,0 +1 @@
|
|||
/src/themes/carbon
|
File diff suppressed because it is too large
Load Diff
|
@ -13,7 +13,12 @@
|
|||
"@casl/react": "^3.1.0",
|
||||
"@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0",
|
||||
"@monaco-editor/react": "^4.4.5",
|
||||
"@rjsf/core": "^4.2.0",
|
||||
"@mui/material": "^5.10.14",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@rjsf/core": "*",
|
||||
"@rjsf/mui": "^5.0.0-beta.13",
|
||||
"@rjsf/utils": "^5.0.0-beta.13",
|
||||
"@rjsf/validator-ajv8": "^5.0.0-beta.13",
|
||||
"@tanstack/react-table": "^8.2.2",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
|
@ -73,9 +78,9 @@
|
|||
"test": "react-scripts test --coverage",
|
||||
"t": "npm test -- --watchAll=false",
|
||||
"eject": "craco eject",
|
||||
"format": "prettier --write src/**/*.js{,x}",
|
||||
"lint": "./node_modules/.bin/eslint src *.js",
|
||||
"lint:fix": "./node_modules/.bin/eslint --fix src *.js"
|
||||
"format": "prettier --write src/**/*.[tj]s{,x}",
|
||||
"lint": "./node_modules/.bin/eslint src *.[tj]s{,x}",
|
||||
"lint:fix": "./node_modules/.bin/eslint --fix src *.[tj]s{,x}"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
|
|
@ -53,6 +53,7 @@ export default function ButtonWithConfirmation({
|
|||
secondaryButtonText="Cancel"
|
||||
onSecondarySubmit={handleConfirmationPromptCancel}
|
||||
onRequestSubmit={handleConfirmation}
|
||||
onRequestClose={handleConfirmationPromptCancel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -165,11 +165,7 @@ export default function ProcessGroupForm({
|
|||
};
|
||||
|
||||
const formButtons = () => {
|
||||
const buttons = [
|
||||
<Button kind="secondary" type="submit">
|
||||
Submit
|
||||
</Button>,
|
||||
];
|
||||
const buttons = [<Button type="submit">Submit</Button>];
|
||||
if (mode === 'edit') {
|
||||
buttons.push(
|
||||
<ButtonWithConfirmation
|
||||
|
|
|
@ -31,7 +31,7 @@ h1{
|
|||
border: 1px solid #393939;
|
||||
}
|
||||
.cds--btn.button-white-background:hover {
|
||||
background: #525252;
|
||||
background: lightgrey;
|
||||
}
|
||||
|
||||
.cds--breadcrumb-item a.cds--link:hover {
|
||||
|
|
|
@ -3,11 +3,6 @@ import { Link, useNavigate, useSearchParams } from 'react-router-dom';
|
|||
import {
|
||||
Button,
|
||||
Table,
|
||||
// ExpandableTile,
|
||||
// TileAboveTheFoldContent,
|
||||
// TileBelowTheFoldContent,
|
||||
// TextInput,
|
||||
// ClickableTile,
|
||||
// @ts-ignore
|
||||
} from '@carbon/react';
|
||||
import { Can } from '@casl/react';
|
||||
|
|
|
@ -242,6 +242,7 @@ export default function ProcessModelEditDiagram() {
|
|||
secondaryButtonText="Cancel"
|
||||
onSecondarySubmit={handleFileNameCancel}
|
||||
onRequestSubmit={handleFileNameSave}
|
||||
onRequestClose={handleFileNameCancel}
|
||||
>
|
||||
<label>File Name:</label>
|
||||
<span>
|
||||
|
@ -634,6 +635,7 @@ export default function ProcessModelEditDiagram() {
|
|||
primaryButtonText="Close"
|
||||
onRequestSubmit={handleScriptEditorClose}
|
||||
size="lg"
|
||||
onRequestClose={handleScriptEditorClose}
|
||||
>
|
||||
<Editor
|
||||
height={500}
|
||||
|
@ -671,6 +673,7 @@ export default function ProcessModelEditDiagram() {
|
|||
modalHeading="Edit Markdown"
|
||||
primaryButtonText="Close"
|
||||
onRequestSubmit={handleMarkdownEditorClose}
|
||||
onRequestClose={handleMarkdownEditorClose}
|
||||
size="lg"
|
||||
>
|
||||
<MDEditor
|
||||
|
|
|
@ -388,6 +388,7 @@ export default function ProcessModelShow() {
|
|||
|
||||
const handleFileUploadCancel = () => {
|
||||
setShowFileUploadModal(false);
|
||||
setFilesToUpload(null);
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: any) => {
|
||||
|
@ -405,6 +406,7 @@ export default function ProcessModelShow() {
|
|||
});
|
||||
}
|
||||
setShowFileUploadModal(false);
|
||||
setFilesToUpload(null);
|
||||
};
|
||||
|
||||
const fileUploadModal = () => {
|
||||
|
@ -432,6 +434,7 @@ export default function ProcessModelShow() {
|
|||
iconDescription="Delete file"
|
||||
name=""
|
||||
multiple={false}
|
||||
onDelete={() => setFilesToUpload(null)}
|
||||
onChange={(event: any) => setFilesToUpload(event.target.files)}
|
||||
/>
|
||||
</Modal>
|
||||
|
|
|
@ -132,6 +132,7 @@ export default function ReactFormEditor() {
|
|||
secondaryButtonText="Cancel"
|
||||
onSecondarySubmit={handleFileNameCancel}
|
||||
onRequestSubmit={handleFileNameSave}
|
||||
onRequestClose={handleFileNameCancel}
|
||||
>
|
||||
<label>File Name:</label>
|
||||
<span>
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { useContext, useEffect, useState } from 'react';
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||
import Form from '@rjsf/core';
|
||||
import validator from '@rjsf/validator-ajv8';
|
||||
|
||||
// @ts-ignore
|
||||
import { Button, Stack } from '@carbon/react';
|
||||
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import Form from '../themes/carbon';
|
||||
import HttpService from '../services/HttpService';
|
||||
import ErrorContext from '../contexts/ErrorContext';
|
||||
import { modifyProcessModelPath } from '../helpers';
|
||||
|
@ -144,6 +146,7 @@ export default function TaskShow() {
|
|||
onSubmit={handleFormSubmit}
|
||||
schema={jsonSchema}
|
||||
uiSchema={formUiSchema}
|
||||
validator={validator}
|
||||
>
|
||||
{reactFragmentToHideSubmitButton}
|
||||
</Form>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import { IconButtonProps } from '@rjsf/utils';
|
||||
|
||||
const AddButton: React.ComponentType<IconButtonProps> = ({
|
||||
uiSchema,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<IconButton title="Add Item" {...props} color="primary">
|
||||
<AddIcon />
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddButton;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './AddButton';
|
||||
export * from './AddButton';
|
|
@ -0,0 +1,72 @@
|
|||
import React, { CSSProperties } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import { ArrayFieldTemplateItemType } from '@rjsf/utils';
|
||||
|
||||
function ArrayFieldItemTemplate(props: ArrayFieldTemplateItemType) {
|
||||
const {
|
||||
children,
|
||||
disabled,
|
||||
hasToolbar,
|
||||
hasMoveDown,
|
||||
hasMoveUp,
|
||||
hasRemove,
|
||||
index,
|
||||
onDropIndexClick,
|
||||
onReorderClick,
|
||||
readonly,
|
||||
uiSchema,
|
||||
registry,
|
||||
} = props;
|
||||
const { MoveDownButton, MoveUpButton, RemoveButton } =
|
||||
registry.templates.ButtonTemplates;
|
||||
const btnStyle: CSSProperties = {
|
||||
flex: 1,
|
||||
paddingLeft: 6,
|
||||
paddingRight: 6,
|
||||
fontWeight: 'bold',
|
||||
minWidth: 0,
|
||||
};
|
||||
return (
|
||||
<Grid container alignItems="center">
|
||||
<Grid item xs style={{ overflow: 'auto' }}>
|
||||
<Box mb={2}>
|
||||
<Paper elevation={2}>
|
||||
<Box p={2}>{children}</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Grid>
|
||||
{hasToolbar && (
|
||||
<Grid item>
|
||||
{(hasMoveUp || hasMoveDown) && (
|
||||
<MoveUpButton
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly || !hasMoveUp}
|
||||
onClick={onReorderClick(index, index - 1)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
)}
|
||||
{(hasMoveUp || hasMoveDown) && (
|
||||
<MoveDownButton
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly || !hasMoveDown}
|
||||
onClick={onReorderClick(index, index + 1)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
)}
|
||||
{hasRemove && (
|
||||
<RemoveButton
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly}
|
||||
onClick={onDropIndexClick(index)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export default ArrayFieldItemTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './ArrayFieldItemTemplate';
|
||||
export * from './ArrayFieldItemTemplate';
|
|
@ -0,0 +1,90 @@
|
|||
import React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import {
|
||||
ArrayFieldTemplateItemType,
|
||||
ArrayFieldTemplateProps,
|
||||
getTemplate,
|
||||
getUiOptions,
|
||||
} from '@rjsf/utils';
|
||||
|
||||
function ArrayFieldTemplate(props: ArrayFieldTemplateProps) {
|
||||
const {
|
||||
canAdd,
|
||||
disabled,
|
||||
idSchema,
|
||||
uiSchema,
|
||||
items,
|
||||
onAddClick,
|
||||
readonly,
|
||||
registry,
|
||||
required,
|
||||
schema,
|
||||
title,
|
||||
} = props;
|
||||
const uiOptions = getUiOptions(uiSchema);
|
||||
const ArrayFieldDescriptionTemplate =
|
||||
getTemplate<'ArrayFieldDescriptionTemplate'>(
|
||||
'ArrayFieldDescriptionTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const ArrayFieldItemTemplate = getTemplate<'ArrayFieldItemTemplate'>(
|
||||
'ArrayFieldItemTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const ArrayFieldTitleTemplate = getTemplate<'ArrayFieldTitleTemplate'>(
|
||||
'ArrayFieldTitleTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const {
|
||||
ButtonTemplates: { AddButton },
|
||||
} = registry.templates;
|
||||
return (
|
||||
<Paper elevation={2}>
|
||||
<Box p={2}>
|
||||
<ArrayFieldTitleTemplate
|
||||
idSchema={idSchema}
|
||||
title={uiOptions.title || title}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
required={required}
|
||||
registry={registry}
|
||||
/>
|
||||
<ArrayFieldDescriptionTemplate
|
||||
idSchema={idSchema}
|
||||
description={uiOptions.description || schema.description}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
<Grid container key={`array-item-list-${idSchema.$id}`}>
|
||||
{items &&
|
||||
items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType) => (
|
||||
<ArrayFieldItemTemplate key={key} {...itemProps} />
|
||||
))}
|
||||
{canAdd && (
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item>
|
||||
<Box mt={2}>
|
||||
<AddButton
|
||||
className="array-item-add"
|
||||
onClick={onAddClick}
|
||||
disabled={disabled || readonly}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
|
||||
export default ArrayFieldTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './ArrayFieldTemplate';
|
||||
export * from './ArrayFieldTemplate';
|
|
@ -0,0 +1,114 @@
|
|||
// @ts-ignore
|
||||
import { TextInput } from '@carbon/react';
|
||||
import {
|
||||
getInputProps,
|
||||
FormContextType,
|
||||
RJSFSchema,
|
||||
StrictRJSFSchema,
|
||||
WidgetProps,
|
||||
} from '@rjsf/utils';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
/** The `BaseInputTemplate` is the template to use to render the basic `<input>` component for the `core` theme.
|
||||
* It is used as the template for rendering many of the <input> based widgets that differ by `type` and callbacks only.
|
||||
* It can be customized/overridden for other themes or individual implementations as needed.
|
||||
*
|
||||
* @param props - The `WidgetProps` for this template
|
||||
*/
|
||||
export default function BaseInputTemplate<
|
||||
T = any,
|
||||
S extends StrictRJSFSchema = RJSFSchema,
|
||||
F extends FormContextType = any
|
||||
>(props: WidgetProps<T, S, F>) {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
readonly,
|
||||
disabled,
|
||||
autofocus,
|
||||
label,
|
||||
onBlur,
|
||||
onFocus,
|
||||
onChange,
|
||||
required,
|
||||
options,
|
||||
schema,
|
||||
uiSchema,
|
||||
formContext,
|
||||
registry,
|
||||
rawErrors,
|
||||
type,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
// Note: since React 15.2.0 we can't forward unknown element attributes, so we
|
||||
// exclude the "options" and "schema" ones here.
|
||||
if (!id) {
|
||||
console.log('No id for', props);
|
||||
throw new Error(`no id for props ${JSON.stringify(props)}`);
|
||||
}
|
||||
const inputProps = {
|
||||
...rest,
|
||||
...getInputProps<T, S, F>(schema, type, options),
|
||||
};
|
||||
|
||||
let inputValue;
|
||||
if (inputProps.type === 'number' || inputProps.type === 'integer') {
|
||||
inputValue = value || value === 0 ? value : '';
|
||||
} else {
|
||||
inputValue = value == null ? '' : value;
|
||||
}
|
||||
|
||||
const _onChange = useCallback(
|
||||
({ target: { value } }: React.ChangeEvent<HTMLInputElement>) =>
|
||||
onChange(value === '' ? options.emptyValue : value),
|
||||
[onChange, options]
|
||||
);
|
||||
const _onBlur = useCallback(
|
||||
({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, value),
|
||||
[onBlur, id]
|
||||
);
|
||||
const _onFocus = useCallback(
|
||||
({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onFocus(id, value),
|
||||
[onFocus, id]
|
||||
);
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TextInput
|
||||
id={id}
|
||||
name={id}
|
||||
labelText={labelToUse}
|
||||
autoFocus={autofocus}
|
||||
disabled={disabled || readonly}
|
||||
value={value || value === 0 ? value : ''}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...inputProps}
|
||||
/>
|
||||
{Array.isArray(schema.examples) && (
|
||||
<datalist key={`datalist_${id}`} id={`examples_${id}`}>
|
||||
{[
|
||||
...new Set(
|
||||
schema.examples.concat(schema.default ? [schema.default] : [])
|
||||
),
|
||||
].map((example: any) => (
|
||||
<option key={example} value={example} />
|
||||
))}
|
||||
</datalist>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './BaseInputTemplate';
|
||||
export * from './BaseInputTemplate';
|
|
@ -0,0 +1,8 @@
|
|||
import { ComponentType } from 'react';
|
||||
import { withTheme, FormProps } from '@rjsf/core';
|
||||
|
||||
import Theme from '../Theme';
|
||||
|
||||
const CarbonForm: ComponentType<FormProps> = withTheme(Theme);
|
||||
|
||||
export default CarbonForm;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './CarbonForm';
|
||||
export * from './CarbonForm';
|
|
@ -0,0 +1,52 @@
|
|||
import React from 'react';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import { schemaRequiresTrueValue, WidgetProps } from '@rjsf/utils';
|
||||
|
||||
function CheckboxWidget(props: WidgetProps) {
|
||||
const {
|
||||
schema,
|
||||
id,
|
||||
value,
|
||||
disabled,
|
||||
readonly,
|
||||
label,
|
||||
autofocus,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
} = props;
|
||||
// Because an unchecked checkbox will cause html5 validation to fail, only add
|
||||
// the "required" attribute if the field value must be "true", due to the
|
||||
// "const" or "enum" keywords
|
||||
const required = schemaRequiresTrueValue(schema);
|
||||
|
||||
const _onChange = (_: any, checked: boolean) => onChange(checked);
|
||||
const _onBlur = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLButtonElement>) => onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLButtonElement>) => onFocus(id, value);
|
||||
|
||||
return (
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
id={id}
|
||||
name={id}
|
||||
checked={typeof value === 'undefined' ? false : Boolean(value)}
|
||||
required={required}
|
||||
disabled={disabled || readonly}
|
||||
autoFocus={autofocus}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
}
|
||||
label={label || ''}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default CheckboxWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './CheckboxWidget';
|
||||
export * from './CheckboxWidget';
|
|
@ -0,0 +1,93 @@
|
|||
import React from 'react';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import FormGroup from '@mui/material/FormGroup';
|
||||
import FormLabel from '@mui/material/FormLabel';
|
||||
import { WidgetProps } from '@rjsf/utils';
|
||||
|
||||
const selectValue = (value: any, selected: any, all: any) => {
|
||||
const at = all.indexOf(value);
|
||||
const updated = selected.slice(0, at).concat(value, selected.slice(at));
|
||||
|
||||
// As inserting values at predefined index positions doesn't work with empty
|
||||
// arrays, we need to reorder the updated selection to match the initial order
|
||||
return updated.sort((a: any, b: any) => all.indexOf(a) > all.indexOf(b));
|
||||
};
|
||||
|
||||
const deselectValue = (value: any, selected: any) => {
|
||||
return selected.filter((v: any) => v !== value);
|
||||
};
|
||||
|
||||
function CheckboxesWidget({
|
||||
schema,
|
||||
label,
|
||||
id,
|
||||
disabled,
|
||||
options,
|
||||
value,
|
||||
autofocus,
|
||||
readonly,
|
||||
required,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
}: WidgetProps) {
|
||||
const { enumOptions, enumDisabled, inline } = options;
|
||||
|
||||
const _onChange =
|
||||
(option: any) =>
|
||||
({ target: { checked } }: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const all = (enumOptions as any).map(({ value }: any) => value);
|
||||
|
||||
if (checked) {
|
||||
onChange(selectValue(option.value, value, all));
|
||||
} else {
|
||||
onChange(deselectValue(option.value, value));
|
||||
}
|
||||
};
|
||||
|
||||
const _onBlur = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLButtonElement>) => onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLButtonElement>) => onFocus(id, value);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormLabel required={required} htmlFor={id}>
|
||||
{label || schema.title}
|
||||
</FormLabel>
|
||||
<FormGroup id={id} row={!!inline}>
|
||||
{Array.isArray(enumOptions) &&
|
||||
enumOptions.map((option, index: number) => {
|
||||
const checked = value.indexOf(option.value) !== -1;
|
||||
const itemDisabled =
|
||||
Array.isArray(enumDisabled) &&
|
||||
enumDisabled.indexOf(option.value) !== -1;
|
||||
const checkbox = (
|
||||
<Checkbox
|
||||
id={`${id}-${option.value}`}
|
||||
name={id}
|
||||
checked={checked}
|
||||
disabled={disabled || itemDisabled || readonly}
|
||||
autoFocus={autofocus && index === 0}
|
||||
onChange={_onChange(option)}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<FormControlLabel
|
||||
control={checkbox}
|
||||
key={option.value}
|
||||
label={option.label}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</FormGroup>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default CheckboxesWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './CheckboxesWidget';
|
||||
export * from './CheckboxesWidget';
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import { getTemplate, localToUTC, utcToLocal, WidgetProps } from '@rjsf/utils';
|
||||
|
||||
function DateTimeWidget(props: WidgetProps) {
|
||||
const { options, registry } = props;
|
||||
const BaseInputTemplate = getTemplate<'BaseInputTemplate'>(
|
||||
'BaseInputTemplate',
|
||||
registry,
|
||||
options
|
||||
);
|
||||
const value = utcToLocal(props.value);
|
||||
const onChange = (value: any) => {
|
||||
props.onChange(localToUTC(value));
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseInputTemplate
|
||||
type="datetime-local"
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
{...props}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default DateTimeWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './DateTimeWidget';
|
||||
export * from './DateTimeWidget';
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react';
|
||||
import { getTemplate, WidgetProps } from '@rjsf/utils';
|
||||
|
||||
function DateWidget(props: WidgetProps) {
|
||||
const { options, registry } = props;
|
||||
const BaseInputTemplate = getTemplate<'BaseInputTemplate'>(
|
||||
'BaseInputTemplate',
|
||||
registry,
|
||||
options
|
||||
);
|
||||
return (
|
||||
<BaseInputTemplate
|
||||
type="date"
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default DateWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './DateWidget';
|
||||
export * from './DateWidget';
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { DescriptionFieldProps } from '@rjsf/utils';
|
||||
|
||||
function DescriptionField({ description, id }: DescriptionFieldProps) {
|
||||
if (description) {
|
||||
return (
|
||||
<Typography id={id} variant="subtitle2" style={{ marginTop: '5px' }}>
|
||||
{description}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default DescriptionField;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './DescriptionField';
|
||||
export * from './DescriptionField';
|
|
@ -0,0 +1,16 @@
|
|||
import { ErrorListProps } from '@rjsf/utils';
|
||||
// @ts-ignore
|
||||
import { Tag } from '@carbon/react';
|
||||
|
||||
function ErrorList({ errors }: ErrorListProps) {
|
||||
if (errors) {
|
||||
return (
|
||||
<Tag type="red" size="md" title="Fill Required Fields">
|
||||
Please fill out required fields
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default ErrorList;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './ErrorList';
|
||||
export * from './ErrorList';
|
|
@ -0,0 +1,9 @@
|
|||
import { FieldErrorProps } from '@rjsf/utils';
|
||||
|
||||
/** The `FieldErrorTemplate` component renders the errors local to the particular field
|
||||
*
|
||||
* @param props - The `FieldErrorProps` for the errors being rendered
|
||||
*/
|
||||
export default function FieldErrorTemplate(_props: FieldErrorProps) {
|
||||
return null;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './FieldErrorTemplate';
|
||||
export * from './FieldErrorTemplate';
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react';
|
||||
import { FieldHelpProps } from '@rjsf/utils';
|
||||
import FormHelperText from '@mui/material/FormHelperText';
|
||||
|
||||
/** The `FieldHelpTemplate` component renders any help desired for a field
|
||||
*
|
||||
* @param props - The `FieldHelpProps` to be rendered
|
||||
*/
|
||||
export default function FieldHelpTemplate(props: FieldHelpProps) {
|
||||
const { idSchema, help } = props;
|
||||
if (!help) {
|
||||
return null;
|
||||
}
|
||||
const id = `${idSchema.$id}__help`;
|
||||
return <FormHelperText id={id}>{help}</FormHelperText>;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './FieldHelpTemplate';
|
||||
export * from './FieldHelpTemplate';
|
|
@ -0,0 +1,64 @@
|
|||
import React from 'react';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { FieldTemplateProps, getTemplate, getUiOptions } from '@rjsf/utils';
|
||||
|
||||
function FieldTemplate({
|
||||
id,
|
||||
children,
|
||||
classNames,
|
||||
disabled,
|
||||
displayLabel,
|
||||
hidden,
|
||||
label,
|
||||
onDropPropertyClick,
|
||||
onKeyChange,
|
||||
readonly,
|
||||
required,
|
||||
rawErrors = [],
|
||||
errors,
|
||||
help,
|
||||
rawDescription,
|
||||
schema,
|
||||
uiSchema,
|
||||
registry,
|
||||
}: FieldTemplateProps) {
|
||||
const uiOptions = getUiOptions(uiSchema);
|
||||
const WrapIfAdditionalTemplate = getTemplate<'WrapIfAdditionalTemplate'>(
|
||||
'WrapIfAdditionalTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
|
||||
if (hidden) {
|
||||
return <div style={{ display: 'none' }}>{children}</div>;
|
||||
}
|
||||
return (
|
||||
<WrapIfAdditionalTemplate
|
||||
classNames={classNames}
|
||||
disabled={disabled}
|
||||
id={id}
|
||||
label={label}
|
||||
onDropPropertyClick={onDropPropertyClick}
|
||||
onKeyChange={onKeyChange}
|
||||
readonly={readonly}
|
||||
required={required}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
>
|
||||
<FormControl fullWidth error={!!rawErrors.length} required={required}>
|
||||
{children}
|
||||
{displayLabel && rawDescription ? (
|
||||
<Typography variant="caption" color="textSecondary">
|
||||
{rawDescription}
|
||||
</Typography>
|
||||
) : null}
|
||||
{errors}
|
||||
{help}
|
||||
</FormControl>
|
||||
</WrapIfAdditionalTemplate>
|
||||
);
|
||||
}
|
||||
|
||||
export default FieldTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './FieldTemplate';
|
||||
export * from './FieldTemplate';
|
|
@ -0,0 +1,55 @@
|
|||
import React from 'react';
|
||||
import IconButton, {
|
||||
IconButtonProps as MuiIconButtonProps,
|
||||
} from '@mui/material/IconButton';
|
||||
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
||||
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
||||
import RemoveIcon from '@mui/icons-material/Remove';
|
||||
import { IconButtonProps } from '@rjsf/utils';
|
||||
|
||||
export default function MuiIconButton(props: IconButtonProps) {
|
||||
const { icon, color, uiSchema, ...otherProps } = props;
|
||||
return (
|
||||
<IconButton
|
||||
{...otherProps}
|
||||
size="small"
|
||||
color={color as MuiIconButtonProps['color']}
|
||||
>
|
||||
{icon}
|
||||
</IconButton>
|
||||
);
|
||||
}
|
||||
|
||||
export function MoveDownButton(props: IconButtonProps) {
|
||||
return (
|
||||
<MuiIconButton
|
||||
title="Move down"
|
||||
{...props}
|
||||
icon={<ArrowDownwardIcon fontSize="small" />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function MoveUpButton(props: IconButtonProps) {
|
||||
return (
|
||||
<MuiIconButton
|
||||
title="Move up"
|
||||
{...props}
|
||||
icon={<ArrowUpwardIcon fontSize="small" />}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function RemoveButton(props: IconButtonProps) {
|
||||
const { iconType, ...otherProps } = props;
|
||||
return (
|
||||
<MuiIconButton
|
||||
title="Remove"
|
||||
{...otherProps}
|
||||
color="error"
|
||||
icon={
|
||||
<RemoveIcon fontSize={iconType === 'default' ? undefined : 'small'} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './IconButton';
|
||||
export * from './IconButton';
|
|
@ -0,0 +1,89 @@
|
|||
import React from 'react';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import {
|
||||
ObjectFieldTemplateProps,
|
||||
canExpand,
|
||||
getTemplate,
|
||||
getUiOptions,
|
||||
} from '@rjsf/utils';
|
||||
|
||||
function ObjectFieldTemplate({
|
||||
description,
|
||||
title,
|
||||
properties,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
uiSchema,
|
||||
idSchema,
|
||||
schema,
|
||||
formData,
|
||||
onAddClick,
|
||||
registry,
|
||||
}: ObjectFieldTemplateProps) {
|
||||
const uiOptions = getUiOptions(uiSchema);
|
||||
const TitleFieldTemplate = getTemplate<'TitleFieldTemplate'>(
|
||||
'TitleFieldTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate'>(
|
||||
'DescriptionFieldTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const {
|
||||
ButtonTemplates: { AddButton },
|
||||
} = registry.templates;
|
||||
return (
|
||||
<>
|
||||
{(uiOptions.title || title) && (
|
||||
<TitleFieldTemplate
|
||||
id={`${idSchema.$id}-title`}
|
||||
title={title}
|
||||
required={required}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
)}
|
||||
{(uiOptions.description || description) && (
|
||||
<DescriptionFieldTemplate
|
||||
id={`${idSchema.$id}-description`}
|
||||
description={uiOptions.description || description!}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
)}
|
||||
<Grid container spacing={2} style={{ marginTop: '10px' }}>
|
||||
{properties.map((element, index) =>
|
||||
// Remove the <Grid> if the inner element is hidden as the <Grid>
|
||||
// itself would otherwise still take up space.
|
||||
element.hidden ? (
|
||||
element.content
|
||||
) : (
|
||||
<Grid item xs={12} key={index} style={{ marginBottom: '10px' }}>
|
||||
{element.content}
|
||||
</Grid>
|
||||
)
|
||||
)}
|
||||
{canExpand(schema, uiSchema, formData) && (
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item>
|
||||
<AddButton
|
||||
className="object-property-expand"
|
||||
onClick={onAddClick(schema)}
|
||||
disabled={disabled || readonly}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ObjectFieldTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './ObjectFieldTemplate';
|
||||
export * from './ObjectFieldTemplate';
|
|
@ -0,0 +1,62 @@
|
|||
import React from 'react';
|
||||
// @ts-ignore
|
||||
import { RadioButtonGroup, RadioButton } from '@carbon/react';
|
||||
import { WidgetProps } from '@rjsf/utils';
|
||||
|
||||
function RadioWidget({
|
||||
id,
|
||||
schema,
|
||||
options,
|
||||
value,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
label,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
}: WidgetProps) {
|
||||
const { enumOptions, enumDisabled } = options;
|
||||
|
||||
const localOnChange = (_: any, value: any) =>
|
||||
onChange(schema.type == 'boolean' ? value !== 'false' : value);
|
||||
const _onBlur = ({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, value);
|
||||
|
||||
const row = options ? options.inline : false;
|
||||
|
||||
return (
|
||||
<RadioButtonGroup
|
||||
orientation="vertical"
|
||||
id={id}
|
||||
name={id}
|
||||
value={`${value}`}
|
||||
row={row as boolean}
|
||||
legendText={label || schema.title}
|
||||
onChange={localOnChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
>
|
||||
{Array.isArray(enumOptions) &&
|
||||
enumOptions.map((option) => {
|
||||
const itemDisabled =
|
||||
Array.isArray(enumDisabled) &&
|
||||
enumDisabled.indexOf(option.value) !== -1;
|
||||
return (
|
||||
<RadioButton
|
||||
labelText={`${option.label}`}
|
||||
value={`${option.value}`}
|
||||
id={`${id}-${option.value}`}
|
||||
key={option.value}
|
||||
disabled={disabled || itemDisabled || readonly}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RadioButtonGroup>
|
||||
);
|
||||
}
|
||||
|
||||
export default RadioWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './RadioWidget';
|
||||
export * from './RadioWidget';
|
|
@ -0,0 +1,47 @@
|
|||
import React from 'react';
|
||||
import FormLabel from '@mui/material/FormLabel';
|
||||
import Slider from '@mui/material/Slider';
|
||||
import { WidgetProps, rangeSpec } from '@rjsf/utils';
|
||||
|
||||
function RangeWidget({
|
||||
value,
|
||||
readonly,
|
||||
disabled,
|
||||
onBlur,
|
||||
onFocus,
|
||||
options,
|
||||
schema,
|
||||
onChange,
|
||||
required,
|
||||
label,
|
||||
id,
|
||||
}: WidgetProps) {
|
||||
const sliderProps = { value, label, id, name: id, ...rangeSpec(schema) };
|
||||
|
||||
const _onChange = (_: any, value?: number | number[]) => {
|
||||
onChange(value ? options.emptyValue : value);
|
||||
};
|
||||
const _onBlur = ({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, value);
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLInputElement>) => onFocus(id, value);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormLabel required={required} id={id}>
|
||||
{label}
|
||||
</FormLabel>
|
||||
<Slider
|
||||
disabled={disabled || readonly}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
valueLabelDisplay="auto"
|
||||
{...sliderProps}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default RangeWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './RangeWidget';
|
||||
export * from './RangeWidget';
|
|
@ -0,0 +1,76 @@
|
|||
// @ts-ignore
|
||||
import { Select, SelectItem } from '@carbon/react';
|
||||
import { WidgetProps, processSelectValue } from '@rjsf/utils';
|
||||
|
||||
function SelectWidget({
|
||||
schema,
|
||||
id,
|
||||
options,
|
||||
label,
|
||||
required,
|
||||
disabled,
|
||||
readonly,
|
||||
value,
|
||||
multiple,
|
||||
autofocus,
|
||||
onChange,
|
||||
onBlur,
|
||||
onFocus,
|
||||
uiSchema,
|
||||
rawErrors = [],
|
||||
}: WidgetProps) {
|
||||
const { enumOptions, enumDisabled } = options;
|
||||
|
||||
const emptyValue = multiple ? [] : '';
|
||||
|
||||
const _onChange = ({
|
||||
target: { value },
|
||||
}: React.ChangeEvent<{ name?: string; value: unknown }>) =>
|
||||
onChange(processSelectValue(schema, value, options));
|
||||
const _onBlur = ({ target: { value } }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onBlur(id, processSelectValue(schema, value, options));
|
||||
const _onFocus = ({
|
||||
target: { value },
|
||||
}: React.FocusEvent<HTMLInputElement>) =>
|
||||
onFocus(id, processSelectValue(schema, value, options));
|
||||
|
||||
let labelToUse = label;
|
||||
if (uiSchema && uiSchema['ui:title']) {
|
||||
labelToUse = uiSchema['ui:title'];
|
||||
} else if (schema && schema.title) {
|
||||
labelToUse = schema.title;
|
||||
}
|
||||
if (required) {
|
||||
labelToUse = `${labelToUse}*`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
id={id}
|
||||
name={id}
|
||||
labelText={labelToUse}
|
||||
select
|
||||
value={typeof value === 'undefined' ? emptyValue : value}
|
||||
disabled={disabled || readonly}
|
||||
autoFocus={autofocus}
|
||||
error={rawErrors.length > 0}
|
||||
onChange={_onChange}
|
||||
onBlur={_onBlur}
|
||||
onFocus={_onFocus}
|
||||
InputLabelProps={{
|
||||
shrink: true,
|
||||
}}
|
||||
SelectProps={{
|
||||
multiple: typeof multiple === 'undefined' ? false : multiple,
|
||||
}}
|
||||
>
|
||||
{(enumOptions as any).map(({ value, label }: any, i: number) => {
|
||||
const disabled: any =
|
||||
enumDisabled && (enumDisabled as any).indexOf(value) != -1;
|
||||
return <SelectItem text={label} value={value} disabled={disabled} />;
|
||||
})}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './SelectWidget';
|
||||
export * from './SelectWidget';
|
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
// import Box from '@mui/material/Box';
|
||||
// @ts-ignore
|
||||
import { Button } from '@carbon/react';
|
||||
import { SubmitButtonProps, getSubmitButtonOptions } from '@rjsf/utils';
|
||||
|
||||
// const SubmitButton: React.ComponentType<SubmitButtonProps> = (props) => {
|
||||
function SubmitButton(props: SubmitButtonProps) {
|
||||
const { uiSchema } = props;
|
||||
const {
|
||||
submitText,
|
||||
norender,
|
||||
props: submitButtonProps,
|
||||
} = getSubmitButtonOptions(uiSchema);
|
||||
if (norender) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
className="react-json-schema-form-submit-button"
|
||||
type="submit"
|
||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||
{...submitButtonProps}
|
||||
>
|
||||
{submitText}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
export default SubmitButton;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './SubmitButton';
|
||||
export * from './SubmitButton';
|
|
@ -0,0 +1,35 @@
|
|||
import AddButton from '../AddButton';
|
||||
import ArrayFieldItemTemplate from '../ArrayFieldItemTemplate';
|
||||
import ArrayFieldTemplate from '../ArrayFieldTemplate';
|
||||
import BaseInputTemplate from '../BaseInputTemplate';
|
||||
import DescriptionField from '../DescriptionField';
|
||||
import ErrorList from '../ErrorList';
|
||||
import { MoveDownButton, MoveUpButton, RemoveButton } from '../IconButton';
|
||||
import FieldErrorTemplate from '../FieldErrorTemplate';
|
||||
import FieldHelpTemplate from '../FieldHelpTemplate';
|
||||
import FieldTemplate from '../FieldTemplate';
|
||||
import ObjectFieldTemplate from '../ObjectFieldTemplate';
|
||||
import SubmitButton from '../SubmitButton';
|
||||
import TitleField from '../TitleField';
|
||||
import WrapIfAdditionalTemplate from '../WrapIfAdditionalTemplate';
|
||||
|
||||
export default {
|
||||
ArrayFieldItemTemplate,
|
||||
ArrayFieldTemplate,
|
||||
BaseInputTemplate,
|
||||
ButtonTemplates: {
|
||||
AddButton,
|
||||
MoveDownButton,
|
||||
MoveUpButton,
|
||||
RemoveButton,
|
||||
SubmitButton,
|
||||
},
|
||||
DescriptionFieldTemplate: DescriptionField,
|
||||
ErrorListTemplate: ErrorList,
|
||||
FieldErrorTemplate,
|
||||
FieldHelpTemplate,
|
||||
FieldTemplate,
|
||||
ObjectFieldTemplate,
|
||||
TitleFieldTemplate: TitleField,
|
||||
WrapIfAdditionalTemplate,
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './Templates';
|
||||
export * from './Templates';
|
|
@ -0,0 +1,20 @@
|
|||
import React from 'react';
|
||||
import { getTemplate, WidgetProps } from '@rjsf/utils';
|
||||
|
||||
function TextareaWidget(props: WidgetProps) {
|
||||
const { options, registry } = props;
|
||||
const BaseInputTemplate = getTemplate<'BaseInputTemplate'>(
|
||||
'BaseInputTemplate',
|
||||
registry,
|
||||
options
|
||||
);
|
||||
|
||||
let rows: string | number = 5;
|
||||
if (typeof options.rows === 'string' || typeof options.rows === 'number') {
|
||||
rows = options.rows;
|
||||
}
|
||||
|
||||
return <BaseInputTemplate {...props} multiline rows={rows} />;
|
||||
}
|
||||
|
||||
export default TextareaWidget;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './TextareaWidget';
|
||||
export * from './TextareaWidget';
|
|
@ -0,0 +1,11 @@
|
|||
import { ThemeProps } from '@rjsf/core';
|
||||
|
||||
import Templates from '../Templates';
|
||||
import Widgets from '../Widgets';
|
||||
|
||||
const Theme: ThemeProps = {
|
||||
templates: Templates,
|
||||
widgets: Widgets,
|
||||
};
|
||||
|
||||
export default Theme;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './Theme';
|
||||
export * from './Theme';
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { TitleFieldProps } from '@rjsf/utils';
|
||||
|
||||
function TitleField({ id, title }: TitleFieldProps) {
|
||||
return (
|
||||
<Box id={id} mb={1} mt={1}>
|
||||
<Typography variant="h5">{title}</Typography>
|
||||
<Divider />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default TitleField;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './TitleField';
|
||||
export * from './TitleField';
|
|
@ -0,0 +1,19 @@
|
|||
import CheckboxWidget from '../CheckboxWidget/CheckboxWidget';
|
||||
import CheckboxesWidget from '../CheckboxesWidget/CheckboxesWidget';
|
||||
import DateWidget from '../DateWidget/DateWidget';
|
||||
import DateTimeWidget from '../DateTimeWidget/DateTimeWidget';
|
||||
import RadioWidget from '../RadioWidget/RadioWidget';
|
||||
import RangeWidget from '../RangeWidget/RangeWidget';
|
||||
import SelectWidget from '../SelectWidget/SelectWidget';
|
||||
import TextareaWidget from '../TextareaWidget/TextareaWidget';
|
||||
|
||||
export default {
|
||||
CheckboxWidget,
|
||||
CheckboxesWidget,
|
||||
DateWidget,
|
||||
DateTimeWidget,
|
||||
RadioWidget,
|
||||
RangeWidget,
|
||||
SelectWidget,
|
||||
TextareaWidget,
|
||||
};
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './Widgets';
|
||||
export * from './Widgets';
|
|
@ -0,0 +1,80 @@
|
|||
import React, { CSSProperties } from 'react';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import InputLabel from '@mui/material/InputLabel';
|
||||
import Input from '@mui/material/OutlinedInput';
|
||||
import {
|
||||
ADDITIONAL_PROPERTY_FLAG,
|
||||
WrapIfAdditionalTemplateProps,
|
||||
} from '@rjsf/utils';
|
||||
|
||||
function WrapIfAdditionalTemplate({
|
||||
children,
|
||||
classNames,
|
||||
disabled,
|
||||
id,
|
||||
label,
|
||||
onDropPropertyClick,
|
||||
onKeyChange,
|
||||
readonly,
|
||||
required,
|
||||
schema,
|
||||
uiSchema,
|
||||
registry,
|
||||
}: WrapIfAdditionalTemplateProps) {
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const { RemoveButton } = registry.templates.ButtonTemplates;
|
||||
const keyLabel = `${label} Key`; // i18n ?
|
||||
const additional = ADDITIONAL_PROPERTY_FLAG in schema;
|
||||
const btnStyle: CSSProperties = {
|
||||
flex: 1,
|
||||
paddingLeft: 6,
|
||||
paddingRight: 6,
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
if (!additional) {
|
||||
return <div className={classNames}>{children}</div>;
|
||||
}
|
||||
|
||||
const handleBlur = ({ target }: React.FocusEvent<HTMLInputElement>) =>
|
||||
onKeyChange(target.value);
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
key={`${id}-key`}
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
className={classNames}
|
||||
>
|
||||
<Grid item xs>
|
||||
<FormControl fullWidth required={required}>
|
||||
<InputLabel>{keyLabel}</InputLabel>
|
||||
<Input
|
||||
defaultValue={label}
|
||||
disabled={disabled || readonly}
|
||||
id={`${id}-key`}
|
||||
name={`${id}-key`}
|
||||
onBlur={!readonly ? handleBlur : undefined}
|
||||
type="text"
|
||||
/>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
{children}
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<RemoveButton
|
||||
iconType="default"
|
||||
style={btnStyle}
|
||||
disabled={disabled || readonly}
|
||||
onClick={onDropPropertyClick(label)}
|
||||
uiSchema={uiSchema}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export default WrapIfAdditionalTemplate;
|
|
@ -0,0 +1,2 @@
|
|||
export { default } from './WrapIfAdditionalTemplate';
|
||||
export * from './WrapIfAdditionalTemplate';
|
|
@ -0,0 +1,3 @@
|
|||
button.react-json-schema-form-submit-button {
|
||||
margin-top: 1.5em;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import CarbonForm from './CarbonForm/CarbonForm';
|
||||
import './index.css';
|
||||
|
||||
export { default as Form } from './CarbonForm';
|
||||
export { default as Templates } from './Templates';
|
||||
export { default as Theme } from './Theme';
|
||||
export { default as Widgets } from './Widgets';
|
||||
|
||||
export default CarbonForm;
|
Loading…
Reference in New Issue