copied mui theme to use as base for carbon theme w/ burnettk cullerton

This commit is contained in:
jasquat 2022-11-16 13:59:09 -05:00
parent c3c941126b
commit bb7324616b
56 changed files with 1243 additions and 43 deletions

View File

@ -18,6 +18,7 @@
"@casl/react": "^3.1.0",
"@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0",
"@monaco-editor/react": "^4.4.5",
"@mui/material": "^5.10.14",
"@react-icons/all-files": "^4.1.0",
"@rjsf/core": "*",
"@rjsf/mui": "^5.0.0-beta.13",
@ -4447,7 +4448,6 @@
"version": "5.0.0-alpha.106",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.106.tgz",
"integrity": "sha512-xJQQtwPCPwr6hGWTBdvDwHYwExn3Bw7nPQkN8Fuz8kHpZqoMVWQvvaFS557AIkkI2AFLV3DxVIMjbCvrIntBWg==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.1",
"@emotion/is-prop-valid": "^1.2.0",
@ -4480,7 +4480,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
"integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
"peer": true,
"dependencies": {
"@emotion/memoize": "^0.8.0"
}
@ -4488,20 +4487,17 @@
"node_modules/@mui/base/node_modules/@emotion/memoize": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==",
"peer": true
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
},
"node_modules/@mui/base/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"peer": true
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@mui/core-downloads-tracker": {
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.14.tgz",
"integrity": "sha512-qLgIJNOR9Dre8JiZ/neVzOf4jf88J6YtOkQqugtMrleLjbfRVUSS4LWl9CSOjNq76quYdmYWnSDgfQqOooT2cQ==",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui"
@ -4537,7 +4533,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.14.tgz",
"integrity": "sha512-HWzKVAykePMx54WtxVwZyL1W4k3xlHYIqwMw0CaXAvgB3UE9yjABZuuGr8vG5Z6CSNWamzd+s1x8u7pQPFl9og==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.1",
"@mui/base": "5.0.0-alpha.106",
@ -4581,14 +4576,12 @@
"node_modules/@mui/material/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"peer": true
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@mui/private-theming": {
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.10.14.tgz",
"integrity": "sha512-3aIBe8WK65CwAPDY8nB11hYnzE1CZMymi76UnaFrA/DdGDwl5Y8F6uB+StKrkVmsqF1po7Mp2odqVkHj320gXw==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.1",
"@mui/utils": "^5.10.14",
@ -4615,7 +4608,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.14.tgz",
"integrity": "sha512-bgKdM57ExogWpIfhL/ngSlzF4FhbH00vYF+Y5VALTob4uslFqje0xzoWmbfcCn4cZt2NXxZJIwhsq4vzo5itlw==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.1",
"@emotion/cache": "^11.10.5",
@ -4647,7 +4639,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.14.tgz",
"integrity": "sha512-2de7XCjRb1j8Od0Stmo0LwFMLpOMNT4wzfINuExXI1TVSuyxXIXUxiC5FEgJW3GMvf/a7SUR8VOiMoKlKWzukw==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.1",
"@mui/private-theming": "^5.10.14",
@ -4687,7 +4678,6 @@
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.1.tgz",
"integrity": "sha512-c5mSM7ivD8EsqK6HUi9hQPr5V7TJ/IRThUQ9nWNYPdhCGriTSQV4vL6DflT99LkM+wLiIS1rVjphpEWxERep7A==",
"peer": true,
"peerDependencies": {
"@types/react": "*"
},
@ -4701,7 +4691,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.14.tgz",
"integrity": "sha512-12p59+wDZpA++XVJmKwqsZmrA1nmUQ5d0a1yQWtcDjxNyER1EDzozYN/db+FY2i5ceQh2TynPTEwGms2mXDwFg==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.1",
"@types/prop-types": "^15.7.5",
@ -4723,8 +4712,7 @@
"node_modules/@mui/utils/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"peer": true
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
@ -5921,7 +5909,6 @@
"version": "17.0.3",
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
"integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==",
"peer": true,
"dependencies": {
"@types/react": "*"
}
@ -8977,7 +8964,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
"peer": true,
"engines": {
"node": ">=6"
}
@ -34603,7 +34589,6 @@
"version": "5.0.0-alpha.106",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.106.tgz",
"integrity": "sha512-xJQQtwPCPwr6hGWTBdvDwHYwExn3Bw7nPQkN8Fuz8kHpZqoMVWQvvaFS557AIkkI2AFLV3DxVIMjbCvrIntBWg==",
"peer": true,
"requires": {
"@babel/runtime": "^7.20.1",
"@emotion/is-prop-valid": "^1.2.0",
@ -34619,7 +34604,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
"integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
"peer": true,
"requires": {
"@emotion/memoize": "^0.8.0"
}
@ -34627,22 +34611,19 @@
"@emotion/memoize": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==",
"peer": true
"integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
},
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"peer": true
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
"@mui/core-downloads-tracker": {
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.14.tgz",
"integrity": "sha512-qLgIJNOR9Dre8JiZ/neVzOf4jf88J6YtOkQqugtMrleLjbfRVUSS4LWl9CSOjNq76quYdmYWnSDgfQqOooT2cQ==",
"peer": true
"integrity": "sha512-qLgIJNOR9Dre8JiZ/neVzOf4jf88J6YtOkQqugtMrleLjbfRVUSS4LWl9CSOjNq76quYdmYWnSDgfQqOooT2cQ=="
},
"@mui/icons-material": {
"version": "5.10.14",
@ -34657,7 +34638,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.14.tgz",
"integrity": "sha512-HWzKVAykePMx54WtxVwZyL1W4k3xlHYIqwMw0CaXAvgB3UE9yjABZuuGr8vG5Z6CSNWamzd+s1x8u7pQPFl9og==",
"peer": true,
"requires": {
"@babel/runtime": "^7.20.1",
"@mui/base": "5.0.0-alpha.106",
@ -34676,8 +34656,7 @@
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"peer": true
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
@ -34685,7 +34664,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.10.14.tgz",
"integrity": "sha512-3aIBe8WK65CwAPDY8nB11hYnzE1CZMymi76UnaFrA/DdGDwl5Y8F6uB+StKrkVmsqF1po7Mp2odqVkHj320gXw==",
"peer": true,
"requires": {
"@babel/runtime": "^7.20.1",
"@mui/utils": "^5.10.14",
@ -34696,7 +34674,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.14.tgz",
"integrity": "sha512-bgKdM57ExogWpIfhL/ngSlzF4FhbH00vYF+Y5VALTob4uslFqje0xzoWmbfcCn4cZt2NXxZJIwhsq4vzo5itlw==",
"peer": true,
"requires": {
"@babel/runtime": "^7.20.1",
"@emotion/cache": "^11.10.5",
@ -34708,7 +34685,6 @@
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.14.tgz",
"integrity": "sha512-2de7XCjRb1j8Od0Stmo0LwFMLpOMNT4wzfINuExXI1TVSuyxXIXUxiC5FEgJW3GMvf/a7SUR8VOiMoKlKWzukw==",
"peer": true,
"requires": {
"@babel/runtime": "^7.20.1",
"@mui/private-theming": "^5.10.14",
@ -34724,14 +34700,12 @@
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.1.tgz",
"integrity": "sha512-c5mSM7ivD8EsqK6HUi9hQPr5V7TJ/IRThUQ9nWNYPdhCGriTSQV4vL6DflT99LkM+wLiIS1rVjphpEWxERep7A==",
"peer": true,
"requires": {}
},
"@mui/utils": {
"version": "5.10.14",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.10.14.tgz",
"integrity": "sha512-12p59+wDZpA++XVJmKwqsZmrA1nmUQ5d0a1yQWtcDjxNyER1EDzozYN/db+FY2i5ceQh2TynPTEwGms2mXDwFg==",
"peer": true,
"requires": {
"@babel/runtime": "^7.20.1",
"@types/prop-types": "^15.7.5",
@ -34743,8 +34717,7 @@
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
"peer": true
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
@ -35627,7 +35600,6 @@
"version": "17.0.3",
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
"integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==",
"peer": true,
"requires": {
"@types/react": "*"
}
@ -37942,8 +37914,7 @@
"clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
"peer": true
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
},
"co": {
"version": "4.6.0",

View File

@ -13,6 +13,7 @@
"@casl/react": "^3.1.0",
"@ginkgo-bioworks/react-json-schema-form-builder": "^2.9.0",
"@monaco-editor/react": "^4.4.5",
"@mui/material": "^5.10.14",
"@react-icons/all-files": "^4.1.0",
"@rjsf/core": "*",
"@rjsf/mui": "^5.0.0-beta.13",

View File

@ -1,7 +1,5 @@
import { useContext, useEffect, useState } from 'react';
import { Link, useNavigate, useParams } from 'react-router-dom';
// import Form from '@rjsf/core';
import Form from '@rjsf/mui';
import validator from '@rjsf/validator-ajv8';
// @ts-ignore
@ -9,7 +7,7 @@ import { Button, Stack } from '@carbon/react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
// import Form from '../themes';
import Form from '../themes/carbon';
import HttpService from '../services/HttpService';
import ErrorContext from '../contexts/ErrorContext';
import { modifyProcessModelPath } from '../helpers';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './AddButton';
export * from './AddButton';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './ArrayFieldItemTemplate';
export * from './ArrayFieldItemTemplate';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './ArrayFieldTemplate';
export * from './ArrayFieldTemplate';

View File

@ -0,0 +1,82 @@
import React from 'react';
import TextField, { TextFieldProps } from '@mui/material/TextField';
import { getInputProps, WidgetProps } from '@rjsf/utils';
function BaseInputTemplate({
id,
placeholder,
required,
readonly,
disabled,
type,
label,
value,
onChange,
onBlur,
onFocus,
autofocus,
options,
schema,
uiSchema,
rawErrors = [],
formContext,
registry,
...textFieldProps
}: WidgetProps) {
const inputProps = getInputProps(schema, type, options);
// Now we need to pull out the step, min, max into an inner `inputProps` for material-ui
const { step, min, max, ...rest } = inputProps;
const otherProps = {
inputProps: {
step,
min,
max,
...(schema.examples ? { list: `examples_${id}` } : undefined),
},
...rest,
};
const _onChange = ({
target: { value },
}: React.ChangeEvent<HTMLInputElement>) =>
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);
const { schemaUtils } = registry;
const displayLabel = schemaUtils.getDisplayLabel(schema, uiSchema);
return (
<>
<TextField
id={id}
name={id}
placeholder={placeholder}
label={displayLabel ? label || schema.title : false}
autoFocus={autofocus}
required={required}
disabled={disabled || readonly}
{...otherProps}
value={value || value === 0 ? value : ''}
error={rawErrors.length > 0}
onChange={_onChange}
onBlur={_onBlur}
onFocus={_onFocus}
{...(textFieldProps as TextFieldProps)}
/>
{schema.examples && (
<datalist id={`examples_${id}`}>
{(schema.examples as string[])
.concat(schema.default ? ([schema.default] as string[]) : [])
.map((example: any) => {
return <option key={example} value={example} />;
})}
</datalist>
)}
</>
);
}
export default BaseInputTemplate;

View File

@ -0,0 +1,2 @@
export { default } from './BaseInputTemplate';
export * from './BaseInputTemplate';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './CheckboxWidget';
export * from './CheckboxWidget';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './CheckboxesWidget';
export * from './CheckboxesWidget';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './DateTimeWidget';
export * from './DateTimeWidget';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './DateWidget';
export * from './DateWidget';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './DescriptionField';
export * from './DescriptionField';

View File

@ -0,0 +1,34 @@
import React from 'react';
import ErrorIcon from '@mui/icons-material/Error';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import Paper from '@mui/material/Paper';
import Typography from '@mui/material/Typography';
import { ErrorListProps } from '@rjsf/utils';
function ErrorList({ errors }: ErrorListProps) {
return (
<Paper elevation={2}>
<Box mb={2} p={2}>
<Typography variant="h6">Errors</Typography>
<List dense>
{errors.map((error, i: number) => {
return (
<ListItem key={i}>
<ListItemIcon>
<ErrorIcon color="error" />
</ListItemIcon>
<ListItemText primary={error.stack} />
</ListItem>
);
})}
</List>
</Box>
</Paper>
);
}
export default ErrorList;

View File

@ -0,0 +1,2 @@
export { default } from './ErrorList';
export * from './ErrorList';

View File

@ -0,0 +1,29 @@
import React from 'react';
import { FieldErrorProps } from '@rjsf/utils';
import ListItem from '@mui/material/ListItem';
import FormHelperText from '@mui/material/FormHelperText';
import List from '@mui/material/List';
/** 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) {
const { errors = [], idSchema } = props;
if (errors.length === 0) {
return null;
}
const id = `${idSchema.$id}__error`;
return (
<List dense disablePadding>
{errors.map((error, i: number) => {
return (
<ListItem key={i} disableGutters>
<FormHelperText id={id}>{error}</FormHelperText>
</ListItem>
);
})}
</List>
);
}

View File

@ -0,0 +1,2 @@
export { default } from './FieldErrorTemplate';
export * from './FieldErrorTemplate';

View File

@ -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>;
}

View File

@ -0,0 +1,2 @@
export { default } from './FieldHelpTemplate';
export * from './FieldHelpTemplate';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './FieldTemplate';
export * from './FieldTemplate';

View File

@ -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'} />
}
/>
);
}

View File

@ -0,0 +1,2 @@
export { default } from './IconButton';
export * from './IconButton';

View File

@ -0,0 +1,8 @@
import { ComponentType } from 'react';
import { withTheme, FormProps } from '@rjsf/core';
import Theme from '../Theme';
const MuiForm: ComponentType<FormProps> = withTheme(Theme);
export default MuiForm;

View File

@ -0,0 +1,2 @@
export { default } from './MuiForm';
export * from './MuiForm';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './ObjectFieldTemplate';
export * from './ObjectFieldTemplate';

View File

@ -0,0 +1,73 @@
import React from 'react';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormLabel from '@mui/material/FormLabel';
import Radio from '@mui/material/Radio';
import RadioGroup from '@mui/material/RadioGroup';
import { WidgetProps } from '@rjsf/utils';
function RadioWidget({
id,
schema,
options,
value,
required,
disabled,
readonly,
label,
onChange,
onBlur,
onFocus,
}: WidgetProps) {
const { enumOptions, enumDisabled } = options;
const _onChange = (_: 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 (
<>
<FormLabel required={required} htmlFor={id}>
{label || schema.title}
</FormLabel>
<RadioGroup
id={id}
name={id}
value={`${value}`}
row={row as boolean}
onChange={_onChange}
onBlur={_onBlur}
onFocus={_onFocus}
>
{Array.isArray(enumOptions) &&
enumOptions.map((option) => {
const itemDisabled =
Array.isArray(enumDisabled) &&
enumDisabled.indexOf(option.value) !== -1;
return (
<FormControlLabel
control={
<Radio
name={id}
id={`${id}-${option.value}`}
color="primary"
/>
}
label={`${option.label}`}
value={`${option.value}`}
key={option.value}
disabled={disabled || itemDisabled || readonly}
/>
);
})}
</RadioGroup>
</>
);
}
export default RadioWidget;

View File

@ -0,0 +1,2 @@
export { default } from './RadioWidget';
export * from './RadioWidget';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './RangeWidget';
export * from './RangeWidget';

View File

@ -0,0 +1,71 @@
import React from 'react';
import MenuItem from '@mui/material/MenuItem';
import TextField from '@mui/material/TextField';
import { WidgetProps, processSelectValue } from '@rjsf/utils';
function SelectWidget({
schema,
id,
options,
label,
required,
disabled,
readonly,
value,
multiple,
autofocus,
onChange,
onBlur,
onFocus,
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));
return (
<TextField
id={id}
name={id}
label={label || schema.title}
select
value={typeof value === 'undefined' ? emptyValue : value}
required={required}
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 (
<MenuItem key={i} value={value} disabled={disabled}>
{label}
</MenuItem>
);
})}
</TextField>
);
}
export default SelectWidget;

View File

@ -0,0 +1,2 @@
export { default } from './SelectWidget';
export * from './SelectWidget';

View File

@ -0,0 +1,29 @@
import React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import { SubmitButtonProps, getSubmitButtonOptions } from '@rjsf/utils';
const SubmitButton: React.ComponentType<SubmitButtonProps> = (props) => {
const {
submitText,
norender,
props: submitButtonProps,
} = getSubmitButtonOptions(props.uiSchema);
if (norender) {
return null;
}
return (
<Box marginTop={3}>
<Button
type="submit"
variant="contained"
color="primary"
{...submitButtonProps}
>
{submitText}
</Button>
</Box>
);
};
export default SubmitButton;

View File

@ -0,0 +1,2 @@
export { default } from './SubmitButton';
export * from './SubmitButton';

View File

@ -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,
};

View File

@ -0,0 +1,2 @@
export { default } from './Templates';
export * from './Templates';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './TextareaWidget';
export * from './TextareaWidget';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './Theme';
export * from './Theme';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './TitleField';
export * from './TitleField';

View File

@ -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,
};

View File

@ -0,0 +1,2 @@
export { default } from './Widgets';
export * from './Widgets';

View File

@ -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;

View File

@ -0,0 +1,2 @@
export { default } from './WrapIfAdditionalTemplate';
export * from './WrapIfAdditionalTemplate';

View File

@ -0,0 +1,8 @@
import MuiForm from './MuiForm/MuiForm';
export { default as Form } from './MuiForm';
export { default as Templates } from './Templates';
export { default as Theme } from './Theme';
export { default as Widgets } from './Widgets';
export default MuiForm;