UNPKG

@jsonforms/vanilla-renderers

Version:

Default Renderer Set for JSON Forms

847 lines (807 loc) 48.4 kB
import maxBy from 'lodash/maxBy'; import React, { useContext, useMemo, useState } from 'react'; import { getConfig, convertToValidClassName as convertToValidClassName$2, getAjv, rankWith as rankWith$1, isControl, isDescriptionHidden, NOT_APPLICABLE, computeLabel, and, isEnumControl, optionIs, isOneOfEnumControl, Helpers, findUISchema, createDefaultValue, composePaths, isObjectArrayWithNesting, uiTypeIs, isVisible, deriveLabelForUISchemaElement, Paths, getControlPath, Resolve, encode, Test, isBooleanControl, isDateControl, isDateTimeControl, isIntegerControl, isNumberControl, isNumberFormatControl, isRangeControl, isStringControl, isMultiLineControl, isTimeControl } from '@jsonforms/core'; import { useJsonForms, withJsonFormsControlProps, Control, DispatchCell, withJsonFormsEnumProps, withJsonFormsOneOfEnumProps, withJsonFormsArrayControlProps, withTranslateProps, withArrayTranslationProps, JsonFormsDispatch, withJsonFormsLayoutProps, withJsonFormsLabelProps, withJsonFormsCellProps, withJsonFormsEnumCellProps, withJsonFormsOneOfEnumCellProps } from '@jsonforms/react'; import isEmpty from 'lodash/isEmpty'; import remove from 'lodash/remove'; import join from 'lodash/join'; import filter from 'lodash/filter'; import reduce from 'lodash/reduce'; import merge from 'lodash/merge'; import range from 'lodash/range'; import fpfilter from 'lodash/fp/filter'; import fpmap from 'lodash/fp/map'; import fpflow from 'lodash/fp/flow'; import fpkeys from 'lodash/fp/keys'; import fpstartCase from 'lodash/fp/startCase'; const REGISTER_STYLE = 'REGISTER_STYLE'; const REGISTER_STYLES = 'REGISTER_STYLES'; const UNREGISTER_STYLE = 'UNREGISTER_STYLE'; const registerStyle$1 = (styleName, classNames) => ({ type: REGISTER_STYLE, name: styleName, classNames, }); const unregisterStyle = (styleName) => ({ type: UNREGISTER_STYLE, name: styleName, }); const registerStyles = (styleDefs) => ({ type: REGISTER_STYLES, styles: styleDefs, }); const i18nDefaults = { 'enum.none': 'None', }; const removeStyle = (styles, name) => { const copy = styles.slice(); remove(copy, (styleDef) => styleDef.name === name); return copy; }; const registerStyle = (styles, { name, classNames }) => { const copy = removeStyle(styles, name); copy.push({ name, classNames }); return copy; }; const findStyle = (styles) => (style, ...args) => { const foundStyles = filter(styles, (s) => s.name === style); return reduce(foundStyles, (res, style) => { if (typeof style.classNames === 'function') { return res.concat(style.classNames(args)); } return res.concat(style.classNames); }, []); }; const findStyleAsClassName = (styles) => (style, ...args) => join(findStyle(styles)(style, args), ' '); const stylingReducer = (state = [], action) => { switch (action.type) { case REGISTER_STYLE: { return registerStyle(state, { name: action.name, classNames: action.classNames, }); } case REGISTER_STYLES: { return action.styles.reduce((allStyles, style) => registerStyle(allStyles, style), state); } case UNREGISTER_STYLE: { return removeStyle(state, action.name); } default: return state; } }; const getStyle = (state) => (styleName, ...args) => findStyle(state.jsonforms.styles)(styleName, args); const getStyleAsClassName = (state) => (styleName, ...args) => findStyleAsClassName(state.jsonforms.styles)(styleName, args); const vanillaStyles = [ { name: 'control', classNames: ['control'], }, { name: 'control.trim', classNames: ['trim'], }, { name: 'control.input', classNames: ['input'], }, { name: 'control.select', classNames: ['select'], }, { name: 'control.checkbox', classNames: ['checkbox'], }, { name: 'control.radio', classNames: ['radio'], }, { name: 'control.radio.option', classNames: ['radio-option'], }, { name: 'control.radio.input', classNames: ['radio-input'], }, { name: 'control.radio.label', classNames: ['radio-label'], }, { name: 'control.validation.error', classNames: ['validation_error'], }, { name: 'control.validation', classNames: ['validation'], }, { name: 'categorization', classNames: ['categorization'], }, { name: 'categorization.master', classNames: ['categorization-master'], }, { name: 'categorization.detail', classNames: ['categorization-detail'], }, { name: 'category.group', classNames: ['category-group'], }, { name: 'category.subcategories', classNames: ['category-subcategories'], }, { name: 'array.layout', classNames: ['array-layout'], }, { name: 'array.children', classNames: ['children'], }, { name: 'group.layout', classNames: ['group-layout'], }, { name: 'horizontal.layout', classNames: ['horizontal-layout'], }, { name: 'horizontal.layout.item', classNames: ([size]) => [`horizontal-layout-${size}`], }, { name: 'vertical.layout', classNames: ['vertical-layout'], }, { name: 'array.table.validation.error', classNames: ['validation_error'], }, { name: 'array.table.validation', classNames: ['validation'], }, { name: 'array.table', classNames: ['array-table-layout', 'control'], }, { name: 'array.control.validation.error', classNames: ['validation_error'], }, { name: 'array.control.validation', classNames: ['validation'], }, { name: 'array.control.add', classNames: ['button-add'], }, { name: 'array.child.controls', classNames: ['child-controls'], }, { name: 'array.child.controls.up', classNames: ['button-up'], }, { name: 'array.child.controls.down', classNames: ['button-down'], }, { name: 'array.child.controls.delete', classNames: ['button-delete'], }, { name: 'array.control', classNames: ['array-control-layout', 'control'], }, { name: 'input.description', classNames: ['input-description'], }, ]; const defaultContext = { styles: vanillaStyles, }; const JsonFormsStyleContext = React.createContext(defaultContext); const useStyleContext = () => useContext(JsonFormsStyleContext); const useStyles = () => { const { styles } = useStyleContext(); return styles; }; const addVanillaControlProps = (mapStateToProps) => (state, ownProps) => { const props = mapStateToProps(state, ownProps); const config = getConfig(state); const trim = config.trim; const controlElement = props.uischema; const isValid = isEmpty(props.errors); const styles = getStyle(state)('control'); let classNames = !isEmpty(controlElement.scope) ? styles.concat([`${convertToValidClassName$2(controlElement.scope)}`]) : ['']; if (trim) { classNames = classNames.concat(getStyle(state)('control.trim')); } const labelClass = getStyleAsClassName(state)('control.label'); const descriptionClassName = getStyleAsClassName(state)('input.description'); const validationClassName = getStyleAsClassName(state)('control.validation'); const validationErrorClassName = getStyleAsClassName(state)('control.validation.error'); const inputClassName = ['validate'].concat(isValid ? 'valid' : 'invalid'); return { ...props, getStyleAsClassName: getStyleAsClassName(state), getStyle: getStyle(state), classNames: { wrapper: classNames.join(' '), input: inputClassName.join(' '), label: labelClass, description: descriptionClassName, validation: validationClassName, validationError: validationErrorClassName, }, }; }; const withVanillaControlProps = (Component) => function WithVanillaControlProps(props) { const ctx = useJsonForms(); const contextStyles = useStyles(); const controlElement = props.uischema; const config = ctx.config; const trim = config && config.trim; const styles = useMemo(() => findStyle(contextStyles)('control'), [contextStyles]); let classNames = !isEmpty(controlElement.scope) ? styles.concat([`${convertToValidClassName$2(controlElement.scope)}`]) : ['']; if (trim) { classNames = classNames.concat(findStyle(contextStyles)('control.trim')); } const isValid = isEmpty(props.errors); const labelClass = useMemo(() => findStyleAsClassName(contextStyles)('control.label'), [contextStyles]); const descriptionClassName = useMemo(() => findStyleAsClassName(contextStyles)('input.description'), [contextStyles]); const validationClassName = useMemo(() => findStyleAsClassName(contextStyles)('control.validation'), [contextStyles]); const validationErrorClassName = useMemo(() => findStyleAsClassName(contextStyles)('control.validation.error'), [contextStyles]); const inputClassName = ['validate'].concat(isValid ? 'valid' : 'invalid'); const getStyleAsClassName = useMemo(() => findStyleAsClassName(contextStyles), [contextStyles]); const getStyle = useMemo(() => findStyle(contextStyles), [contextStyles]); const wrapper = classNames.join(' '); const input = inputClassName.join(' '); const classNamesProp = useMemo(() => ({ wrapper, input, label: labelClass, description: descriptionClassName, validation: validationClassName, validationError: validationErrorClassName, }), [ wrapper, input, labelClass, descriptionClassName, validationClassName, validationErrorClassName, ]); return (React.createElement(Component, { ...props, getStyleAsClassName: getStyleAsClassName, getStyle: getStyle, classNames: classNamesProp })); }; const addVanillaLayoutProps = (mapStateToProps) => (state, ownProps) => { const props = mapStateToProps(state, ownProps); return { ...props, getStyleAsClassName: getStyleAsClassName(state), getStyle: getStyle(state), }; }; const addVanillaCellProps = (mapStateToCellsProps) => (state, ownProps) => { const props = mapStateToCellsProps(state, ownProps); const inputClassName = ['validate'].concat(props.isValid ? 'valid' : 'invalid'); return { ...props, className: inputClassName.join(' '), getStyleAsClassName: getStyleAsClassName(state), getStyle: getStyle(state), }; }; const withVanillaCellPropsForType = (type) => (Component) => function WithVanillaCellPropsForType(props) { const inputClassName = ['validate'].concat(props.isValid ? 'valid' : 'invalid'); const styles = useStyles(); const definedStyle = findStyleAsClassName(styles)(type); if (definedStyle) { inputClassName.push(definedStyle); } return (React.createElement(Component, { ...props, getStyleAsClassName: findStyleAsClassName(styles), getStyle: findStyle(styles), className: inputClassName.join(' ') })); }; const withAjvProps = (Component) => function WithAjvProps(props) { const ctx = useJsonForms(); const ajv = getAjv({ jsonforms: { ...ctx } }); return React.createElement(Component, { ...props, ajv: ajv }); }; const withVanillaCellProps = withVanillaCellPropsForType('control.input'); const withVanillaEnumCellProps = withVanillaCellPropsForType('control.select'); const withVanillaBooleanCellProps = withVanillaCellPropsForType('control.checkbox'); class InputControl extends Control { render() { const { classNames, description, id, errors, label, uischema, schema, rootSchema, visible, enabled, required, path, cells, config, } = this.props; const isValid = errors.length === 0; const divClassNames = [classNames.validation] .concat(isValid ? classNames.description : classNames.validationError) .join(' '); const appliedUiSchemaOptions = merge({}, config, uischema.options); const showDescription = !isDescriptionHidden(visible, description, this.state.isFocused, appliedUiSchemaOptions.showUnfocusedDescription); const testerContext = { rootSchema: rootSchema, config: config, }; const cell = maxBy(cells, (r) => r.tester(uischema, schema, testerContext)); if (cell === undefined || cell.tester(uischema, schema, testerContext) === NOT_APPLICABLE) { console.warn('No applicable cell found.', uischema, schema); return null; } else { return (React.createElement("div", { className: classNames.wrapper, hidden: !visible, onFocus: this.onFocus, onBlur: this.onBlur, id: id }, React.createElement("label", { htmlFor: id + '-input', className: classNames.label }, computeLabel(label, required, appliedUiSchemaOptions.hideRequiredAsterisk)), React.createElement(DispatchCell, { uischema: uischema, schema: schema, path: path, id: id + '-input', enabled: enabled }), React.createElement("div", { className: divClassNames }, !isValid ? errors : showDescription ? description : null))); } } } const inputControlTester = rankWith$1(1, isControl); var InputControl$1 = withVanillaControlProps(withJsonFormsControlProps(InputControl)); const RadioGroup = ({ classNames, id, label, options, required, description, errors, data, uischema, visible, config, enabled, path, handleChange, }) => { const contextStyles = useStyles(); const [isFocused, setFocus] = useState(false); const radioControl = useMemo(() => findStyleAsClassName(contextStyles)('control.radio'), [contextStyles]); const radioOption = useMemo(() => findStyleAsClassName(contextStyles)('control.radio.option'), [contextStyles]); const radioInput = useMemo(() => findStyleAsClassName(contextStyles)('control.radio.input'), [contextStyles]); const radioLabel = useMemo(() => findStyleAsClassName(contextStyles)('control.radio.label'), [contextStyles]); const isValid = errors.length === 0; const divClassNames = [classNames.validation] .concat(isValid ? classNames.description : classNames.validationError) .join(' '); const appliedUiSchemaOptions = merge({}, config, uischema.options); const showDescription = !isDescriptionHidden(visible, description, isFocused, appliedUiSchemaOptions.showUnfocusedDescription); const hasRadioClass = !radioControl || radioControl === 'radio'; let groupStyle = {}; if (hasRadioClass) { groupStyle = { display: 'flex', flexDirection: 'vertical' === appliedUiSchemaOptions.orientation ? 'column' : 'row', }; } return (React.createElement("div", { className: classNames.wrapper, hidden: !visible, onFocus: () => setFocus(true), onBlur: () => setFocus(false) }, React.createElement("label", { htmlFor: id, className: classNames.label }, computeLabel(label, required, appliedUiSchemaOptions.hideRequiredAsterisk)), React.createElement("div", { className: radioControl, style: groupStyle }, options.map((option) => (React.createElement("div", { key: option.label, className: radioOption }, React.createElement("input", { type: 'radio', value: option.value, id: option.value, name: id, checked: data === option.value, onChange: (_) => handleChange(path, option.value), disabled: !enabled, className: radioInput }), React.createElement("label", { htmlFor: option.value, className: radioLabel }, option.label))))), React.createElement("div", { className: divClassNames }, !isValid ? errors : showDescription ? description : null))); }; const RadioGroupControl = (props) => { return React.createElement(RadioGroup, { ...props }); }; const radioGroupControlTester = rankWith$1(3, and(isEnumControl, optionIs('format', 'radio'))); var RadioGroupControl$1 = withVanillaControlProps(withJsonFormsEnumProps(RadioGroupControl)); const OneOfRadioGroupControl = (props) => { return React.createElement(RadioGroup, { ...props }); }; const oneOfRadioGroupControlTester = rankWith$1(3, and(isOneOfEnumControl, optionIs('format', 'radio'))); var OneOfRadioGroupControl$1 = withVanillaControlProps(withJsonFormsOneOfEnumProps(OneOfRadioGroupControl)); const { convertToValidClassName: convertToValidClassName$1 } = Helpers; const ArrayControl = ({ classNames, data, label, path, schema, errors, addItem, removeItems, moveUp, moveDown, uischema, uischemas, getStyleAsClassName, renderers, rootSchema, translations, enabled, }) => { const controlElement = uischema; const childUiSchema = useMemo(() => findUISchema(uischemas, schema, uischema.scope, path, undefined, uischema, rootSchema), [uischemas, schema, uischema.scope, path, uischema, rootSchema]); const isValid = errors.length === 0; const validationClass = getStyleAsClassName('array.control.validation'); const divClassNames = [validationClass] .concat(isValid ? '' : getStyleAsClassName('array.control.validation.error')) .join(' '); const buttonClassAdd = getStyleAsClassName('array.control.add'); const labelClass = getStyleAsClassName('array.control.label'); const childControlsClass = getStyleAsClassName('array.child.controls'); const buttonClassUp = getStyleAsClassName('array.child.controls.up'); const buttonClassDown = getStyleAsClassName('array.child.controls.down'); const buttonClassDelete = getStyleAsClassName('array.child.controls.delete'); const controlClass = [ getStyleAsClassName('array.control'), convertToValidClassName$1(controlElement.scope), ].join(' '); return (React.createElement("div", { className: controlClass }, React.createElement("header", null, React.createElement("label", { className: labelClass }, label), React.createElement("button", { type: 'button', className: buttonClassAdd, disabled: !enabled, onClick: addItem(path, createDefaultValue(schema, rootSchema)) }, "Add to ", label)), React.createElement("div", { className: divClassNames }, errors), React.createElement("div", { className: classNames.children }, data ? (range(0, data.length).map((index) => { const childPath = composePaths(path, `${index}`); return (React.createElement("div", { key: index }, React.createElement(JsonFormsDispatch, { schema: schema, uischema: childUiSchema || uischema, path: childPath, key: childPath, renderers: renderers }), React.createElement("div", { className: childControlsClass }, React.createElement("button", { type: 'button', className: buttonClassUp, disabled: !enabled, "aria-label": translations.upAriaLabel, onClick: () => { moveUp(path, index)(); } }, translations.up), React.createElement("button", { type: 'button', className: buttonClassDown, disabled: !enabled, "aria-label": translations.downAriaLabel, onClick: () => { moveDown(path, index)(); } }, translations.down), React.createElement("button", { type: 'button', className: buttonClassDelete, disabled: !enabled, "aria-label": translations.removeAriaLabel, onClick: () => { if (window.confirm('Are you sure you wish to delete this item?')) { removeItems(path, [index])(); } } }, translations.removeTooltip)))); })) : (React.createElement("p", null, translations.noDataMessage))))); }; const ArrayControlRenderer = ({ schema, uischema, data, path, rootSchema, uischemas, addItem, getStyle, getStyleAsClassName, removeItems, moveUp, moveDown, id, visible, enabled, errors, translations, arraySchema, }) => { const controlElement = uischema; const labelDescription = Helpers.createLabelDescriptionFrom(controlElement, schema); const label = labelDescription.show ? labelDescription.text : ''; const controlClassName = `control ${Helpers.convertToValidClassName(controlElement.scope)}`; const fieldSetClassName = getStyleAsClassName('array.layout'); const buttonClassName = getStyleAsClassName('array.button'); const childrenClassName = getStyleAsClassName('array.children'); const classNames = { wrapper: controlClassName, fieldSet: fieldSetClassName, button: buttonClassName, children: childrenClassName, }; return (React.createElement(ArrayControl, { classNames: classNames, data: data, label: label, path: path, schema: schema, arraySchema: arraySchema, errors: errors, addItem: addItem, removeItems: removeItems, moveUp: moveUp, moveDown: moveDown, uischema: uischema, uischemas: uischemas, getStyleAsClassName: getStyleAsClassName, rootSchema: rootSchema, id: id, visible: visible, enabled: enabled, getStyle: getStyle, translations: translations })); }; var ArrayControlRenderer$1 = withVanillaControlProps(withJsonFormsArrayControlProps(withTranslateProps(withArrayTranslationProps(ArrayControlRenderer)))); const arrayControlTester = rankWith$1(4, isObjectArrayWithNesting); const isCategorization = (category) => category.type === 'Categorization'; const categorizationTester = rankWith$1(1, and(uiTypeIs('Categorization'), (uischema) => { const hasCategory = (element) => { if (isEmpty(element.elements)) { return false; } return element.elements .map((elem) => isCategorization(elem) ? hasCategory(elem) : elem.type === 'Category') .reduce((prev, curr) => prev && curr, true); }; return hasCategory(uischema); })); const getCategoryClassName = (category, selectedCategory) => (selectedCategory === category ? 'selected' : ''); const CategorizationList = ({ selectedCategory, elements, data, depth, onSelect, subcategoriesClassName, groupClassName, t, ajv, config, }) => { const filteredElements = useMemo(() => { return elements.filter((category) => isVisible(category, data, undefined, ajv, config)); }, [elements, data, ajv, config]); const categoryLabels = useMemo(() => filteredElements.map((cat) => deriveLabelForUISchemaElement(cat, t)), [filteredElements, t]); return (React.createElement("ul", { className: subcategoriesClassName }, filteredElements.map((category, idx) => { if (isCategorization(category)) { return (React.createElement("li", { key: categoryLabels[idx], className: groupClassName }, React.createElement("span", null, categoryLabels[idx]), React.createElement(CategorizationList, { selectedCategory: selectedCategory, elements: category.elements, data: data, ajv: ajv, config: config, depth: depth + 1, onSelect: onSelect, subcategoriesClassName: subcategoriesClassName, groupClassName: groupClassName, t: t }))); } else { return (React.createElement("li", { key: categoryLabels[idx], onClick: onSelect(idx), className: getCategoryClassName(category, selectedCategory) }, React.createElement("span", null, categoryLabels[idx]))); } }))); }; const SingleCategory = ({ category, schema, path }) => ( React.createElement("div", { id: 'categorization.detail' }, (category.elements || []).map((child, index) => (React.createElement(JsonFormsDispatch, { key: `${path}-${index}`, uischema: child, schema: schema, path: path }))))); const CategorizationRenderer = ({ data, uischema, schema, path, selected, t, visible, getStyleAsClassName, onChange, ajv, config, }) => { const categorization = uischema; const elements = categorization.elements; const classNames = getStyleAsClassName('categorization'); const masterClassNames = getStyleAsClassName('categorization.master'); const detailClassNames = getStyleAsClassName('categorization.detail'); const subcategoriesClassName = getStyleAsClassName('category.subcategories'); const groupClassName = getStyleAsClassName('category.group'); const [previousCategorization, setPreviousCategorization] = useState(uischema); const [activeCategory, setActiveCategory] = useState(selected ?? 0); const safeCategory = activeCategory >= categorization.elements.length ? 0 : activeCategory; if (categorization !== previousCategorization) { setActiveCategory(0); setPreviousCategorization(categorization); } const onCategorySelected = (categoryIndex) => () => { if (onChange) { return onChange(categoryIndex, safeCategory); } return setActiveCategory(categoryIndex); }; return (React.createElement("div", { className: classNames, hidden: visible === null || visible === undefined ? false : !visible }, React.createElement("div", { className: masterClassNames }, React.createElement(CategorizationList, { elements: elements, selectedCategory: elements[safeCategory], data: data, ajv: ajv, config: config, depth: 0, onSelect: onCategorySelected, subcategoriesClassName: subcategoriesClassName, groupClassName: groupClassName, t: t })), React.createElement("div", { className: detailClassNames }, React.createElement(SingleCategory, { category: elements[safeCategory], schema: schema, path: path, key: safeCategory })))); }; var CategorizationRenderer$1 = withAjvProps(withVanillaControlProps(withTranslateProps(withJsonFormsLayoutProps(CategorizationRenderer)))); const labelRendererTester = rankWith$1(1, uiTypeIs('Label')); const LabelRenderer = ({ text, visible, getStyleAsClassName }) => { const classNames = getStyleAsClassName('label-control'); const isHidden = !visible; return (React.createElement("label", { hidden: isHidden, className: classNames }, text)); }; var LabelRenderer$1 = withVanillaControlProps(withJsonFormsLabelProps(LabelRenderer)); const { convertToValidClassName } = Helpers; const { or, isObjectArrayControl, isPrimitiveArrayControl, rankWith } = Test; const tableArrayControlTester = rankWith(3, or(isObjectArrayControl, isPrimitiveArrayControl)); class TableArrayControl extends React.Component { constructor() { super(...arguments); this.confirmDelete = (path, index) => { const p = path.substring(0, path.lastIndexOf('.')); this.props.removeItems(p, [index])(); }; } render() { const { addItem, uischema, schema, rootSchema, path, data, visible, errors, label, getStyleAsClassName, childErrors, translations, enabled, } = this.props; const controlElement = uischema; const tableClass = getStyleAsClassName('array.table.table'); const labelClass = getStyleAsClassName('array.table.label'); const buttonClass = getStyleAsClassName('array.table.button'); const validationClass = getStyleAsClassName('array.table.validation'); const controlClass = [ getStyleAsClassName('array.table'), convertToValidClassName(controlElement.scope), ].join(' '); const createControlElement = (key) => ({ type: 'Control', label: false, scope: schema.type === 'object' ? `#/properties/${key}` : '#', }); const isValid = errors.length === 0; const divClassNames = [validationClass] .concat(isValid ? '' : getStyleAsClassName('array.table.validation.error')) .join(' '); return (React.createElement("div", { className: controlClass, hidden: !visible }, React.createElement("header", null, React.createElement("label", { className: labelClass }, label), React.createElement("button", { type: 'button', disabled: !enabled, className: buttonClass, onClick: addItem(path, createDefaultValue(schema, rootSchema)) }, translations.addTooltip)), React.createElement("div", { className: divClassNames }, !isValid ? errors : ''), React.createElement("table", { className: tableClass }, React.createElement("thead", null, React.createElement("tr", null, schema.properties ? (fpflow(fpkeys, fpfilter((prop) => schema.properties[prop].type !== 'array'), fpmap((prop) => (React.createElement("th", { key: prop }, schema.properties[prop].title ?? fpstartCase(prop)))))(schema.properties)) : (React.createElement("th", null, "Items")), React.createElement("th", null, "Valid"), React.createElement("th", null, "\u00A0"))), React.createElement("tbody", null, !data || !Array.isArray(data) || data.length === 0 ? (React.createElement("tr", null, React.createElement("td", null, translations.noDataMessage))) : (data.map((_child, index) => { const childPath = Paths.compose(path, `${index}`); const errorsPerEntry = filter(childErrors, (error) => { const errorPath = getControlPath(error); return errorPath.startsWith(childPath); }); const validationClassName = getStyleAsClassName('array.validation'); const errorValidationClassName = getStyleAsClassName('array.validation.error'); const errorClassNames = errorsPerEntry ? [validationClassName] .concat(errorValidationClassName) .join(' ') : validationClassName; return (React.createElement("tr", { key: childPath }, schema.properties ? (fpflow(fpkeys, fpfilter((prop) => schema.properties[prop].type !== 'array'), fpmap((prop) => { const childPropPath = Paths.compose(childPath, prop.toString()); return (React.createElement("td", { key: childPropPath }, React.createElement(DispatchCell, { schema: Resolve.schema(schema, `#/properties/${encode(prop)}`, rootSchema), uischema: createControlElement(encode(prop)), path: childPath + '.' + prop }))); }))(schema.properties)) : (React.createElement("td", { key: Paths.compose(childPath, index.toString()) }, React.createElement(DispatchCell, { schema: schema, uischema: createControlElement(), path: childPath }))), React.createElement("td", null, errorsPerEntry ? (React.createElement("span", { className: errorClassNames }, join(errorsPerEntry.map((e) => e.message), ' and '))) : (React.createElement("span", { className: errorClassNames }, "OK"))), React.createElement("td", null, React.createElement("button", { type: 'button', disabled: !enabled, "aria-label": translations.removeAriaLabel, onClick: () => { if (window.confirm(translations.deleteDialogMessage)) { this.confirmDelete(childPath, index); } } }, translations.removeTooltip)))); })))))); } } var TableArrayControl$1 = withVanillaControlProps(withJsonFormsArrayControlProps(withTranslateProps(withArrayTranslationProps(TableArrayControl)))); const BooleanCell = (props) => { const { data, className, id, enabled, uischema, path, handleChange } = props; return (React.createElement("input", { type: 'checkbox', checked: !!data, onChange: (ev) => handleChange(path, ev.target.checked), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus })); }; const booleanCellTester = rankWith$1(2, isBooleanControl); var BooleanCell$1 = withJsonFormsCellProps(withVanillaBooleanCellProps(BooleanCell)); const DateCell = (props) => { const { data, className, id, enabled, uischema, path, handleChange } = props; return (React.createElement("input", { type: 'date', value: data || '', onChange: (ev) => handleChange(path, ev.target.value), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus })); }; const dateCellTester = rankWith$1(2, isDateControl); var DateCell$1 = withJsonFormsCellProps(withVanillaCellProps(DateCell)); const DateTimeCell = (props) => { const { data, className, id, enabled, uischema, path, handleChange } = props; const toISOString = (inputDateTime) => { return inputDateTime === '' ? '' : inputDateTime + ':00.000Z'; }; return (React.createElement("input", { type: 'datetime-local', value: (data || '').substr(0, 16), onChange: (ev) => handleChange(path, toISOString(ev.target.value)), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus })); }; const dateTimeCellTester = rankWith$1(2, isDateTimeControl); var DateTimeCell$1 = withJsonFormsCellProps(withVanillaCellProps(DateTimeCell)); const EnumCell = (props) => { const { data, className, id, enabled, schema, uischema, path, handleChange, options, t, } = props; const noneOptionLabel = useMemo(() => t('enum.none', i18nDefaults['enum.none'], { schema, uischema, path }), [t, schema, uischema, path]); return (React.createElement("select", { className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus, value: data || '', onChange: (ev) => handleChange(path, ev.target.selectedIndex === 0 ? undefined : ev.target.value) }, [ React.createElement("option", { value: '', key: 'jsonforms.enum.none' }, noneOptionLabel), ].concat(options.map((optionValue) => (React.createElement("option", { value: optionValue.value, label: optionValue.label, key: optionValue.value })))))); }; const enumCellTester = rankWith$1(2, isEnumControl); var EnumCell$1 = withJsonFormsEnumCellProps(withTranslateProps(withVanillaEnumCellProps(EnumCell))); const toNumber$1 = (value) => value === '' ? undefined : parseInt(value, 10); const IntegerCell = (props) => { const { data, className, id, enabled, uischema, path, handleChange } = props; return (React.createElement("input", { type: 'number', step: '1', value: data ?? '', onChange: (ev) => handleChange(path, toNumber$1(ev.target.value)), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus })); }; const integerCellTester = rankWith$1(2, isIntegerControl); var IntegerCell$1 = withJsonFormsCellProps(withVanillaCellProps(IntegerCell)); const toNumber = (value) => (value === '' ? undefined : Number(value)); const NumberCell = (props) => { const { data, className, id, enabled, uischema, path, handleChange } = props; return (React.createElement("input", { type: 'number', step: '0.1', value: data ?? '', onChange: (ev) => handleChange(path, toNumber(ev.target.value)), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus })); }; const numberCellTester = rankWith$1(2, isNumberControl); var NumberCell$1 = withJsonFormsCellProps(withVanillaCellProps(NumberCell)); const NumberFormatCell = (props) => { const { className, id, enabled, uischema, path, handleChange, schema } = props; const maxLength = schema.maxLength; const formattedNumber = props.toFormatted(props.data); const onChange = (ev) => { const validStringNumber = props.fromFormatted(ev.currentTarget.value); handleChange(path, validStringNumber); }; return (React.createElement("input", { type: 'text', value: formattedNumber, onChange: onChange, className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus, maxLength: uischema.options && uischema.options.restrict ? maxLength : undefined, size: uischema.options && uischema.options.trim ? maxLength : undefined })); }; const numberFormatCellTester = rankWith$1(4, isNumberFormatControl); var NumberFormatCell$1 = withJsonFormsCellProps(withVanillaCellProps(NumberFormatCell)); const OneOfEnumCell = (props) => { const { data, className, id, enabled, schema, uischema, path, handleChange, options, t, } = props; const noneOptionLabel = useMemo(() => t('enum.none', i18nDefaults['enum.none'], { schema, uischema, path }), [t, schema, uischema, path]); const noneOption = (React.createElement("option", { value: '', key: 'jsonforms.enum.none' }, noneOptionLabel)); return (React.createElement("select", { className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus, value: data || '', onChange: (ev) => handleChange(path, ev.target.selectedIndex === 0 ? undefined : ev.target.value) }, (uischema.options?.hideEmptyOption === true ? [] : [noneOption]).concat(options.map((optionValue) => (React.createElement("option", { value: optionValue.value, label: optionValue.label, key: optionValue.value })))))); }; const oneOfEnumCellTester = rankWith$1(2, isOneOfEnumControl); var OneOfEnumCell$1 = withJsonFormsOneOfEnumCellProps(withTranslateProps(withVanillaEnumCellProps(OneOfEnumCell))); const SliderCell = (props) => { const { data, className, id, enabled, uischema, schema, path, handleChange } = props; return (React.createElement("div", { style: { display: 'flex' } }, React.createElement("input", { type: 'range', max: schema.maximum, min: schema.minimum, value: data || schema.default, onChange: (ev) => handleChange(path, Number(ev.target.value)), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus, style: { flex: '1' } }), React.createElement("label", { style: { marginLeft: '0.5em' } }, data || schema.default))); }; const sliderCellTester = rankWith$1(4, isRangeControl); var SliderCell$1 = withJsonFormsCellProps(withVanillaCellProps(SliderCell)); const TextCell = (props) => { const { config, data, className, id, enabled, uischema, schema, path, handleChange, } = props; const maxLength = schema.maxLength; const appliedUiSchemaOptions = merge({}, config, uischema.options); return (React.createElement("input", { type: appliedUiSchemaOptions.format === 'password' ? 'password' : 'text', value: data || '', onChange: (ev) => handleChange(path, ev.target.value === '' ? undefined : ev.target.value), className: className, id: id, disabled: !enabled, autoFocus: appliedUiSchemaOptions.focus, placeholder: appliedUiSchemaOptions.placeholder, maxLength: appliedUiSchemaOptions.restrict ? maxLength : undefined, size: appliedUiSchemaOptions.trim ? maxLength : undefined })); }; const textCellTester = rankWith$1(1, isStringControl); var TextCell$1 = withJsonFormsCellProps(withVanillaCellProps(TextCell)); const TextAreaCell = (props) => { const { data, className, id, enabled, config, uischema, path, handleChange } = props; const appliedUiSchemaOptions = merge({}, config, uischema.options); return (React.createElement("textarea", { value: data || '', onChange: (ev) => handleChange(path, ev.target.value === '' ? undefined : ev.target.value), className: className, id: id, disabled: !enabled, autoFocus: appliedUiSchemaOptions.focus, placeholder: appliedUiSchemaOptions.placeholder })); }; const textAreaCellTester = rankWith$1(2, isMultiLineControl); var TextAreaCell$1 = withJsonFormsCellProps(withVanillaCellProps(TextAreaCell)); const appendSecondsIfNecessary = (value) => { if (typeof value === 'string') { const splitValue = value.split(':'); if (splitValue.length === 2) { splitValue.push('00'); } return splitValue.join(':'); } return value; }; const TimeCell = (props) => { const { data, className, id, enabled, uischema, path, handleChange } = props; return (React.createElement("input", { type: 'time', value: data || '', onChange: (ev) => handleChange(path, appendSecondsIfNecessary(ev.target.value)), className: className, id: id, disabled: !enabled, autoFocus: uischema.options && uischema.options.focus })); }; const timeCellTester = rankWith$1(2, isTimeControl); var TimeCell$1 = withJsonFormsCellProps(withVanillaCellProps(TimeCell)); var CustomizableCells = /*#__PURE__*/Object.freeze({ __proto__: null, BooleanCell: BooleanCell, DateCell: DateCell, DateTimeCell: DateTimeCell, EnumCell: EnumCell, IntegerCell: IntegerCell, NumberCell: NumberCell, NumberFormatCell: NumberFormatCell, SliderCell: SliderCell, TextCell: TextCell, TextAreaCell: TextAreaCell, TimeCell: TimeCell }); const renderChildren = (layout, schema, className, path, enabled) => { if (isEmpty(layout.elements)) { return []; } const { renderers, cells } = useJsonForms(); return layout.elements.map((child, index) => { return (React.createElement("div", { className: className, key: `${path}-${index}` }, React.createElement(JsonFormsDispatch, { renderers: renderers, cells: cells, uischema: child, schema: schema, path: path, enabled: enabled }))); }); }; const groupTester = rankWith$1(1, uiTypeIs('Group')); const GroupLayoutRenderer = (props) => { const { data: _data, ...otherProps } = props; return React.createElement(GroupLayoutRendererComponent, { ...otherProps }); }; const GroupLayoutRendererComponent = React.memo(function GroupLayoutRendererComponent({ schema, uischema, path, enabled, visible, label, getStyle, getStyleAsClassName, }) { const group = uischema; const elementsSize = group.elements ? group.elements.length : 0; const classNames = getStyleAsClassName('group.layout'); const childClassNames = ['group-layout-item'] .concat(getStyle('group.layout.item', elementsSize)) .join(' '); return (React.createElement("fieldset", { className: classNames, hidden: visible === undefined || visible === null ? false : !visible }, !isEmpty(label) ? (React.createElement("legend", { className: getStyleAsClassName('group.label') }, label)) : (''), renderChildren(group, schema, childClassNames, path, enabled))); }); var GroupLayout = withVanillaControlProps(withJsonFormsLayoutProps(GroupLayoutRenderer)); const JsonFormsLayout = ({ className, children, visible, }) => { return (React.createElement("div", { className: className, hidden: visible === undefined || visible === null ? false : !visible }, children)); }; const horizontalLayoutTester = rankWith$1(1, uiTypeIs('HorizontalLayout')); const HorizontalLayoutRenderer = (props) => { const { data: _data, ...otherProps } = props; return React.createElement(HorizontalLayoutRendererComponent, { ...otherProps }); }; const HorizontalLayoutRendererComponent = React.memo(function HorizontalLayoutRendererComponent({ schema, uischema, getStyle, getStyleAsClassName, enabled, visible, path, }) { const horizontalLayout = uischema; const elementsSize = horizontalLayout.elements ? horizontalLayout.elements.length : 0; const layoutClassName = getStyleAsClassName('horizontal.layout'); const childClassNames = ['horizontal-layout-item'] .concat(getStyle('horizontal.layout.item', elementsSize)) .join(' '); return (React.createElement(JsonFormsLayout, { className: layoutClassName, visible: visible, enabled: enabled, path: path, uischema: uischema, schema: schema, getStyle: getStyle, getStyleAsClassName: getStyleAsClassName }, renderChildren(horizontalLayout, schema, childClassNames, path, enabled))); }); var HorizontalLayout = withVanillaControlProps(withJsonFormsLayoutProps(HorizontalLayoutRenderer, false)); const verticalLayoutTester = rankWith$1(1, uiTypeIs('VerticalLayout')); const VerticalLayoutRenderer = (props) => { const { data: _data, ...otherProps } = props; return React.createElement(VerticalLayoutRendererComponent, { ...otherProps }); }; const VerticalLayoutRendererComponent = React.memo(function VerticalLayoutRendererComponent({ schema, uischema, path, visible, enabled, getStyle, getStyleAsClassName, }) { const verticalLayout = uischema; const elementsSize = verticalLayout.elements ? verticalLayout.elements.length : 0; const layoutClassName = getStyleAsClassName('vertical.layout'); const childClassNames = ['vertical-layout-item'] .concat(getStyle('vertical.layout.item', elementsSize)) .join(' '); return (React.createElement(JsonFormsLayout, { className: layoutClassName, uischema: uischema, schema: schema, visible: visible, enabled: enabled, path: path, getStyle: getStyle, getStyleAsClassName: getStyleAsClassName }, renderChildren(verticalLayout, schema, childClassNames, path, enabled))); }); var VerticalLayout = withVanillaControlProps(withJsonFormsLayoutProps(VerticalLayoutRenderer, false)); const vanillaRenderers = [ { tester: inputControlTester, renderer: InputControl$1 }, { tester: radioGroupControlTester, renderer: RadioGroupControl$1 }, { tester: oneOfRadioGroupControlTester, renderer: OneOfRadioGroupControl$1 }, { tester: arrayControlTester, renderer: ArrayControlRenderer$1 }, { tester: labelRendererTester, renderer: LabelRenderer$1 }, { tester: categorizationTester, renderer: CategorizationRenderer$1 }, { tester: tableArrayControlTester, renderer: TableArrayControl$1 }, { tester: groupTester, renderer: GroupLayout }, { tester: verticalLayoutTester, renderer: VerticalLayout }, { tester: horizontalLayoutTester, renderer: HorizontalLayout }, ]; const vanillaCells = [ { tester: booleanCellTester, cell: BooleanCell$1 }, { tester: dateCellTester, cell: DateCell$1 }, { tester: dateTimeCellTester, cell: DateTimeCell$1 }, { tester: enumCellTester, cell: EnumCell$1 }, { tester: integerCellTester, cell: IntegerCell$1 }, { tester: numberCellTester, cell: NumberCell$1 }, { tester: oneOfEnumCellTester, cell: OneOfEnumCell$1 }, { tester: sliderCellTester, cell: SliderCell$1 }, { tester: textAreaCellTester, cell: TextAreaCell$1 }, { tester: textCellTester, cell: TextCell$1 }, { tester: timeCellTester, cell: TimeCell$1 }, ]; export { ArrayControlRenderer$1 as ArrayControl, BooleanCell$1 as BooleanCell, CategorizationRenderer$1 as Categorization, CustomizableCells as Customizable, DateCell$1 as DateCell, DateTimeCell$1 as DateTimeCell, EnumCell$1 as EnumCell, GroupLayout, HorizontalLayout, InputControl$1 as InputControl, IntegerCell$1 as IntegerCell, JsonFormsStyleContext, LabelRenderer$1 as LabelRenderer, NumberCell$1 as NumberCell, NumberFormatCell$1 as NumberFormatCell, OneOfEnumCell$1 as OneOfEnumCell, OneOfRadioGroupControl$1 as OneOfRadioGroupControl, REGISTER_STYLE, REGISTER_STYLES, RadioGroupControl$1 as RadioGroupControl, SliderCell$1 as SliderCell, TableArrayControl$1 as TableArrayControl, TextAreaCell$1 as TextAreaCell, TextCell$1 as TextCell, TimeCell$1 as TimeCell, UNREGISTER_STYLE, VerticalLayout, addVanillaCellProps, addVanillaControlProps, addVanillaLayoutProps, arrayControlTester, booleanCellTester, categorizationTester, dateCellTester, dateTimeCellTester, enumCellTester, getStyle, getStyleAsClassName, groupTester, horizontalLayoutTester, i18nDefaults, inputControlTester, integerCellTester, labelRendererTester, numberCellTester, numberFormatCellTester, oneOfEnumCellTester, oneOfRadioGroupControlTester, radioGroupControlTester, registerStyle$1 as registerStyle, registerStyles, sliderCellTester, stylingReducer, tableArrayControlTester, textAreaCellTester, textCellTester, timeCellTester, unregisterStyle, useStyleContext, useStyles, vanillaCells, vanillaRenderers, vanillaStyles, verticalLayoutTester, withAjvProps, withVanillaBooleanCellProps, withVanillaCellProps, withVanillaControlProps, withVanillaEnumCellProps }; //# sourceMappingURL=jsonforms-react-vanilla.esm.js.map