diff --git a/packages/examples/src/examples/nestedCategorization.ts b/packages/examples/src/examples/nestedCategorization.ts new file mode 100644 index 000000000..1d6a1ee31 --- /dev/null +++ b/packages/examples/src/examples/nestedCategorization.ts @@ -0,0 +1,176 @@ +/* + The MIT License + + Copyright (c) 2023 EclipseSource Munich + https://github.com/eclipsesource/jsonforms + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the 'Software'), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ +import { registerExamples } from '../register'; + +export const schema = { + type: 'object', + properties: { + cat1: { + type: 'object', + properties: { + subcat11: { + type: 'string' + } + } + }, + cat2: { + type: 'object', + properties: { + subcat21: { + type: 'string' + }, + subcat22: { + type: 'string' + } + } + }, + cat3: { + type: 'object', + properties: { + subcat31: { + type: 'string' + }, + subcat32: { + type: 'string' + }, + subcat33: { + type: 'string' + } + } + } + } +} + +export const uischema = { + type: 'Categorization', + elements: [ + { + type: 'Category', + label: 'Cat1', + elements: [ + { + type: 'Categorization', + elements: [ + { + type: 'Category', + label: 'SubCat1-1', + elements: [ + { + type: 'Control', + scope: '#/properties/cat1/properties/subcat11' + } + ] + } + ] + } + ] + }, + { + type: 'Category', + label: 'Cat2', + elements: [ + { + type: 'Categorization', + elements: [ + { + type: 'Category', + label: 'SubCat2-1', + elements: [ + { + type: 'Control', + scope: '#/properties/cat2/properties/subcat21' + } + ] + }, + { + type: 'Category', + label: 'SubCat2-2', + elements: [ + { + type: 'Control', + scope: '#/properties/cat2/properties/subcat22' + } + ] + } + ] + } + ] + }, + , + { + type: 'Category', + label: 'Cat3', + elements: [ + { + type: 'Categorization', + elements: [ + { + type: 'Category', + label: 'SubCat3-1', + elements: [ + { + type: 'Control', + scope: '#/properties/cat3/properties/subcat31' + } + ] + }, + { + type: 'Category', + label: 'SubCat3-2', + elements: [ + { + type: 'Control', + scope: '#/properties/cat3/properties/subcat32' + } + ] + }, + { + type: 'Category', + label: 'SubCat3-3', + elements: [ + { + type: 'Control', + scope: '#/properties/cat3/properties/subcat33' + } + ] + } + ] + } + ] + } + ] +}; + +export const data = {}; + +registerExamples([ + { + name: 'nestedCategorization', + label: 'Nested Categorization', + data, + schema, + uischema + } +]); diff --git a/packages/examples/src/index.ts b/packages/examples/src/index.ts index a9b955b2e..0bd5c7af9 100644 --- a/packages/examples/src/index.ts +++ b/packages/examples/src/index.ts @@ -30,6 +30,7 @@ import * as anyOfOneOfAllOfResolve from './examples/anyOf-oneOf-allOf-resolve'; import * as array from './examples/arrays'; import * as arrayI18n from './examples/arraysI18n'; import * as nestedArray from './examples/nestedArrays'; +import * as nestedCategorization from './examples/nestedCategorization'; import * as arrayWithDetail from './examples/arrays-with-detail'; import * as arrayWithDetailAndRule from './examples/arrays-with-detail-and-rule'; import * as arrayWithCustomChildLabel from './examples/arrays-with-custom-element-label'; @@ -100,6 +101,7 @@ export { array, arrayI18n, nestedArray, + nestedCategorization, arrayWithDetail, arrayWithDetailAndRule, arrayWithCustomChildLabel, diff --git a/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx b/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx index 38c956944..65c862f3f 100644 --- a/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx +++ b/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React, {useState, useMemo} from 'react'; +import React, { useState, useMemo } from 'react'; import { AppBar, Hidden, Tab, Tabs } from '@mui/material'; import { and, @@ -92,12 +92,21 @@ export const MaterialCategorizationLayoutRenderer = (props: MaterialCategorizati t } = props; const categorization = uischema as Categorization; - const [activeCategory, setActiveCategory]= useState(selected??0); + const [previousCategorization, setPreviousCategorization] = useState(uischema as Categorization); + const [activeCategory, setActiveCategory] = useState(selected ?? 0); const categories = useMemo(() => categorization.elements.filter((category: Category) => isVisible(category, data, undefined, ajv) - ),[categorization, data, ajv]); + ), [categorization, data, ajv]); + + if (categorization !== previousCategorization) { + setActiveCategory(0); + setPreviousCategorization(categorization); + } + + const safeCategory = activeCategory >= categorization.elements.length ? 0 : activeCategory; + const childProps: MaterialLayoutRendererProps = { - elements: categories[activeCategory].elements, + elements: categories[safeCategory] ? categories[safeCategory].elements : [], schema, path, direction: 'column', @@ -108,13 +117,13 @@ export const MaterialCategorizationLayoutRenderer = (props: MaterialCategorizati }; const onTabChange = (_event: any, value: any) => { if (onChange) { - onChange(value, activeCategory); + onChange(value, safeCategory); } setActiveCategory(value); }; const tabLabels = useMemo(() => { - return categories.map((e: Category) => + return categories.map((e: Category) => deriveLabelForUISchemaElement(e, t) ) }, [categories, t]) @@ -122,17 +131,18 @@ export const MaterialCategorizationLayoutRenderer = (props: MaterialCategorizati return ( - + {categories.map((_, idx: number) => ( ))}
- +
); }; export default withAjvProps(withTranslateProps(withJsonFormsLayoutProps(MaterialCategorizationLayoutRenderer))); +