diff --git a/CHANGELOG.md b/CHANGELOG.md index 22131cadb1..979b70d83c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,20 +17,98 @@ should change the heading of the (upcoming) version to include a major version b --> # 6.0.0-beta.21 +## @rjsf/antd + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to fix up the props in `AntdIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` + +## @rjsf/chakra-ui + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to add `ChakraIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` + ## @rjsf/core - Added `initialDefaultsGenerated` flag to state, which indicates whether the initial generation of defaults has been completed -- Added `ObjectField` tests for additionalProperties with defaults +- Added `ObjectField` tests for additionalProperties with defaults +- Added a new `OptionalDataControlsField` to the `fields` that renders either undefined (when there is data for a readonly/disabled field) or gets the `OptionalDataControlsTemplate` and renders the `label` and potentially an `onAddClick` or `onRemoveClick` function +- Updated `ArrayField` and `ObjectField` to check whether it `shouldRenderOptionalData()` and if true, calls `ObjectDataControlsField` and passes the result to its associated render template as `optionalDataControl` +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list + +## @rjsf/daisyui + +- Updated `ArrayFieldTemplate`, `ArrayFieldTitleTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to better support the `OptionalDataControlTemplate` + +## @rjsf/fluentui-rc + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to add `FluentIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` + +## @rjsf/mantine + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list + +## @rjsf/mui + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list + +## @rjsf/primereact + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to add `PrimeIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` + +## @rjsf/react-bootstrap + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to add `BootstrapIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` + +## @rjsf/semantic-ui + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to add `SemanticIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` + +## @rjsf/shadcn + +- Updated `ArrayFieldTemplate`, `ObjectFieldTemplate`, `TitleField` to add support for the new `optionalDataControl` feature + - Added the new `OptionalDataControlTemplate` to the theme, adding it to the `templates` list +- Updated the `ButtonTemplates` classes to add `ShadIconButtonProps` and the `IconButton`s associated with them to better support the `OptionalDataControlTemplate` ## @rjsf/utils - Updated `getDefaultFormState` to add a new `initialDefaultsGenerated` prop flag, along with type definitions, fixing uneditable & permanent defaults with additional properties [3759](https://github.com/rjsf-team/react-jsonschema-form/issues/3759) - Updated `createSchemaUtils` definition to reflect addition of `initialDefaultsGenerated` - Updated existing tests where `getDefaultFormState` is used to reflect addition of `initialDefaultsGenerated` - -## @rjsf/docs - -- Updated docs for `getDefaultFormState` to reflect addition of `initialDefaultsGenerated` prop +- Updated `types.ts` to support the new `Optional Data Controls` feature as follows: + - Added new `OptionalDataControlsTemplateProps` and refactored the common props from `ArrayFieldTemplateProps` and `ObjectFieldTemplateProps` into a new super type, `ContainerFieldTemplateProps` + - Added new `optionalDataControl?: ReactNode` to the `ArrayFieldTitleProps`, `TitleFieldProps` and `ContainerFieldTemplateProps` + - Updated `GlobalFormOptions` to add new `enableOptionalDataFieldForType?: ('object' | 'array')[]` prop + - Updated `SchemaUtilsType`'s `retrieveSchema()` function to add an additional, property `resolveAnyOfOrOneOfRefs?: boolean` +- Updated the `Templates` interface to add a new required template `OptionalDataControlsTemplate: ComponentType>` +- Updated `retrieveSchema()` to add an additional property `resolveAnyOfOrOneOfRefs?: boolean` which causes `resolveAllSchemas()` to resolve `$ref`s inside of the options of `anyOf`/`oneOf` schemas +- Updated `getDefaultFormState` to fix an issue where optional array props had their default set to an empty array when they shouldn't be +- Updated the `TranslatableString` enum to add three new strings in support of the new feature: `OptionalObjectAdd`, `OptionalObjectRemove` and `OptionalObjectEmptyMsg` +- Added four new utility functions: `isFormDataAvailable()`, `isRootSchema()`, `optionalControlsId()`, and `shouldRenderOptionalField()` + +## Dev / docs / playground + +- Updated docs for `getDefaultFormState` to reflect addition of the `initialDefaultsGenerated` prop +- Updated `utility-function.me` docs to add documentation for the new functions + - Also updated docs for `retrieveSchema` and `SchemaUtilsType` for the new prop +- Updated `uiSchema.md` to add documentation for the new `enableOptionalDataFieldForType` prop +- Updated the `v6x upgrade guide.md` to document the new feature and utility functions and changes to `retrieveSchema` +- Updated the playground to add a new `Optional Data Controls` example +- Updated the snapshot and jest tests for `Form` to test the new `Optional Data Controls` feature # 6.0.0-beta-20 diff --git a/packages/antd/src/templates/ArrayFieldTemplate/index.tsx b/packages/antd/src/templates/ArrayFieldTemplate/index.tsx index 213660f390..fe9f670c23 100644 --- a/packages/antd/src/templates/ArrayFieldTemplate/index.tsx +++ b/packages/antd/src/templates/ArrayFieldTemplate/index.tsx @@ -32,6 +32,7 @@ export default function ArrayFieldTemplate< disabled, fieldPathId, items, + optionalDataControl, onAddClick, readonly, registry, @@ -56,6 +57,7 @@ export default function ArrayFieldTemplate< registry, uiOptions, ); + const showOptionalDataControlInTitle = !readonly && !disabled; const { formContext } = registry; // Button templates are not overridden in the uiSchema const { @@ -84,6 +86,7 @@ export default function ArrayFieldTemplate< schema={schema} uiSchema={uiSchema} registry={registry} + optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined} /> )} @@ -99,12 +102,11 @@ export default function ArrayFieldTemplate< )} - {items && - items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( - - ))} + {!showOptionalDataControlInTitle ? optionalDataControl : undefined} + {items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( + + ))} - {canAdd && ( diff --git a/packages/antd/src/templates/IconButton/index.tsx b/packages/antd/src/templates/IconButton/index.tsx index 82586117da..c7308e1a61 100644 --- a/packages/antd/src/templates/IconButton/index.tsx +++ b/packages/antd/src/templates/IconButton/index.tsx @@ -14,22 +14,24 @@ import { } from '@rjsf/utils'; import { MouseEventHandler } from 'react'; -// The `type` and `color` for IconButtonProps collides with props of `ButtonProps` so omit it to avoid Typescript issue export type AntdIconButtonProps< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any, -> = Omit, 'type' | 'color'>; +> = IconButtonProps & Pick; export default function IconButton( - props: AntdIconButtonProps & Omit, + props: AntdIconButtonProps, ) { - const { iconType = 'default', icon, onClick, uiSchema, registry, ...otherProps } = props; + const { iconType = 'default', icon, onClick, uiSchema, registry, color, ...otherProps } = props; return ( + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + Option 1 + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + +`; + +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema, readonly and no formData 1`] = ` +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + Option 1 + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema and formData 1`] = ` +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + Option 1 + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema, readonly and formData 1`] = ` +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + Option 1 + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema and no formData 1`] = ` +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + Option 1 + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema, disabled and no formData 1`] = ` +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + Option 1 + + +
+ + + + + +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+`; + exports[`single fields password field 1`] = `
Titre 1 +
Person Info +
@@ -1897,6 +1906,15 @@ exports[`Complex grid renders person and address and employment in a complex gri > Person Info +
@@ -3789,6 +3807,15 @@ exports[`Complex grid renders person and address and employment in a complex gri > Person Info +
@@ -5297,6 +5324,15 @@ exports[`Complex grid renders person and address and employment in a complex gri > Person Info +
@@ -7104,6 +7140,15 @@ exports[`Three even column grid renders person and address in three columns, no > Person Info +
@@ -8149,6 +8194,15 @@ exports[`Two even column grid renders person and address in two columns, no empl > Person Info +
diff --git a/packages/antd/test/__snapshots__/Object.test.tsx.snap b/packages/antd/test/__snapshots__/Object.test.tsx.snap index b631f7d8ff..dc99af31b8 100644 --- a/packages/antd/test/__snapshots__/Object.test.tsx.snap +++ b/packages/antd/test/__snapshots__/Object.test.tsx.snap @@ -240,7 +240,11 @@ exports[`object fields additionalProperties 1`] = ` disabled={false} id="root_foo__remove" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Remove" type="button" > @@ -303,7 +307,11 @@ exports[`object fields additionalProperties 1`] = ` disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -907,7 +915,11 @@ exports[`object fields show add button and fields if additionalProperties is tru disabled={false} id="root_additionalProperty__remove" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Remove" type="button" > @@ -970,7 +982,11 @@ exports[`object fields show add button and fields if additionalProperties is tru disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -1086,6 +1102,15 @@ exports[`object fields with title and description additionalProperties 1`] = ` > Test field +
@@ -1363,7 +1392,11 @@ exports[`object fields with title and description additionalProperties 1`] = ` disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -1493,6 +1526,15 @@ exports[`object fields with title and description from both additionalProperties > My Field +
@@ -1770,7 +1816,11 @@ exports[`object fields with title and description from both additionalProperties disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -1900,6 +1950,15 @@ exports[`object fields with title and description from both object 1`] = ` > My Field +
My Field +
@@ -2561,7 +2633,11 @@ exports[`object fields with title and description from uiSchema additionalProper disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -2691,6 +2767,15 @@ exports[`object fields with title and description from uiSchema object 1`] = ` > My Field +
My Field +
@@ -3352,7 +3450,11 @@ exports[`object fields with title and description from uiSchema show add button disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -3482,6 +3584,15 @@ exports[`object fields with title and description object 1`] = ` > Test field +
Test field +
@@ -4143,7 +4267,11 @@ exports[`object fields with title and description show add button and fields if disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -4441,7 +4569,11 @@ exports[`object fields with title and description with global label off addition disabled={false} id="root_foo__remove" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Remove" type="button" > @@ -4504,7 +4636,11 @@ exports[`object fields with title and description with global label off addition disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > @@ -5128,7 +5264,11 @@ exports[`object fields with title and description with global label off show add disabled={false} id="root_additionalProperty__remove" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Remove" type="button" > @@ -5191,7 +5331,11 @@ exports[`object fields with title and description with global label off show add disabled={false} id="root__add" onClick={[Function]} - style={{}} + style={ + { + "paddingTop": "4px", + } + } title="Add Item" type="button" > diff --git a/packages/chakra-ui/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx b/packages/chakra-ui/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx index 1680fc61e1..227f2fa423 100644 --- a/packages/chakra-ui/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx +++ b/packages/chakra-ui/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx @@ -15,8 +15,20 @@ export default function ArrayFieldTemplate< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any, >(props: ArrayFieldTemplateProps) { - const { canAdd, disabled, fieldPathId, uiSchema, items, onAddClick, readonly, registry, required, schema, title } = - props; + const { + canAdd, + disabled, + fieldPathId, + uiSchema, + items, + optionalDataControl, + onAddClick, + readonly, + registry, + required, + schema, + title, + } = props; const uiOptions = getUiOptions(uiSchema); const ArrayFieldDescriptionTemplate = getTemplate<'ArrayFieldDescriptionTemplate', T, S, F>( 'ArrayFieldDescriptionTemplate', @@ -33,6 +45,7 @@ export default function ArrayFieldTemplate< registry, uiOptions, ); + const showOptionalDataControlInTitle = !readonly && !disabled; // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, @@ -46,6 +59,7 @@ export default function ArrayFieldTemplate< uiSchema={uiSchema} required={required} registry={registry} + optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined} /> - {items.length > 0 && - items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( - - ))} + {!showOptionalDataControlInTitle ? optionalDataControl : undefined} + {items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( + + ))} {canAdd && ( - + = RJSFIconButtonProps & Omit; function ChakraIconButton( - props: IconButtonProps, + props: ChakraIconButtonProps, ) { const { icon, iconType, uiSchema, registry, ...otherProps } = props; diff --git a/packages/chakra-ui/src/IconButton/IconButton.tsx b/packages/chakra-ui/src/IconButton/IconButton.tsx index 0802259553..c3d3f7a2b1 100644 --- a/packages/chakra-ui/src/IconButton/IconButton.tsx +++ b/packages/chakra-ui/src/IconButton/IconButton.tsx @@ -1,10 +1,10 @@ -import { FormContextType, IconButtonProps, RJSFSchema, StrictRJSFSchema, TranslatableString } from '@rjsf/utils'; - +import { FormContextType, RJSFSchema, StrictRJSFSchema, TranslatableString } from '@rjsf/utils'; import { ArrowUpIcon, ArrowDownIcon, CopyIcon, DeleteIcon } from 'lucide-react'; -import ChakraIconButton from './ChakraIconButton'; + +import ChakraIconButton, { ChakraIconButtonProps } from './ChakraIconButton'; export function CopyButton( - props: IconButtonProps, + props: ChakraIconButtonProps, ) { const { registry: { translateString }, @@ -15,7 +15,7 @@ export function CopyButton( - props: IconButtonProps, + props: ChakraIconButtonProps, ) { const { registry: { translateString }, @@ -30,7 +30,7 @@ export function MoveDownButton( - props: IconButtonProps, + props: ChakraIconButtonProps, ) { const { registry: { translateString }, @@ -45,7 +45,7 @@ export function MoveUpButton( - props: IconButtonProps, + props: ChakraIconButtonProps, ) { const { registry: { translateString }, diff --git a/packages/chakra-ui/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx b/packages/chakra-ui/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx index 87c500034b..6d39663644 100644 --- a/packages/chakra-ui/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx +++ b/packages/chakra-ui/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx @@ -28,6 +28,7 @@ export default function ObjectFieldTemplate< fieldPathId, schema, formData, + optionalDataControl, onAddClick, registry, } = props; @@ -38,6 +39,7 @@ export default function ObjectFieldTemplate< registry, uiOptions, ); + const showOptionalDataControlInTitle = !readonly && !disabled; // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, @@ -53,6 +55,7 @@ export default function ObjectFieldTemplate< schema={schema} uiSchema={uiSchema} registry={registry} + optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined} /> )} {description && ( @@ -64,7 +67,8 @@ export default function ObjectFieldTemplate< registry={registry} /> )} - + + {!showOptionalDataControlInTitle ? {optionalDataControl} : undefined} {properties.map((element, index) => element.hidden ? ( element.content diff --git a/packages/chakra-ui/src/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx b/packages/chakra-ui/src/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx new file mode 100644 index 0000000000..4536fac506 --- /dev/null +++ b/packages/chakra-ui/src/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx @@ -0,0 +1,47 @@ +import { FormContextType, OptionalDataControlsTemplateProps, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { PlusIcon } from 'lucide-react'; + +import ChakraIconButton, { RemoveButton } from '../IconButton'; + +/** The OptionalDataControlsTemplate renders one of three different states. If + * there is an `onAddClick()` function, it renders the "Add" button. If there is + * an `onRemoveClick()` function, it renders the "Remove" button. Otherwise it + * renders the "No data found" section. All of them use the `label` as either + * the `title` of buttons or simply outputting it. + * + * @param props - The `OptionalDataControlsTemplateProps` for the template + */ +export default function OptionalDataControlsTemplate< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: OptionalDataControlsTemplateProps) { + const { id, registry, label, onAddClick, onRemoveClick } = props; + if (onAddClick) { + return ( + } + size='xs' + variant='subtle' + /> + ); + } else if (onRemoveClick) { + return ( + + ); + } + return {label}; +} diff --git a/packages/chakra-ui/src/OptionalDataControlsTemplate/index.ts b/packages/chakra-ui/src/OptionalDataControlsTemplate/index.ts new file mode 100644 index 0000000000..cf4d5a78ee --- /dev/null +++ b/packages/chakra-ui/src/OptionalDataControlsTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from './OptionalDataControlsTemplate'; +export * from './OptionalDataControlsTemplate'; diff --git a/packages/chakra-ui/src/Templates/Templates.ts b/packages/chakra-ui/src/Templates/Templates.ts index 5dca9821ec..ab8cf81317 100644 --- a/packages/chakra-ui/src/Templates/Templates.ts +++ b/packages/chakra-ui/src/Templates/Templates.ts @@ -11,6 +11,7 @@ import FieldTemplate from '../FieldTemplate'; import GridTemplate from '../GridTemplate'; import MultiSchemaFieldTemplate from '../MultiSchemaFieldTemplate'; import ObjectFieldTemplate from '../ObjectFieldTemplate'; +import OptionalDataControlsTemplate from '../OptionalDataControlsTemplate'; import SubmitButton from '../SubmitButton'; import TitleField from '../TitleField'; import WrapIfAdditionalTemplate from '../WrapIfAdditionalTemplate'; @@ -41,6 +42,7 @@ export function generateTemplates< GridTemplate, MultiSchemaFieldTemplate, ObjectFieldTemplate, + OptionalDataControlsTemplate, TitleFieldTemplate: TitleField, WrapIfAdditionalTemplate, }; diff --git a/packages/chakra-ui/src/TitleField/TitleField.tsx b/packages/chakra-ui/src/TitleField/TitleField.tsx index e30a8164d7..6867437877 100644 --- a/packages/chakra-ui/src/TitleField/TitleField.tsx +++ b/packages/chakra-ui/src/TitleField/TitleField.tsx @@ -1,13 +1,24 @@ import { FormContextType, RJSFSchema, StrictRJSFSchema, TitleFieldProps } from '@rjsf/utils'; -import { Box, Separator, Heading } from '@chakra-ui/react'; +import { Box, Flex, Heading, Separator, Spacer } from '@chakra-ui/react'; export default function TitleField({ id, title, + optionalDataControl, }: TitleFieldProps) { + let heading = {title}; + if (optionalDataControl) { + heading = ( + + {heading} + + {optionalDataControl} + + ); + } return ( - {title} + {heading} ); diff --git a/packages/chakra-ui/test/__snapshots__/Array.test.tsx.snap b/packages/chakra-ui/test/__snapshots__/Array.test.tsx.snap index 92dc08f9da..0f0f9af000 100644 --- a/packages/chakra-ui/test/__snapshots__/Array.test.tsx.snap +++ b/packages/chakra-ui/test/__snapshots__/Array.test.tsx.snap @@ -1812,7 +1812,7 @@ exports[`array fields empty errors array 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -2631,7 +2631,7 @@ exports[`array fields has errors 1`] = ` .emotion-10 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -3020,7 +3020,7 @@ exports[`array fields no errors 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } diff --git a/packages/chakra-ui/test/__snapshots__/Form.test.tsx.snap b/packages/chakra-ui/test/__snapshots__/Form.test.tsx.snap index 6335e95add..949b0504b6 100644 --- a/packages/chakra-ui/test/__snapshots__/Form.test.tsx.snap +++ b/packages/chakra-ui/test/__snapshots__/Form.test.tsx.snap @@ -2145,7 +2145,7 @@ exports[`single fields field with description 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -2493,7 +2493,7 @@ exports[`single fields field with description in uiSchema 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -2841,7 +2841,7 @@ exports[`single fields field with markdown description 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -3195,7 +3195,7 @@ exports[`single fields field with markdown description in uiSchema 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -5024,7 +5024,7 @@ exports[`single fields hidden field 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -6080,6 +6080,10924 @@ exports[`single fields number field 1`] = ` `; +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema and no formData 1`] = ` +@layer recipes { + .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + } + + .emotion-0>:not(style, [hidden])~:not(style, [hidden]) { + --space-y-reverse: 0; + margin-top: calc(var(--chakra-spacing-4) * calc(1 - var(--space-y-reverse))); + margin-bottom: calc(var(--chakra-spacing-4) * var(--space-y-reverse)); + } +} + +@layer recipes { + .emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + gap: var(--chakra-spacing-4); + } +} + +.emotion-2 { + margin-top: var(--chakra-spacing-1); + margin-bottom: var(--chakra-spacing-4); +} + +@layer recipes { + .emotion-3 { + font-family: var(--chakra-fonts-heading); + font-weight: var(--chakra-font-weights-semibold); + font-size: var(--chakra-font-sizes-xl); + line-height: 1.875rem; + } +} + +@layer recipes { + .emotion-4 { + display: block; + border-color: var(--chakra-colors-border); + --separator-thickness: 1px; + border-style: solid; + border-top-width: var(--separator-thickness); + } +} + +.emotion-5 { + display: grid; + gap: var(--chakra-spacing-4); + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-14 { + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-14 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-15 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: start; + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + font-weight: var(--chakra-font-weights-medium); + gap: var(--chakra-spacing-1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + .emotion-15:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + } +} + +@layer recipes { + .emotion-16 { + width: 100%; + min-width: var(--input-height); + outline: 0; + position: relative; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + text-align: start; + border-radius: var(--chakra-radii-l2); + height: var(--input-height); + --focus-color: var(--chakra-colors-color-palette-focus-ring); + --error-color: var(--chakra-colors-border-error); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + padding-inline: var(--chakra-spacing-3); + --input-height: var(--chakra-sizes-10); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + --focus-ring-color: var(--focus-color); + } + + .emotion-16:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-16:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + --focus-ring-color: var(--error-color); + border-color: var(--error-color); + } + + .emotion-16:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } +} + +.emotion-44 { + display: grid; +} + +.emotion-45 { + justify-self: flex-end; +} + +.emotion-46 { + margin-top: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-47 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-47:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-47:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-47 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-47:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-47:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-97 { + margin-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-97 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + min-width: 0; + word-wrap: break-word; + border-radius: var(--chakra-radii-l3); + color: var(--chakra-colors-fg); + text-align: start; + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + border-width: 1px; + border-color: var(--chakra-colors-border); + --card-padding: var(--chakra-spacing-6); + } +} + +.emotion-98 { + padding-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-98 { + padding: var(--card-padding); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-99 { + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-100 { + margin-bottom: var(--chakra-spacing-1); + position: relative; +} + +@layer recipes { + .emotion-100 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-102 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: var(--chakra-spacing-1\\.5); + width: var(--chakra-sizes-full); + --select-trigger-height: var(--chakra-sizes-10); + --select-trigger-padding-x: var(--chakra-spacing-3); + } +} + +@layer recipes { + .emotion-103 { + position: relative; + } +} + +@layer recipes { + .emotion-105 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + width: var(--chakra-sizes-full); + min-height: var(--select-trigger-height); + --input-height: var(--select-trigger-height); + padding-inline: var(--select-trigger-padding-x); + border-radius: var(--chakra-radii-l2); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: start; + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + } + + .emotion-105:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } + + .emotion-105:is(:placeholder-shown, [data-placeholder-shown]) { + --mix-color: color-mix(in srgb, var(--chakra-colors-fg-muted) 80%, transparent); + color: var(--mix-color, var(--chakra-colors-fg-muted)); + } + + .emotion-105:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-105:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + border-color: var(--chakra-colors-border-error); + } + + .emotion-105:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + border-color: var(--chakra-colors-border-emphasized); + } +} + +@layer recipes { + .emotion-106 { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-wrap: wrap; + max-width: 80%; + } +} + +@layer recipes { + .emotion-107 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-1); + position: absolute; + inset-inline-end: 0; + top: 0; + bottom: 0; + padding-inline: var(--select-trigger-padding-x); + pointer-events: none; + } +} + +@layer recipes { + .emotion-108 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + color: var(--chakra-colors-fg-muted); + } + + .emotion-108:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + color: var(--chakra-colors-fg-subtle); + } + + .emotion-108:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + color: var(--chakra-colors-fg-error); + } + + .emotion-108 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +.emotion-109 { + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; +} + +.emotion-110 { + min-width: 100%!important; + z-index: 2!important; + top: calc(100% + 5px)!important; +} + +@layer recipes { + .emotion-111 { + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + z-index: var(--chakra-z-index-dropdown); + border-radius: var(--chakra-radii-l2); + outline: 0; + max-height: var(--chakra-sizes-96); + overflow-y: auto; + box-shadow: var(--chakra-shadows-md); + padding: var(--chakra-spacing-1); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + } + + .emotion-111:is([open], [data-open], [data-state=open]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fast); + animation-duration: var(--chakra-durations-fast); + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=top] { + -webkit-animation-name: slide-from-bottom,fade-in; + animation-name: slide-from-bottom,fade-in; + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=bottom] { + -webkit-animation-name: slide-from-top,fade-in; + animation-name: slide-from-top,fade-in; + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=left] { + -webkit-animation-name: slide-from-right,fade-in; + animation-name: slide-from-right,fade-in; + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=right] { + -webkit-animation-name: slide-from-left,fade-in; + animation-name: slide-from-left,fade-in; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fastest); + animation-duration: var(--chakra-durations-fastest); + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=top] { + -webkit-animation-name: slide-to-bottom,fade-out; + animation-name: slide-to-bottom,fade-out; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=bottom] { + -webkit-animation-name: slide-to-top,fade-out; + animation-name: slide-to-top,fade-out; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=left] { + -webkit-animation-name: slide-to-right,fade-out; + animation-name: slide-to-right,fade-out; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=right] { + -webkit-animation-name: slide-to-left,fade-out; + animation-name: slide-to-left,fade-out; + } +} + +@layer recipes { + .emotion-112 { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-2); + cursor: var(--chakra-cursor-option); + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: start; + border-radius: var(--chakra-radii-l1); + padding-block: var(--chakra-spacing-1\\.5); + padding-inline: var(--chakra-spacing-2); + } + + .emotion-112[data-highlighted] { + --mix-background: color-mix(in srgb, var(--chakra-colors-bg-emphasized) 60%, transparent); + background: var(--mix-background, var(--chakra-colors-bg-emphasized)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-bg-emphasized)); + } + + .emotion-112:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + pointer-events: none; + opacity: 0.5; + } + + .emotion-112 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +@layer recipes { + .emotion-113 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +.emotion-132 { + margin-top: var(--chakra-spacing-3); +} + +
+
+
+
+
+
+ test +
+ +
+
+
+
+
+
+
+
+ nestedObjectOptional +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ deepObjectOptional +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepObject +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+`; + +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema, readonly and no formData 1`] = ` +@layer recipes { + .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + } + + .emotion-0>:not(style, [hidden])~:not(style, [hidden]) { + --space-y-reverse: 0; + margin-top: calc(var(--chakra-spacing-4) * calc(1 - var(--space-y-reverse))); + margin-bottom: calc(var(--chakra-spacing-4) * var(--space-y-reverse)); + } +} + +@layer recipes { + .emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + gap: var(--chakra-spacing-4); + } +} + +.emotion-2 { + margin-top: var(--chakra-spacing-1); + margin-bottom: var(--chakra-spacing-4); +} + +@layer recipes { + .emotion-3 { + font-family: var(--chakra-fonts-heading); + font-weight: var(--chakra-font-weights-semibold); + font-size: var(--chakra-font-sizes-xl); + line-height: 1.875rem; + } +} + +@layer recipes { + .emotion-4 { + display: block; + border-color: var(--chakra-colors-border); + --separator-thickness: 1px; + border-style: solid; + border-top-width: var(--separator-thickness); + } +} + +.emotion-5 { + display: grid; + gap: var(--chakra-spacing-4); + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-14 { + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-14 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-15 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: start; + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + font-weight: var(--chakra-font-weights-medium); + gap: var(--chakra-spacing-1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + .emotion-15:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + } +} + +@layer recipes { + .emotion-16 { + width: 100%; + min-width: var(--input-height); + outline: 0; + position: relative; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + text-align: start; + border-radius: var(--chakra-radii-l2); + height: var(--input-height); + --focus-color: var(--chakra-colors-color-palette-focus-ring); + --error-color: var(--chakra-colors-border-error); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + padding-inline: var(--chakra-spacing-3); + --input-height: var(--chakra-sizes-10); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + --focus-ring-color: var(--focus-color); + } + + .emotion-16:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-16:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + --focus-ring-color: var(--error-color); + border-color: var(--error-color); + } + + .emotion-16:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } +} + +.emotion-44 { + display: grid; +} + +.emotion-45 { + justify-self: flex-end; +} + +.emotion-46 { + margin-top: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-47 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-47:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-47:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-47 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-47:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-47:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-97 { + margin-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-97 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + min-width: 0; + word-wrap: break-word; + border-radius: var(--chakra-radii-l3); + color: var(--chakra-colors-fg); + text-align: start; + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + border-width: 1px; + border-color: var(--chakra-colors-border); + --card-padding: var(--chakra-spacing-6); + } +} + +.emotion-98 { + padding-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-98 { + padding: var(--card-padding); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-99 { + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-100 { + margin-bottom: var(--chakra-spacing-1); + position: relative; +} + +@layer recipes { + .emotion-100 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-102 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: var(--chakra-spacing-1\\.5); + width: var(--chakra-sizes-full); + --select-trigger-height: var(--chakra-sizes-10); + --select-trigger-padding-x: var(--chakra-spacing-3); + } +} + +@layer recipes { + .emotion-103 { + position: relative; + } +} + +@layer recipes { + .emotion-105 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + width: var(--chakra-sizes-full); + min-height: var(--select-trigger-height); + --input-height: var(--select-trigger-height); + padding-inline: var(--select-trigger-padding-x); + border-radius: var(--chakra-radii-l2); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: start; + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + } + + .emotion-105:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } + + .emotion-105:is(:placeholder-shown, [data-placeholder-shown]) { + --mix-color: color-mix(in srgb, var(--chakra-colors-fg-muted) 80%, transparent); + color: var(--mix-color, var(--chakra-colors-fg-muted)); + } + + .emotion-105:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-105:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + border-color: var(--chakra-colors-border-error); + } + + .emotion-105:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + border-color: var(--chakra-colors-border-emphasized); + } +} + +@layer recipes { + .emotion-106 { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-wrap: wrap; + max-width: 80%; + } +} + +@layer recipes { + .emotion-107 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-1); + position: absolute; + inset-inline-end: 0; + top: 0; + bottom: 0; + padding-inline: var(--select-trigger-padding-x); + pointer-events: none; + } +} + +@layer recipes { + .emotion-108 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + color: var(--chakra-colors-fg-muted); + } + + .emotion-108:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + color: var(--chakra-colors-fg-subtle); + } + + .emotion-108:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + color: var(--chakra-colors-fg-error); + } + + .emotion-108 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +.emotion-109 { + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; +} + +.emotion-110 { + min-width: 100%!important; + z-index: 2!important; + top: calc(100% + 5px)!important; +} + +@layer recipes { + .emotion-111 { + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + z-index: var(--chakra-z-index-dropdown); + border-radius: var(--chakra-radii-l2); + outline: 0; + max-height: var(--chakra-sizes-96); + overflow-y: auto; + box-shadow: var(--chakra-shadows-md); + padding: var(--chakra-spacing-1); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + } + + .emotion-111:is([open], [data-open], [data-state=open]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fast); + animation-duration: var(--chakra-durations-fast); + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=top] { + -webkit-animation-name: slide-from-bottom,fade-in; + animation-name: slide-from-bottom,fade-in; + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=bottom] { + -webkit-animation-name: slide-from-top,fade-in; + animation-name: slide-from-top,fade-in; + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=left] { + -webkit-animation-name: slide-from-right,fade-in; + animation-name: slide-from-right,fade-in; + } + + .emotion-111:is([open], [data-open], [data-state=open])[data-placement^=right] { + -webkit-animation-name: slide-from-left,fade-in; + animation-name: slide-from-left,fade-in; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fastest); + animation-duration: var(--chakra-durations-fastest); + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=top] { + -webkit-animation-name: slide-to-bottom,fade-out; + animation-name: slide-to-bottom,fade-out; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=bottom] { + -webkit-animation-name: slide-to-top,fade-out; + animation-name: slide-to-top,fade-out; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=left] { + -webkit-animation-name: slide-to-right,fade-out; + animation-name: slide-to-right,fade-out; + } + + .emotion-111:is([closed], [data-closed], [data-state=closed])[data-placement^=right] { + -webkit-animation-name: slide-to-left,fade-out; + animation-name: slide-to-left,fade-out; + } +} + +@layer recipes { + .emotion-112 { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-2); + cursor: var(--chakra-cursor-option); + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: start; + border-radius: var(--chakra-radii-l1); + padding-block: var(--chakra-spacing-1\\.5); + padding-inline: var(--chakra-spacing-2); + } + + .emotion-112[data-highlighted] { + --mix-background: color-mix(in srgb, var(--chakra-colors-bg-emphasized) 60%, transparent); + background: var(--mix-background, var(--chakra-colors-bg-emphasized)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-bg-emphasized)); + } + + .emotion-112:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + pointer-events: none; + opacity: 0.5; + } + + .emotion-112 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +@layer recipes { + .emotion-113 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +.emotion-132 { + margin-top: var(--chakra-spacing-3); +} + +
+
+
+
+
+
+ test +
+ +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ deepObjectOptional +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepObject +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema and formData 1`] = ` +@layer recipes { + .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + } + + .emotion-0>:not(style, [hidden])~:not(style, [hidden]) { + --space-y-reverse: 0; + margin-top: calc(var(--chakra-spacing-4) * calc(1 - var(--space-y-reverse))); + margin-bottom: calc(var(--chakra-spacing-4) * var(--space-y-reverse)); + } +} + +@layer recipes { + .emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + gap: var(--chakra-spacing-4); + } +} + +.emotion-2 { + margin-top: var(--chakra-spacing-1); + margin-bottom: var(--chakra-spacing-4); +} + +@layer recipes { + .emotion-3 { + font-family: var(--chakra-fonts-heading); + font-weight: var(--chakra-font-weights-semibold); + font-size: var(--chakra-font-sizes-xl); + line-height: 1.875rem; + } +} + +@layer recipes { + .emotion-4 { + display: block; + border-color: var(--chakra-colors-border); + --separator-thickness: 1px; + border-style: solid; + border-top-width: var(--separator-thickness); + } +} + +.emotion-5 { + display: grid; + gap: var(--chakra-spacing-4); + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-9 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +@layer recipes { + .emotion-11 { + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + justify-self: stretch; + -webkit-align-self: stretch; + -ms-flex-item-align: stretch; + align-self: stretch; + } +} + +.emotion-12 { + padding-inline: 0; + padding-block: 0; +} + +@layer recipes { + .emotion-12 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-8); + min-width: var(--chakra-sizes-8); + font-size: var(--chakra-font-sizes-xs); + padding-inline: var(--chakra-spacing-2\\.5); + gap: var(--chakra-spacing-1); + background: var(--chakra-colors-color-palette-subtle); + --bg-currentcolor: var(--chakra-colors-color-palette-subtle); + color: var(--chakra-colors-color-palette-fg); + } + + .emotion-12:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-12:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-12 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } + + .emotion-12:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + background: var(--chakra-colors-color-palette-muted); + --bg-currentcolor: var(--chakra-colors-color-palette-muted); + } + + @media (hover: hover) { + .emotion-12:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + background: var(--chakra-colors-color-palette-muted); + --bg-currentcolor: var(--chakra-colors-color-palette-muted); + } + } +} + +.emotion-12 :where(svg) { + font-size: 1.2em; +} + +.emotion-17 { + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-17 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-18 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: start; + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + font-weight: var(--chakra-font-weights-medium); + gap: var(--chakra-spacing-1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + .emotion-18:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + } +} + +@layer recipes { + .emotion-19 { + width: 100%; + min-width: var(--input-height); + outline: 0; + position: relative; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + text-align: start; + border-radius: var(--chakra-radii-l2); + height: var(--input-height); + --focus-color: var(--chakra-colors-color-palette-focus-ring); + --error-color: var(--chakra-colors-border-error); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + padding-inline: var(--chakra-spacing-3); + --input-height: var(--chakra-sizes-10); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + --focus-ring-color: var(--focus-color); + } + + .emotion-19:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-19:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + --focus-ring-color: var(--error-color); + border-color: var(--error-color); + } + + .emotion-19:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } +} + +.emotion-45 { + display: grid; +} + +.emotion-46 { + justify-self: flex-end; +} + +.emotion-47 { + margin-top: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-48 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-48:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-48:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-48 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-48:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-48:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-76 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + gap: 0.5rem; + padding-block: var(--chakra-spacing-1); +} + +.emotion-77 { + width: 100%; +} + +@layer recipes { + .emotion-82 { + color: var(--chakra-colors-fg-error); + line-height: 1; + } +} + +.emotion-84 { + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-84 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + gap: 0!important; + isolation: isolate; + position: relative; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + + .emotion-84 [data-group-item]:is(:focus-visible, [data-focus-visible]) { + z-index: 1; + } + + .emotion-84>*[data-first] { + border-start-end-radius: 0!important; + border-end-end-radius: 0!important; + -webkit-margin-end: -1px; + margin-inline-end: -1px; + } + + .emotion-84>*[data-between] { + border-radius: 0!important; + -webkit-margin-end: -1px; + margin-inline-end: -1px; + } + + .emotion-84>*[data-last] { + border-start-start-radius: 0!important; + border-end-start-radius: 0!important; + } +} + +.emotion-85 { + padding-inline: 0; + padding-block: 0; +} + +@layer recipes { + .emotion-85 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-85:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-85:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-85 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-85:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-85:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-85 :where(svg) { + font-size: 1.2em; +} + +.emotion-111 { + margin-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-111 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + min-width: 0; + word-wrap: break-word; + border-radius: var(--chakra-radii-l3); + color: var(--chakra-colors-fg); + text-align: start; + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + border-width: 1px; + border-color: var(--chakra-colors-border); + --card-padding: var(--chakra-spacing-6); + } +} + +.emotion-112 { + padding-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-112 { + padding: var(--card-padding); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-113 { + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-114 { + margin-bottom: var(--chakra-spacing-1); + position: relative; +} + +@layer recipes { + .emotion-114 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-116 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: var(--chakra-spacing-1\\.5); + width: var(--chakra-sizes-full); + --select-trigger-height: var(--chakra-sizes-10); + --select-trigger-padding-x: var(--chakra-spacing-3); + } +} + +@layer recipes { + .emotion-117 { + position: relative; + } +} + +@layer recipes { + .emotion-119 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + width: var(--chakra-sizes-full); + min-height: var(--select-trigger-height); + --input-height: var(--select-trigger-height); + padding-inline: var(--select-trigger-padding-x); + border-radius: var(--chakra-radii-l2); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: start; + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + } + + .emotion-119:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } + + .emotion-119:is(:placeholder-shown, [data-placeholder-shown]) { + --mix-color: color-mix(in srgb, var(--chakra-colors-fg-muted) 80%, transparent); + color: var(--mix-color, var(--chakra-colors-fg-muted)); + } + + .emotion-119:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-119:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + border-color: var(--chakra-colors-border-error); + } + + .emotion-119:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + border-color: var(--chakra-colors-border-emphasized); + } +} + +@layer recipes { + .emotion-120 { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-wrap: wrap; + max-width: 80%; + } +} + +@layer recipes { + .emotion-121 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-1); + position: absolute; + inset-inline-end: 0; + top: 0; + bottom: 0; + padding-inline: var(--select-trigger-padding-x); + pointer-events: none; + } +} + +@layer recipes { + .emotion-122 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + color: var(--chakra-colors-fg-muted); + } + + .emotion-122:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + color: var(--chakra-colors-fg-subtle); + } + + .emotion-122:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + color: var(--chakra-colors-fg-error); + } + + .emotion-122 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +.emotion-123 { + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; +} + +.emotion-124 { + min-width: 100%!important; + z-index: 2!important; + top: calc(100% + 5px)!important; +} + +@layer recipes { + .emotion-125 { + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + z-index: var(--chakra-z-index-dropdown); + border-radius: var(--chakra-radii-l2); + outline: 0; + max-height: var(--chakra-sizes-96); + overflow-y: auto; + box-shadow: var(--chakra-shadows-md); + padding: var(--chakra-spacing-1); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + } + + .emotion-125:is([open], [data-open], [data-state=open]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fast); + animation-duration: var(--chakra-durations-fast); + } + + .emotion-125:is([open], [data-open], [data-state=open])[data-placement^=top] { + -webkit-animation-name: slide-from-bottom,fade-in; + animation-name: slide-from-bottom,fade-in; + } + + .emotion-125:is([open], [data-open], [data-state=open])[data-placement^=bottom] { + -webkit-animation-name: slide-from-top,fade-in; + animation-name: slide-from-top,fade-in; + } + + .emotion-125:is([open], [data-open], [data-state=open])[data-placement^=left] { + -webkit-animation-name: slide-from-right,fade-in; + animation-name: slide-from-right,fade-in; + } + + .emotion-125:is([open], [data-open], [data-state=open])[data-placement^=right] { + -webkit-animation-name: slide-from-left,fade-in; + animation-name: slide-from-left,fade-in; + } + + .emotion-125:is([closed], [data-closed], [data-state=closed]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fastest); + animation-duration: var(--chakra-durations-fastest); + } + + .emotion-125:is([closed], [data-closed], [data-state=closed])[data-placement^=top] { + -webkit-animation-name: slide-to-bottom,fade-out; + animation-name: slide-to-bottom,fade-out; + } + + .emotion-125:is([closed], [data-closed], [data-state=closed])[data-placement^=bottom] { + -webkit-animation-name: slide-to-top,fade-out; + animation-name: slide-to-top,fade-out; + } + + .emotion-125:is([closed], [data-closed], [data-state=closed])[data-placement^=left] { + -webkit-animation-name: slide-to-right,fade-out; + animation-name: slide-to-right,fade-out; + } + + .emotion-125:is([closed], [data-closed], [data-state=closed])[data-placement^=right] { + -webkit-animation-name: slide-to-left,fade-out; + animation-name: slide-to-left,fade-out; + } +} + +@layer recipes { + .emotion-126 { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-2); + cursor: var(--chakra-cursor-option); + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: start; + border-radius: var(--chakra-radii-l1); + padding-block: var(--chakra-spacing-1\\.5); + padding-inline: var(--chakra-spacing-2); + } + + .emotion-126[data-highlighted] { + --mix-background: color-mix(in srgb, var(--chakra-colors-bg-emphasized) 60%, transparent); + background: var(--mix-background, var(--chakra-colors-bg-emphasized)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-bg-emphasized)); + } + + .emotion-126:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + pointer-events: none; + opacity: 0.5; + } + + .emotion-126 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +@layer recipes { + .emotion-127 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +.emotion-146 { + margin-top: var(--chakra-spacing-3); +} + +
+
+
+
+
+
+ test +
+ +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+ +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+ deepObjectOptional +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+ deepObject +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+ +
+ +
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema, readonly and formData 1`] = ` +@layer recipes { + .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + } + + .emotion-0>:not(style, [hidden])~:not(style, [hidden]) { + --space-y-reverse: 0; + margin-top: calc(var(--chakra-spacing-4) * calc(1 - var(--space-y-reverse))); + margin-bottom: calc(var(--chakra-spacing-4) * var(--space-y-reverse)); + } +} + +@layer recipes { + .emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + gap: var(--chakra-spacing-4); + } +} + +.emotion-2 { + margin-top: var(--chakra-spacing-1); + margin-bottom: var(--chakra-spacing-4); +} + +@layer recipes { + .emotion-3 { + font-family: var(--chakra-fonts-heading); + font-weight: var(--chakra-font-weights-semibold); + font-size: var(--chakra-font-sizes-xl); + line-height: 1.875rem; + } +} + +@layer recipes { + .emotion-4 { + display: block; + border-color: var(--chakra-colors-border); + --separator-thickness: 1px; + border-style: solid; + border-top-width: var(--separator-thickness); + } +} + +.emotion-5 { + display: grid; + gap: var(--chakra-spacing-4); + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-14 { + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-14 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-15 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: start; + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + font-weight: var(--chakra-font-weights-medium); + gap: var(--chakra-spacing-1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + .emotion-15:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + } +} + +@layer recipes { + .emotion-16 { + width: 100%; + min-width: var(--input-height); + outline: 0; + position: relative; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + text-align: start; + border-radius: var(--chakra-radii-l2); + height: var(--input-height); + --focus-color: var(--chakra-colors-color-palette-focus-ring); + --error-color: var(--chakra-colors-border-error); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + padding-inline: var(--chakra-spacing-3); + --input-height: var(--chakra-sizes-10); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + --focus-ring-color: var(--focus-color); + } + + .emotion-16:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-16:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + --focus-ring-color: var(--error-color); + border-color: var(--error-color); + } + + .emotion-16:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } +} + +.emotion-39 { + display: grid; +} + +.emotion-40 { + justify-self: flex-end; +} + +.emotion-41 { + margin-top: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-42 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-42:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-42:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-42 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-42:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-42:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-64 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: flex-end; + -webkit-box-align: flex-end; + -ms-flex-align: flex-end; + align-items: flex-end; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + gap: 0.5rem; + padding-block: var(--chakra-spacing-1); +} + +.emotion-65 { + width: 100%; +} + +@layer recipes { + .emotion-70 { + color: var(--chakra-colors-fg-error); + line-height: 1; + } +} + +.emotion-72 { + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: start; + -ms-flex-pack: start; + -webkit-justify-content: flex-start; + justify-content: flex-start; + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-72 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + gap: 0!important; + isolation: isolate; + position: relative; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + } + + .emotion-72 [data-group-item]:is(:focus-visible, [data-focus-visible]) { + z-index: 1; + } + + .emotion-72>*[data-first] { + border-start-end-radius: 0!important; + border-end-end-radius: 0!important; + -webkit-margin-end: -1px; + margin-inline-end: -1px; + } + + .emotion-72>*[data-between] { + border-radius: 0!important; + -webkit-margin-end: -1px; + margin-inline-end: -1px; + } + + .emotion-72>*[data-last] { + border-start-start-radius: 0!important; + border-end-start-radius: 0!important; + } +} + +.emotion-73 { + padding-inline: 0; + padding-block: 0; +} + +@layer recipes { + .emotion-73 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-73:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-73:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-73 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-73:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-73:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-73 :where(svg) { + font-size: 1.2em; +} + +.emotion-99 { + margin-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-99 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + min-width: 0; + word-wrap: break-word; + border-radius: var(--chakra-radii-l3); + color: var(--chakra-colors-fg); + text-align: start; + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + border-width: 1px; + border-color: var(--chakra-colors-border); + --card-padding: var(--chakra-spacing-6); + } +} + +.emotion-100 { + padding-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-100 { + padding: var(--card-padding); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-101 { + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-102 { + margin-bottom: var(--chakra-spacing-1); + position: relative; +} + +@layer recipes { + .emotion-102 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-104 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: var(--chakra-spacing-1\\.5); + width: var(--chakra-sizes-full); + --select-trigger-height: var(--chakra-sizes-10); + --select-trigger-padding-x: var(--chakra-spacing-3); + } +} + +@layer recipes { + .emotion-105 { + position: relative; + } +} + +@layer recipes { + .emotion-107 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + width: var(--chakra-sizes-full); + min-height: var(--select-trigger-height); + --input-height: var(--select-trigger-height); + padding-inline: var(--select-trigger-padding-x); + border-radius: var(--chakra-radii-l2); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: start; + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + } + + .emotion-107:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } + + .emotion-107:is(:placeholder-shown, [data-placeholder-shown]) { + --mix-color: color-mix(in srgb, var(--chakra-colors-fg-muted) 80%, transparent); + color: var(--mix-color, var(--chakra-colors-fg-muted)); + } + + .emotion-107:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-107:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + border-color: var(--chakra-colors-border-error); + } + + .emotion-107:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + border-color: var(--chakra-colors-border-emphasized); + } +} + +@layer recipes { + .emotion-108 { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-wrap: wrap; + max-width: 80%; + } +} + +@layer recipes { + .emotion-109 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-1); + position: absolute; + inset-inline-end: 0; + top: 0; + bottom: 0; + padding-inline: var(--select-trigger-padding-x); + pointer-events: none; + } +} + +@layer recipes { + .emotion-110 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + color: var(--chakra-colors-fg-muted); + } + + .emotion-110:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + color: var(--chakra-colors-fg-subtle); + } + + .emotion-110:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + color: var(--chakra-colors-fg-error); + } + + .emotion-110 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +.emotion-111 { + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; +} + +.emotion-112 { + min-width: 100%!important; + z-index: 2!important; + top: calc(100% + 5px)!important; +} + +@layer recipes { + .emotion-113 { + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + z-index: var(--chakra-z-index-dropdown); + border-radius: var(--chakra-radii-l2); + outline: 0; + max-height: var(--chakra-sizes-96); + overflow-y: auto; + box-shadow: var(--chakra-shadows-md); + padding: var(--chakra-spacing-1); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + } + + .emotion-113:is([open], [data-open], [data-state=open]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fast); + animation-duration: var(--chakra-durations-fast); + } + + .emotion-113:is([open], [data-open], [data-state=open])[data-placement^=top] { + -webkit-animation-name: slide-from-bottom,fade-in; + animation-name: slide-from-bottom,fade-in; + } + + .emotion-113:is([open], [data-open], [data-state=open])[data-placement^=bottom] { + -webkit-animation-name: slide-from-top,fade-in; + animation-name: slide-from-top,fade-in; + } + + .emotion-113:is([open], [data-open], [data-state=open])[data-placement^=left] { + -webkit-animation-name: slide-from-right,fade-in; + animation-name: slide-from-right,fade-in; + } + + .emotion-113:is([open], [data-open], [data-state=open])[data-placement^=right] { + -webkit-animation-name: slide-from-left,fade-in; + animation-name: slide-from-left,fade-in; + } + + .emotion-113:is([closed], [data-closed], [data-state=closed]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fastest); + animation-duration: var(--chakra-durations-fastest); + } + + .emotion-113:is([closed], [data-closed], [data-state=closed])[data-placement^=top] { + -webkit-animation-name: slide-to-bottom,fade-out; + animation-name: slide-to-bottom,fade-out; + } + + .emotion-113:is([closed], [data-closed], [data-state=closed])[data-placement^=bottom] { + -webkit-animation-name: slide-to-top,fade-out; + animation-name: slide-to-top,fade-out; + } + + .emotion-113:is([closed], [data-closed], [data-state=closed])[data-placement^=left] { + -webkit-animation-name: slide-to-right,fade-out; + animation-name: slide-to-right,fade-out; + } + + .emotion-113:is([closed], [data-closed], [data-state=closed])[data-placement^=right] { + -webkit-animation-name: slide-to-left,fade-out; + animation-name: slide-to-left,fade-out; + } +} + +@layer recipes { + .emotion-114 { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-2); + cursor: var(--chakra-cursor-option); + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: start; + border-radius: var(--chakra-radii-l1); + padding-block: var(--chakra-spacing-1\\.5); + padding-inline: var(--chakra-spacing-2); + } + + .emotion-114[data-highlighted] { + --mix-background: color-mix(in srgb, var(--chakra-colors-bg-emphasized) 60%, transparent); + background: var(--mix-background, var(--chakra-colors-bg-emphasized)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-bg-emphasized)); + } + + .emotion-114:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + pointer-events: none; + opacity: 0.5; + } + + .emotion-114 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +@layer recipes { + .emotion-115 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +.emotion-134 { + margin-top: var(--chakra-spacing-3); +} + +
+
+
+
+
+
+ test +
+ +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+ deepObjectOptional +
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+ deepObject +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+ +
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema and no formData 1`] = ` +@layer recipes { + .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + } + + .emotion-0>:not(style, [hidden])~:not(style, [hidden]) { + --space-y-reverse: 0; + margin-top: calc(var(--chakra-spacing-4) * calc(1 - var(--space-y-reverse))); + margin-bottom: calc(var(--chakra-spacing-4) * var(--space-y-reverse)); + } +} + +@layer recipes { + .emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + gap: var(--chakra-spacing-4); + } +} + +.emotion-2 { + margin-top: var(--chakra-spacing-1); + margin-bottom: var(--chakra-spacing-4); +} + +@layer recipes { + .emotion-3 { + font-family: var(--chakra-fonts-heading); + font-weight: var(--chakra-font-weights-semibold); + font-size: var(--chakra-font-sizes-xl); + line-height: 1.875rem; + } +} + +@layer recipes { + .emotion-4 { + display: block; + border-color: var(--chakra-colors-border); + --separator-thickness: 1px; + border-style: solid; + border-top-width: var(--separator-thickness); + } +} + +.emotion-5 { + display: grid; + gap: var(--chakra-spacing-4); + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-9 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +@layer recipes { + .emotion-11 { + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + justify-self: stretch; + -webkit-align-self: stretch; + -ms-flex-item-align: stretch; + align-self: stretch; + } +} + +.emotion-12 { + padding-inline: 0; + padding-block: 0; +} + +@layer recipes { + .emotion-12 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-8); + min-width: var(--chakra-sizes-8); + font-size: var(--chakra-font-sizes-xs); + padding-inline: var(--chakra-spacing-2\\.5); + gap: var(--chakra-spacing-1); + background: var(--chakra-colors-color-palette-subtle); + --bg-currentcolor: var(--chakra-colors-color-palette-subtle); + color: var(--chakra-colors-color-palette-fg); + } + + .emotion-12:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-12:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-12 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } + + .emotion-12:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + background: var(--chakra-colors-color-palette-muted); + --bg-currentcolor: var(--chakra-colors-color-palette-muted); + } + + @media (hover: hover) { + .emotion-12:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + background: var(--chakra-colors-color-palette-muted); + --bg-currentcolor: var(--chakra-colors-color-palette-muted); + } + } +} + +.emotion-12 :where(svg) { + font-size: 1.2em; +} + +.emotion-23 { + display: grid; +} + +.emotion-32 { + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-32 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-33 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: start; + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + font-weight: var(--chakra-font-weights-medium); + gap: var(--chakra-spacing-1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + .emotion-33:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + } +} + +@layer recipes { + .emotion-34 { + width: 100%; + min-width: var(--input-height); + outline: 0; + position: relative; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + text-align: start; + border-radius: var(--chakra-radii-l2); + height: var(--input-height); + --focus-color: var(--chakra-colors-color-palette-focus-ring); + --error-color: var(--chakra-colors-border-error); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + padding-inline: var(--chakra-spacing-3); + --input-height: var(--chakra-sizes-10); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + --focus-ring-color: var(--focus-color); + } + + .emotion-34:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-34:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + --focus-ring-color: var(--error-color); + border-color: var(--error-color); + } + + .emotion-34:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } +} + +.emotion-41 { + justify-self: flex-end; +} + +.emotion-42 { + margin-top: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-43 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-43:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-43:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-43 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-43:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-43:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-46 { + margin-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-46 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + min-width: 0; + word-wrap: break-word; + border-radius: var(--chakra-radii-l3); + color: var(--chakra-colors-fg); + text-align: start; + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + border-width: 1px; + border-color: var(--chakra-colors-border); + --card-padding: var(--chakra-spacing-6); + } +} + +.emotion-47 { + padding-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-47 { + padding: var(--card-padding); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-48 { + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-49 { + margin-bottom: var(--chakra-spacing-1); + position: relative; +} + +@layer recipes { + .emotion-49 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-51 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: var(--chakra-spacing-1\\.5); + width: var(--chakra-sizes-full); + --select-trigger-height: var(--chakra-sizes-10); + --select-trigger-padding-x: var(--chakra-spacing-3); + } +} + +@layer recipes { + .emotion-52 { + position: relative; + } +} + +@layer recipes { + .emotion-54 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + width: var(--chakra-sizes-full); + min-height: var(--select-trigger-height); + --input-height: var(--select-trigger-height); + padding-inline: var(--select-trigger-padding-x); + border-radius: var(--chakra-radii-l2); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: start; + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + } + + .emotion-54:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } + + .emotion-54:is(:placeholder-shown, [data-placeholder-shown]) { + --mix-color: color-mix(in srgb, var(--chakra-colors-fg-muted) 80%, transparent); + color: var(--mix-color, var(--chakra-colors-fg-muted)); + } + + .emotion-54:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-54:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + border-color: var(--chakra-colors-border-error); + } + + .emotion-54:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + border-color: var(--chakra-colors-border-emphasized); + } +} + +@layer recipes { + .emotion-55 { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-wrap: wrap; + max-width: 80%; + } +} + +@layer recipes { + .emotion-56 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-1); + position: absolute; + inset-inline-end: 0; + top: 0; + bottom: 0; + padding-inline: var(--select-trigger-padding-x); + pointer-events: none; + } +} + +@layer recipes { + .emotion-57 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + color: var(--chakra-colors-fg-muted); + } + + .emotion-57:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + color: var(--chakra-colors-fg-subtle); + } + + .emotion-57:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + color: var(--chakra-colors-fg-error); + } + + .emotion-57 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +.emotion-58 { + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; +} + +.emotion-59 { + min-width: 100%!important; + z-index: 2!important; + top: calc(100% + 5px)!important; +} + +@layer recipes { + .emotion-60 { + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + z-index: var(--chakra-z-index-dropdown); + border-radius: var(--chakra-radii-l2); + outline: 0; + max-height: var(--chakra-sizes-96); + overflow-y: auto; + box-shadow: var(--chakra-shadows-md); + padding: var(--chakra-spacing-1); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + } + + .emotion-60:is([open], [data-open], [data-state=open]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fast); + animation-duration: var(--chakra-durations-fast); + } + + .emotion-60:is([open], [data-open], [data-state=open])[data-placement^=top] { + -webkit-animation-name: slide-from-bottom,fade-in; + animation-name: slide-from-bottom,fade-in; + } + + .emotion-60:is([open], [data-open], [data-state=open])[data-placement^=bottom] { + -webkit-animation-name: slide-from-top,fade-in; + animation-name: slide-from-top,fade-in; + } + + .emotion-60:is([open], [data-open], [data-state=open])[data-placement^=left] { + -webkit-animation-name: slide-from-right,fade-in; + animation-name: slide-from-right,fade-in; + } + + .emotion-60:is([open], [data-open], [data-state=open])[data-placement^=right] { + -webkit-animation-name: slide-from-left,fade-in; + animation-name: slide-from-left,fade-in; + } + + .emotion-60:is([closed], [data-closed], [data-state=closed]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fastest); + animation-duration: var(--chakra-durations-fastest); + } + + .emotion-60:is([closed], [data-closed], [data-state=closed])[data-placement^=top] { + -webkit-animation-name: slide-to-bottom,fade-out; + animation-name: slide-to-bottom,fade-out; + } + + .emotion-60:is([closed], [data-closed], [data-state=closed])[data-placement^=bottom] { + -webkit-animation-name: slide-to-top,fade-out; + animation-name: slide-to-top,fade-out; + } + + .emotion-60:is([closed], [data-closed], [data-state=closed])[data-placement^=left] { + -webkit-animation-name: slide-to-right,fade-out; + animation-name: slide-to-right,fade-out; + } + + .emotion-60:is([closed], [data-closed], [data-state=closed])[data-placement^=right] { + -webkit-animation-name: slide-to-left,fade-out; + animation-name: slide-to-left,fade-out; + } +} + +@layer recipes { + .emotion-61 { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-2); + cursor: var(--chakra-cursor-option); + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: start; + border-radius: var(--chakra-radii-l1); + padding-block: var(--chakra-spacing-1\\.5); + padding-inline: var(--chakra-spacing-2); + } + + .emotion-61[data-highlighted] { + --mix-background: color-mix(in srgb, var(--chakra-colors-bg-emphasized) 60%, transparent); + background: var(--mix-background, var(--chakra-colors-bg-emphasized)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-bg-emphasized)); + } + + .emotion-61:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + pointer-events: none; + opacity: 0.5; + } + + .emotion-61 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +@layer recipes { + .emotion-62 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +.emotion-81 { + margin-top: var(--chakra-spacing-3); +} + +
+
+
+
+
+
+ test +
+ +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+ +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema, disabled and no formData 1`] = ` +@layer recipes { + .emotion-0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + } + + .emotion-0>:not(style, [hidden])~:not(style, [hidden]) { + --space-y-reverse: 0; + margin-top: calc(var(--chakra-spacing-4) * calc(1 - var(--space-y-reverse))); + margin-bottom: calc(var(--chakra-spacing-4) * var(--space-y-reverse)); + } +} + +@layer recipes { + .emotion-1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + width: var(--chakra-sizes-full); + gap: var(--chakra-spacing-4); + } +} + +.emotion-2 { + margin-top: var(--chakra-spacing-1); + margin-bottom: var(--chakra-spacing-4); +} + +@layer recipes { + .emotion-3 { + font-family: var(--chakra-fonts-heading); + font-weight: var(--chakra-font-weights-semibold); + font-size: var(--chakra-font-sizes-xl); + line-height: 1.875rem; + } +} + +@layer recipes { + .emotion-4 { + display: block; + border-color: var(--chakra-colors-border); + --separator-thickness: 1px; + border-style: solid; + border-top-width: var(--separator-thickness); + } +} + +.emotion-5 { + display: grid; + gap: var(--chakra-spacing-4); + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-17 { + display: grid; +} + +.emotion-26 { + margin-bottom: var(--chakra-spacing-1); +} + +@layer recipes { + .emotion-26 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-27 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: start; + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + font-weight: var(--chakra-font-weights-medium); + gap: var(--chakra-spacing-1); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + + .emotion-27:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + } +} + +@layer recipes { + .emotion-28 { + width: 100%; + min-width: var(--input-height); + outline: 0; + position: relative; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + text-align: start; + border-radius: var(--chakra-radii-l2); + height: var(--input-height); + --focus-color: var(--chakra-colors-color-palette-focus-ring); + --error-color: var(--chakra-colors-border-error); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + padding-inline: var(--chakra-spacing-3); + --input-height: var(--chakra-sizes-10); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + --focus-ring-color: var(--focus-color); + } + + .emotion-28:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-28:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + --focus-ring-color: var(--error-color); + border-color: var(--error-color); + } + + .emotion-28:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } +} + +.emotion-35 { + justify-self: flex-end; +} + +.emotion-36 { + margin-top: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-37 { + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; + border-radius: var(--chakra-radii-l2); + white-space: nowrap; + vertical-align: middle; + border-width: 1px; + border-color: var(--chakra-colors-transparent); + cursor: var(--chakra-cursor-button); + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + outline: 0; + line-height: 1.25rem; + isolation: isolate; + font-weight: var(--chakra-font-weights-medium); + transition-property: background-color,border-color,color,fill,stroke,opacity,box-shadow,translate,transform; + transition-duration: var(--chakra-durations-moderate); + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + height: var(--chakra-sizes-10); + min-width: var(--chakra-sizes-10); + font-size: var(--chakra-font-sizes-sm); + padding-inline: var(--chakra-spacing-4); + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-color-palette-solid); + --bg-currentcolor: var(--chakra-colors-color-palette-solid); + color: var(--chakra-colors-color-palette-contrast); + } + + .emotion-37:is(:focus-visible, [data-focus-visible]) { + outline-width: var(--focus-ring-width, 2px); + outline-offset: var(--focus-ring-offset, 2px); + outline-style: var(--focus-ring-style, solid); + outline-color: var(--focus-ring-color); + } + + .emotion-37:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-37 :where(svg) { + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + width: var(--chakra-sizes-5); + height: var(--chakra-sizes-5); + } + + .emotion-37:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + + @media (hover: hover) { + .emotion-37:is(:hover, [data-hover]):not(:disabled, [data-disabled]) { + --mix-background: color-mix(in srgb, var(--chakra-colors-color-palette-solid) 90%, transparent); + background: var(--mix-background, var(--chakra-colors-color-palette-solid)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-color-palette-solid)); + } + } +} + +.emotion-40 { + margin-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-40 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + position: relative; + min-width: 0; + word-wrap: break-word; + border-radius: var(--chakra-radii-l3); + color: var(--chakra-colors-fg); + text-align: start; + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + border-width: 1px; + border-color: var(--chakra-colors-border); + --card-padding: var(--chakra-spacing-6); + } +} + +.emotion-41 { + padding-bottom: var(--chakra-spacing-2); +} + +@layer recipes { + .emotion-41 { + padding: var(--card-padding); + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} + +.emotion-42 { + margin-bottom: var(--chakra-spacing-4); +} + +.emotion-43 { + margin-bottom: var(--chakra-spacing-1); + position: relative; +} + +@layer recipes { + .emotion-43 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + width: 100%; + position: relative; + gap: var(--chakra-spacing-1\\.5); + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-align-items: flex-start; + -webkit-box-align: flex-start; + -ms-flex-align: flex-start; + align-items: flex-start; + } +} + +@layer recipes { + .emotion-45 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + gap: var(--chakra-spacing-1\\.5); + width: var(--chakra-sizes-full); + --select-trigger-height: var(--chakra-sizes-10); + --select-trigger-padding-x: var(--chakra-spacing-3); + } +} + +@layer recipes { + .emotion-46 { + position: relative; + } +} + +@layer recipes { + .emotion-48 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + width: var(--chakra-sizes-full); + min-height: var(--select-trigger-height); + --input-height: var(--select-trigger-height); + padding-inline: var(--select-trigger-padding-x); + border-radius: var(--chakra-radii-l2); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-align: start; + --focus-ring-color: var(--chakra-colors-color-palette-focus-ring); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + gap: var(--chakra-spacing-2); + background: var(--chakra-colors-transparent); + --bg-currentcolor: var(--chakra-colors-transparent); + border-width: 1px; + border-color: var(--chakra-colors-border); + } + + .emotion-48:is(:focus-visible, [data-focus-visible]) { + outline-offset: 0px; + outline-width: var(--focus-ring-width, 1px); + outline-color: var(--focus-ring-color); + outline-style: var(--focus-ring-style, solid); + border-color: var(--focus-ring-color); + } + + .emotion-48:is(:placeholder-shown, [data-placeholder-shown]) { + --mix-color: color-mix(in srgb, var(--chakra-colors-fg-muted) 80%, transparent); + color: var(--mix-color, var(--chakra-colors-fg-muted)); + } + + .emotion-48:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + opacity: 0.5; + cursor: not-allowed; + } + + .emotion-48:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + border-color: var(--chakra-colors-border-error); + } + + .emotion-48:is([aria-expanded=true], [data-expanded], [data-state=expanded]) { + border-color: var(--chakra-colors-border-emphasized); + } +} + +@layer recipes { + .emotion-49 { + overflow: hidden; + display: -webkit-box; + -webkit-line-clamp: 1; + -webkit-box-orient: vertical; + text-wrap: wrap; + max-width: 80%; + } +} + +@layer recipes { + .emotion-50 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-1); + position: absolute; + inset-inline-end: 0; + top: 0; + bottom: 0; + padding-inline: var(--select-trigger-padding-x); + pointer-events: none; + } +} + +@layer recipes { + .emotion-51 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + color: var(--chakra-colors-fg-muted); + } + + .emotion-51:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + color: var(--chakra-colors-fg-subtle); + } + + .emotion-51:is([data-invalid], [aria-invalid=true], [data-state=invalid]) { + color: var(--chakra-colors-fg-error); + } + + .emotion-51 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +.emotion-52 { + fill: none; + stroke: currentColor; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; +} + +.emotion-53 { + min-width: 100%!important; + z-index: 2!important; + top: calc(100% + 5px)!important; +} + +@layer recipes { + .emotion-54 { + background: var(--chakra-colors-bg-panel); + --bg-currentcolor: var(--chakra-colors-bg-panel); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + z-index: var(--chakra-z-index-dropdown); + border-radius: var(--chakra-radii-l2); + outline: 0; + max-height: var(--chakra-sizes-96); + overflow-y: auto; + box-shadow: var(--chakra-shadows-md); + padding: var(--chakra-spacing-1); + font-size: var(--chakra-font-sizes-sm); + line-height: 1.25rem; + } + + .emotion-54:is([open], [data-open], [data-state=open]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fast); + animation-duration: var(--chakra-durations-fast); + } + + .emotion-54:is([open], [data-open], [data-state=open])[data-placement^=top] { + -webkit-animation-name: slide-from-bottom,fade-in; + animation-name: slide-from-bottom,fade-in; + } + + .emotion-54:is([open], [data-open], [data-state=open])[data-placement^=bottom] { + -webkit-animation-name: slide-from-top,fade-in; + animation-name: slide-from-top,fade-in; + } + + .emotion-54:is([open], [data-open], [data-state=open])[data-placement^=left] { + -webkit-animation-name: slide-from-right,fade-in; + animation-name: slide-from-right,fade-in; + } + + .emotion-54:is([open], [data-open], [data-state=open])[data-placement^=right] { + -webkit-animation-name: slide-from-left,fade-in; + animation-name: slide-from-left,fade-in; + } + + .emotion-54:is([closed], [data-closed], [data-state=closed]) { + transform-origin: var(--transform-origin); + -webkit-animation-duration: var(--chakra-durations-fastest); + animation-duration: var(--chakra-durations-fastest); + } + + .emotion-54:is([closed], [data-closed], [data-state=closed])[data-placement^=top] { + -webkit-animation-name: slide-to-bottom,fade-out; + animation-name: slide-to-bottom,fade-out; + } + + .emotion-54:is([closed], [data-closed], [data-state=closed])[data-placement^=bottom] { + -webkit-animation-name: slide-to-top,fade-out; + animation-name: slide-to-top,fade-out; + } + + .emotion-54:is([closed], [data-closed], [data-state=closed])[data-placement^=left] { + -webkit-animation-name: slide-to-right,fade-out; + animation-name: slide-to-right,fade-out; + } + + .emotion-54:is([closed], [data-closed], [data-state=closed])[data-placement^=right] { + -webkit-animation-name: slide-to-left,fade-out; + animation-name: slide-to-left,fade-out; + } +} + +@layer recipes { + .emotion-55 { + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + gap: var(--chakra-spacing-2); + cursor: var(--chakra-cursor-option); + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + text-align: start; + border-radius: var(--chakra-radii-l1); + padding-block: var(--chakra-spacing-1\\.5); + padding-inline: var(--chakra-spacing-2); + } + + .emotion-55[data-highlighted] { + --mix-background: color-mix(in srgb, var(--chakra-colors-bg-emphasized) 60%, transparent); + background: var(--mix-background, var(--chakra-colors-bg-emphasized)); + --bg-currentcolor: var(--mix-background, var(--chakra-colors-bg-emphasized)); + } + + .emotion-55:is(:disabled, [disabled], [data-disabled], [aria-disabled=true]) { + pointer-events: none; + opacity: 0.5; + } + + .emotion-55 :where(svg) { + width: var(--chakra-sizes-4); + height: var(--chakra-sizes-4); + } +} + +@layer recipes { + .emotion-56 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } +} + +.emotion-75 { + margin-top: var(--chakra-spacing-3); +} + +
+
+
+
+
+
+ test +
+ +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+ +
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +
+
+ +
+
+ + + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+ +
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+`; + exports[`single fields password field 1`] = ` @layer recipes { .emotion-0 { @@ -16309,7 +27227,7 @@ exports[`single fields title field 1`] = ` .emotion-5 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } diff --git a/packages/chakra-ui/test/__snapshots__/Object.test.tsx.snap b/packages/chakra-ui/test/__snapshots__/Object.test.tsx.snap index fa24d6909b..348842f1a1 100644 --- a/packages/chakra-ui/test/__snapshots__/Object.test.tsx.snap +++ b/packages/chakra-ui/test/__snapshots__/Object.test.tsx.snap @@ -36,7 +36,7 @@ exports[`object fields additionalProperties 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -626,7 +626,7 @@ exports[`object fields object 1`] = ` .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -994,7 +994,7 @@ exports[`object fields show add button and fields if additionalProperties is tru .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -6159,7 +6159,7 @@ exports[`object fields with title and description with global label off addition .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -6740,7 +6740,7 @@ exports[`object fields with title and description with global label off object 1 .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } @@ -7064,7 +7064,7 @@ exports[`object fields with title and description with global label off show add .emotion-2 { display: grid; - gap: var(--chakra-spacing-6); + gap: var(--chakra-spacing-4); margin-bottom: var(--chakra-spacing-4); } diff --git a/packages/core/src/components/Form.tsx b/packages/core/src/components/Form.tsx index e2966e0ae0..037493f951 100644 --- a/packages/core/src/components/Form.tsx +++ b/packages/core/src/components/Form.tsx @@ -216,7 +216,6 @@ export interface FormProps; // Private /** diff --git a/packages/core/src/components/fields/ArrayField.tsx b/packages/core/src/components/fields/ArrayField.tsx index 4f7bf4fb24..9a025a4d2a 100644 --- a/packages/core/src/components/fields/ArrayField.tsx +++ b/packages/core/src/components/fields/ArrayField.tsx @@ -6,7 +6,9 @@ import { isFixedItems, allowAdditionalItems, isCustomWidget, + isFormDataAvailable, optionsList, + shouldRenderOptionalField, toFieldPathId, ArrayFieldTemplateProps, ErrorSchema, @@ -47,7 +49,7 @@ function generateRowId() { * @param formData - The data for the form * @returns - The `formData` converted into a `KeyedFormDataType` element */ -function generateKeyedFormData(formData: T[]): KeyedFormDataType[] { +function generateKeyedFormData(formData?: T[]): KeyedFormDataType[] { return !Array.isArray(formData) ? [] : formData.map((item) => { @@ -83,7 +85,7 @@ class ArrayField) { super(props); - const { formData = [] } = props; + const { formData } = props; const keyedFormData = generateKeyedFormData(formData); this.state = { keyedFormData, @@ -511,15 +513,21 @@ class ArrayField(uiSchema); const _schemaItems: S = isObject(schema.items) ? (schema.items as S) : ({} as S); const itemsSchema: S = schemaUtils.retrieveSchema(_schemaItems); const formData = keyedToPlainFormData(this.state.keyedFormData); - const canAdd = this.canAddItem(formData); + const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema); + const hasFormData = isFormDataAvailable(this.props.formData); + const canAdd = this.canAddItem(formData) && (!renderOptionalField || hasFormData); + const actualFormData = hasFormData ? keyedFormData : []; + const extraClass = renderOptionalField ? ' rjsf-optional-array-field' : ''; + const optionalDataControl = renderOptionalField ? : undefined; const arrayProps: ArrayFieldTemplateProps = { canAdd, - items: keyedFormData.map((keyedItem, index) => { + items: actualFormData.map((keyedItem, index) => { const { key, item } = keyedItem; // While we are actually dealing with a single item of type T, the types require a T[], so cast const itemCast = item as unknown as T[]; @@ -550,7 +558,7 @@ class ArrayField('ArrayFieldTemplate', registry, uiOptions); @@ -726,7 +735,7 @@ class ArrayField(uiSchema); - const { schemaUtils, formContext, globalFormOptions } = registry; + const { schemaUtils, fields, formContext, globalFormOptions } = registry; + const { OptionalDataControlsField } = fields; + const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema); + const hasFormData = isFormDataAvailable(formData); const _schemaItems: S[] = isObject(schema.items) ? (schema.items as S[]) : ([] as S[]); const itemSchemas = _schemaItems.map((item: S, index: number) => - schemaUtils.retrieveSchema(item, formData[index] as unknown as T[]), + schemaUtils.retrieveSchema(item, items[index] as unknown as T[]), ); const additionalSchema = isObject(schema.additionalItems) ? schemaUtils.retrieveSchema(schema.additionalItems as S, formData) : null; - if (!items || items.length < itemSchemas.length) { + if (items.length < itemSchemas.length) { // to make sure at least all fixed items are generated - items = items || []; items = items.concat(new Array(itemSchemas.length - items.length)); } + const actualFormData = hasFormData ? keyedFormData : []; + const extraClass = renderOptionalField ? ' rjsf-optional-array-field' : ''; + const optionalDataControl = renderOptionalField ? : undefined; // These are the props passed into the render function - const canAdd = this.canAddItem(items) && !!additionalSchema; + const canAdd = this.canAddItem(items) && !!additionalSchema && (!renderOptionalField || hasFormData); const arrayProps: ArrayFieldTemplateProps = { canAdd, - className: 'rjsf-field rjsf-field-array rjsf-field-array-fixed-items', + className: `rjsf-field rjsf-field-array rjsf-field-array-fixed-items${extraClass}`, disabled, fieldPathId, formData, - items: keyedFormData.map((keyedItem, index) => { + items: actualFormData.map((keyedItem, index) => { const { key, item } = keyedItem; // While we are actually dealing with a single item of type T, the types require a T[], so cast const itemCast = item as unknown as T[]; @@ -823,6 +837,7 @@ class ArrayField('ArrayFieldTemplate', registry, uiOptions); diff --git a/packages/core/src/components/fields/ObjectField.tsx b/packages/core/src/components/fields/ObjectField.tsx index 9a61cd5a9e..e27f163abf 100644 --- a/packages/core/src/components/fields/ObjectField.tsx +++ b/packages/core/src/components/fields/ObjectField.tsx @@ -3,6 +3,7 @@ import { getTemplate, getUiOptions, orderProperties, + shouldRenderOptionalField, toFieldPathId, ErrorSchema, FieldPathList, @@ -17,6 +18,7 @@ import { REF_KEY, ANY_OF_KEY, ONE_OF_KEY, + isFormDataAvailable, } from '@rjsf/utils'; import Markdown from 'markdown-to-jsx'; import get from 'lodash/get'; @@ -241,31 +243,38 @@ class ObjectField(uiSchema, globalUiOptions); const { properties: schemaProperties = {} } = schema; const templateTitle = uiOptions.title ?? schema.title ?? title ?? name; const description = uiOptions.description ?? schema.description; - let orderedProperties: string[]; - try { - const properties = Object.keys(schemaProperties); - orderedProperties = orderProperties(properties, uiOptions.order); - } catch (err) { - return ( -
-

- - {translateString(TranslatableString.InvalidObjectField, [name || 'root', (err as Error).message])} - -

-
{JSON.stringify(schema)}
-
- ); + const renderOptionalField = shouldRenderOptionalField(registry, schema, required, uiSchema); + const hasFormData = isFormDataAvailable(formData); + let orderedProperties: string[] = []; + if (!renderOptionalField || hasFormData) { + try { + const properties = Object.keys(schemaProperties); + orderedProperties = orderProperties(properties, uiOptions.order); + } catch (err) { + return ( +
+

+ + {translateString(TranslatableString.InvalidObjectField, [name || 'root', (err as Error).message])} + +

+
{JSON.stringify(schema)}
+
+ ); + } } const Template = getTemplate<'ObjectFieldTemplate', T, S, F>('ObjectFieldTemplate', registry, uiOptions); + const optionalDataControl = renderOptionalField ? ( + + ) : undefined; const templateProps = { // getDisplayLabel() always returns false for object types, so just check the `uiOptions.label` @@ -318,6 +327,8 @@ class ObjectField; } diff --git a/packages/core/src/components/fields/OptionalDataControlsField.tsx b/packages/core/src/components/fields/OptionalDataControlsField.tsx new file mode 100644 index 0000000000..7580e27bd3 --- /dev/null +++ b/packages/core/src/components/fields/OptionalDataControlsField.tsx @@ -0,0 +1,84 @@ +import { + FieldProps, + FormContextType, + getSchemaType, + getTemplate, + getUiOptions, + isFormDataAvailable, + optionalControlsId, + OptionalDataControlsTemplateProps, + RJSFSchema, + StrictRJSFSchema, + TranslatableString, +} from '@rjsf/utils'; + +/** The `OptionalDataControlsField` component is used to render the optional data controls for the field associated + * with the given props. + * + * @param props - The `FieldProps` for this template + */ +export default function OptionalDataControlsField< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: FieldProps) { + const { + schema, + uiSchema = {}, + formData, + disabled = false, + readonly = false, + onChange, + errorSchema, + fieldPathId, + registry, + } = props; + + const { globalUiOptions = {}, schemaUtils, translateString } = registry; + const uiOptions = getUiOptions(uiSchema, globalUiOptions); + const OptionalDataControlsTemplate = getTemplate<'OptionalDataControlsTemplate', T, S, F>( + 'OptionalDataControlsTemplate', + registry, + uiOptions, + ); + const hasFormData = isFormDataAvailable(formData); + let id: string; + let label: string | undefined; + let onAddClick: OptionalDataControlsTemplateProps['onAddClick']; + let onRemoveClick: OptionalDataControlsTemplateProps['onRemoveClick']; + if (disabled || readonly) { + id = optionalControlsId(fieldPathId, 'Msg'); + label = hasFormData ? undefined : translateString(TranslatableString.OptionalObjectEmptyMsg); + } else { + const labelEnum = hasFormData ? TranslatableString.OptionalObjectRemove : TranslatableString.OptionalObjectAdd; + label = translateString(labelEnum); + if (hasFormData) { + id = optionalControlsId(fieldPathId, 'Remove'); + onRemoveClick = () => onChange(undefined as T, fieldPathId.path, errorSchema); + } else { + id = optionalControlsId(fieldPathId, 'Add'); + onAddClick = () => { + // If it has form data, store an empty object, otherwise get the default form state and use it + let newFormData: unknown = schemaUtils.getDefaultFormState(schema, formData, 'excludeObjectChildren'); + if (newFormData === undefined) { + // If new form data ended up being undefined, and we have pushed the add button we need to actually add data + newFormData = getSchemaType(schema) === 'array' ? [] : {}; + } + onChange(newFormData as T, fieldPathId.path, errorSchema); + }; + } + } + return ( + label && ( + + ) + ); +} diff --git a/packages/core/src/components/fields/index.ts b/packages/core/src/components/fields/index.ts index 2f3d4c7b4d..a1c0ee5f29 100644 --- a/packages/core/src/components/fields/index.ts +++ b/packages/core/src/components/fields/index.ts @@ -8,6 +8,7 @@ import LayoutMultiSchemaField from './LayoutMultiSchemaField'; import MultiSchemaField from './MultiSchemaField'; import NumberField from './NumberField'; import ObjectField from './ObjectField'; +import OptionalDataControlsField from './OptionalDataControlsField'; import SchemaField from './SchemaField'; import StringField from './StringField'; import NullField from './NullField'; @@ -28,6 +29,7 @@ function fields< NumberField, ObjectField, OneOfField: MultiSchemaField, + OptionalDataControlsField, SchemaField, StringField, NullField, diff --git a/packages/core/src/components/templates/ArrayFieldTemplate.tsx b/packages/core/src/components/templates/ArrayFieldTemplate.tsx index 033e2c3fc3..86c3876c24 100644 --- a/packages/core/src/components/templates/ArrayFieldTemplate.tsx +++ b/packages/core/src/components/templates/ArrayFieldTemplate.tsx @@ -25,6 +25,7 @@ export default function ArrayFieldTemplate< fieldPathId, uiSchema, items, + optionalDataControl, onAddClick, readonly, registry, @@ -49,6 +50,7 @@ export default function ArrayFieldTemplate< uiOptions, ); // Button templates are not overridden in the uiSchema + const showOptionalDataControlInTitle = !readonly && !disabled; const { ButtonTemplates: { AddButton }, } = registry.templates; @@ -61,6 +63,7 @@ export default function ArrayFieldTemplate< schema={schema} uiSchema={uiSchema} registry={registry} + optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined} /> + {!showOptionalDataControlInTitle ? optionalDataControl : undefined}
{items && items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( diff --git a/packages/core/src/components/templates/ArrayFieldTitleTemplate.tsx b/packages/core/src/components/templates/ArrayFieldTitleTemplate.tsx index 85d68c3d27..5542af12e1 100644 --- a/packages/core/src/components/templates/ArrayFieldTitleTemplate.tsx +++ b/packages/core/src/components/templates/ArrayFieldTitleTemplate.tsx @@ -19,7 +19,7 @@ export default function ArrayFieldTitleTemplate< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any, >(props: ArrayFieldTitleProps) { - const { fieldPathId, title, schema, uiSchema, required, registry } = props; + const { fieldPathId, title, schema, uiSchema, required, registry, optionalDataControl } = props; const options = getUiOptions(uiSchema, registry.globalUiOptions); const { label: displayLabel = true } = options; if (!title || !displayLabel) { @@ -38,6 +38,7 @@ export default function ArrayFieldTitleTemplate< schema={schema} uiSchema={uiSchema} registry={registry} + optionalDataControl={optionalDataControl} /> ); } diff --git a/packages/core/src/components/templates/ButtonTemplates/AddButton.tsx b/packages/core/src/components/templates/ButtonTemplates/AddButton.tsx index 6dcf33bfd8..fcc9e62297 100644 --- a/packages/core/src/components/templates/ButtonTemplates/AddButton.tsx +++ b/packages/core/src/components/templates/ButtonTemplates/AddButton.tsx @@ -5,6 +5,7 @@ import IconButton from './IconButton'; /** The `AddButton` renders a button that represent the `Add` action on a form */ export default function AddButton({ + id, className, onClick, disabled, @@ -15,6 +16,7 @@ export default function AddButton

(props: ObjectFieldTemplateProps) { const { + className, description, disabled, formData, fieldPathId, onAddClick, + optionalDataControl, properties, readonly, registry, @@ -44,12 +46,13 @@ export default function ObjectFieldTemplate< registry, options, ); + const showOptionalDataControlInTitle = !readonly && !disabled; // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, } = registry.templates; return ( -

+
{title && ( )} {description && ( @@ -69,6 +73,7 @@ export default function ObjectFieldTemplate< registry={registry} /> )} + {!showOptionalDataControlInTitle ? optionalDataControl : undefined} {properties.map((prop: ObjectFieldTemplatePropertyType) => prop.content)} {canExpand(schema, uiSchema, formData) && ( (props: OptionalDataControlsTemplateProps) { + const { id, registry, label, onAddClick, onRemoveClick } = props; + if (onAddClick) { + return ( + + ); + } else if (onRemoveClick) { + return ( + + ); + } + return {label}; +} diff --git a/packages/core/src/components/templates/TitleField.tsx b/packages/core/src/components/templates/TitleField.tsx index c3916370c2..9c4682b2ef 100644 --- a/packages/core/src/components/templates/TitleField.tsx +++ b/packages/core/src/components/templates/TitleField.tsx @@ -9,11 +9,16 @@ const REQUIRED_FIELD_SYMBOL = '*'; export default function TitleField( props: TitleFieldProps, ) { - const { id, title, required } = props; + const { id, title, required, optionalDataControl } = props; return ( {title} {required && {REQUIRED_FIELD_SYMBOL}} + {optionalDataControl && ( + + {optionalDataControl} + + )} ); } diff --git a/packages/core/src/components/templates/index.ts b/packages/core/src/components/templates/index.ts index e3c3bf2457..345373e86d 100644 --- a/packages/core/src/components/templates/index.ts +++ b/packages/core/src/components/templates/index.ts @@ -15,6 +15,7 @@ import FieldHelpTemplate from './FieldHelpTemplate'; import GridTemplate from './GridTemplate'; import MultiSchemaFieldTemplate from './MultiSchemaFieldTemplate'; import ObjectFieldTemplate from './ObjectFieldTemplate'; +import OptionalDataControlsTemplate from './OptionalDataControlsTemplate'; import TitleField from './TitleField'; import UnsupportedField from './UnsupportedField'; import WrapIfAdditionalTemplate from './WrapIfAdditionalTemplate'; @@ -40,6 +41,7 @@ function templates { }, }, }, + required: ['multipleChoicesList'], }; const uiSchema = { multipleChoicesList: { diff --git a/packages/core/test/Form.test.jsx b/packages/core/test/Form.test.jsx index cb26f5cdf8..17a5f4f75a 100644 --- a/packages/core/test/Form.test.jsx +++ b/packages/core/test/Form.test.jsx @@ -5,7 +5,7 @@ import { fireEvent, act, render, waitFor } from '@testing-library/react'; import { Simulate } from 'react-dom/test-utils'; import { findDOMNode } from 'react-dom'; import { Portal } from 'react-portal'; -import { getTemplate, getUiOptions } from '@rjsf/utils'; +import { getTemplate, getUiOptions, optionalControlsId, buttonId } from '@rjsf/utils'; import validator, { customizeValidator } from '@rjsf/validator-ajv8'; import Form from '../src'; @@ -4945,4 +4945,289 @@ describe('Form omitExtraData and liveOmit', () => { expect(errors).to.have.lengthOf(0); }); }); + + describe('optionalDataControls', () => { + const schema = { + title: 'test', + properties: { + nestedObjectOptional: { + type: 'object', + properties: { + test: { + type: 'string', + }, + }, + }, + nestedArrayOptional: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }; + const arrayOnUiSchema = { + 'ui:globalOptions': { + enableOptionalDataFieldForType: ['array'], + }, + }; + const objectOnUiSchema = { + 'ui:globalOptions': { + enableOptionalDataFieldForType: ['object'], + }, + }; + const bothOnUiSchema = { + 'ui:globalOptions': { + enableOptionalDataFieldForType: ['object', 'array'], + }, + }; + const experimental_defaultFormStateBehavior = { + // Set the emptyObjectFields to only populate required defaults to highlight the code working + emptyObjectFields: 'populateRequiredDefaults', + }; + const arrayId = 'root_nestedArrayOptional'; + const objectId = 'root_nestedObjectOptional'; + const arrayControlAddId = optionalControlsId(arrayId, 'Add'); + const arrayControlRemoveId = optionalControlsId(arrayId, 'Remove'); + const arrayControlMsgId = optionalControlsId(arrayId, 'Msg'); + const arrayAddId = buttonId(arrayId, 'add'); + const objectControlAddId = optionalControlsId(objectId, 'Add'); + const objectControlRemoveId = optionalControlsId(objectId, 'Remove'); + const objectControlMsgId = optionalControlsId(objectId, 'Msg'); + it('does not render any optional data control messages when not turned on and readonly and disabled', () => { + const props = { + schema, + experimental_defaultFormStateBehavior, + readonly: true, + disabled: true, + }; + const { node } = createFormComponent(props); + const addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + const removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + const msgArrayControlNode = node.querySelector(`#${arrayControlMsgId}`); + const addArrayBtn = node.querySelector(`#${arrayAddId}`); + const addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + const removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + const msgObjectControlNode = node.querySelector(`#${objectControlMsgId}`); + const testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).eql(null); + expect(msgArrayControlNode).eql(null); + expect(addArrayBtn).not.eql(null); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).eql(null); + expect(msgObjectControlNode).eql(null); + expect(testInput).not.eql(null); + }); + it('renders optional data control messages when turned on and readonly', () => { + const props = { + schema, + uiSchema: bothOnUiSchema, + experimental_defaultFormStateBehavior, + readonly: true, + }; + const { node } = createFormComponent(props); + const addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + const removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + const msgArrayControlNode = node.querySelector(`#${arrayControlMsgId}`); + const addArrayBtn = node.querySelector(`#${arrayAddId}`); + const addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + const removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + const msgObjectControlNode = node.querySelector(`#${objectControlMsgId}`); + const testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).eql(null); + expect(msgArrayControlNode).not.eql(null); + expect(addArrayBtn).eql(null); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).eql(null); + expect(msgObjectControlNode).not.eql(null); + expect(testInput).eql(null); + }); + it('renders optional data control messages when turned on and readonly', () => { + const props = { + schema, + uiSchema: bothOnUiSchema, + experimental_defaultFormStateBehavior, + disabled: true, + }; + const { node } = createFormComponent(props); + const addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + const removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + const msgArrayControlNode = node.querySelector(`#${arrayControlMsgId}`); + const addArrayBtn = node.querySelector(`#${arrayAddId}`); + const addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + const removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + const msgObjectControlNode = node.querySelector(`#${objectControlMsgId}`); + const testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).eql(null); + expect(msgArrayControlNode).not.eql(null); + expect(addArrayBtn).eql(null); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).eql(null); + expect(msgObjectControlNode).not.eql(null); + expect(testInput).eql(null); + }); + it('does not render any optional data controls when not turned on', () => { + const props = { + schema, + experimental_defaultFormStateBehavior, + }; + const { node } = createFormComponent(props); + const addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + const removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + const addArrayBtn = node.querySelector(`#${arrayAddId}`); + const addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + const removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + const testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).eql(null); + expect(addArrayBtn).not.eql(null); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).eql(null); + expect(testInput).not.eql(null); + }); + it('only render object optional data controls when only object is turned on', () => { + const props = { + schema, + uiSchema: objectOnUiSchema, + experimental_defaultFormStateBehavior, + }; + const { node } = createFormComponent(props); + const addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + const removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + const addArrayBtn = node.querySelector(`#${arrayAddId}`); + let addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + let removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + let testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).eql(null); + expect(addArrayBtn).not.eql(null); + expect(addObjectControlNode).not.eql(null); + expect(removeObjectControlNode).eql(null); + expect(testInput).eql(null); + + // now click on the add optional data button + act(() => addObjectControlNode.click()); + // now check to see if the UI adjusted + addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + testInput = node.querySelector(`#${objectId}_test`); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).not.eql(null); + expect(testInput).not.eql(null); + + // now click on the remove optional data button + act(() => removeObjectControlNode.click()); + // now check to see if the UI adjusted + addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + testInput = node.querySelector(`#${objectId}_test`); + expect(addObjectControlNode).not.eql(null); + expect(removeObjectControlNode).eql(null); + expect(testInput).eql(null); + }); + it('only render array optional data controls when only array is turned on', () => { + const props = { + schema, + uiSchema: arrayOnUiSchema, + experimental_defaultFormStateBehavior, + }; + const { node } = createFormComponent(props); + let addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + let removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + let addArrayBtn = node.querySelector(`#${arrayAddId}`); + const addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + const removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + const testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).not.eql(null); + expect(removeArrayControlNode).eql(null); + expect(addArrayBtn).eql(null); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).eql(null); + expect(testInput).not.eql(null); + + // now click on the add optional data button + act(() => addArrayControlNode.click()); + // now check to see if the UI adjusted + addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + addArrayBtn = node.querySelector(`#${arrayAddId}`); + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).not.eql(null); + expect(addArrayBtn).not.eql(null); + + // now click on the remove optional data button + act(() => removeArrayControlNode.click()); + // now check to see if the UI adjusted + addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + addArrayBtn = node.querySelector(`#${arrayAddId}`); + expect(addArrayControlNode).not.eql(null); + expect(removeArrayControlNode).eql(null); + expect(addArrayBtn).eql(null); + }); + it('render both kinds of optional data controls when only both are turned on', () => { + const props = { + schema, + uiSchema: bothOnUiSchema, + experimental_defaultFormStateBehavior, + }; + const { node } = createFormComponent(props); + let addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + let removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + let addArrayBtn = node.querySelector(`#${arrayAddId}`); + let addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + let removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + let testInput = node.querySelector(`#${objectId}_test`); + // Check that the expected html elements are rendered (or not) as expected + expect(addArrayControlNode).not.eql(null); + expect(removeArrayControlNode).eql(null); + expect(addArrayBtn).eql(null); + expect(addObjectControlNode).not.eql(null); + expect(removeObjectControlNode).eql(null); + expect(testInput).eql(null); + + // now click on the add optional data button + act(() => addArrayControlNode.click()); + act(() => addObjectControlNode.click()); + // now check to see if the UI adjusted + addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + addArrayBtn = node.querySelector(`#${arrayAddId}`); + addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + testInput = node.querySelector(`#${objectId}_test`); + expect(addArrayControlNode).eql(null); + expect(removeArrayControlNode).not.eql(null); + expect(addArrayBtn).not.eql(null); + expect(addObjectControlNode).eql(null); + expect(removeObjectControlNode).not.eql(null); + expect(testInput).not.eql(null); + + // now click on the remove optional data button + act(() => removeArrayControlNode.click()); + act(() => removeObjectControlNode.click()); + // now check to see if the UI adjusted + addArrayControlNode = node.querySelector(`#${arrayControlAddId}`); + removeArrayControlNode = node.querySelector(`#${arrayControlRemoveId}`); + addArrayBtn = node.querySelector(`#${arrayAddId}`); + addObjectControlNode = node.querySelector(`#${objectControlAddId}`); + removeObjectControlNode = node.querySelector(`#${objectControlRemoveId}`); + testInput = node.querySelector(`#${objectId}_test`); + expect(addArrayControlNode).not.eql(null); + expect(removeArrayControlNode).eql(null); + expect(addArrayBtn).eql(null); + expect(addObjectControlNode).not.eql(null); + expect(removeObjectControlNode).eql(null); + expect(testInput).eql(null); + }); + }); }); diff --git a/packages/core/test/__snapshots__/ArraySnap.test.tsx.snap b/packages/core/test/__snapshots__/ArraySnap.test.tsx.snap index 7221eea0e3..65ea626020 100644 --- a/packages/core/test/__snapshots__/ArraySnap.test.tsx.snap +++ b/packages/core/test/__snapshots__/ArraySnap.test.tsx.snap @@ -25,6 +25,7 @@ exports[`array fields array 1`] = ` +

+
+ +
+
+
+ + deepArrayOptional2 + +
+
+

+ +

+
+
+
+
+
+ + deepArray + + * + + +
+
+

+ +

+
+
+
+ +
+
+
+ + nestedArrayOptional + +
+
+

+ +

+
+
+
+
+
+ + nestedObject + + * + + +
+ + +
+
+
+
+
+ + nestedArray + + * + + +
+
+

+ +

+
+
+
+
+ +
+
+ +
+
+
+ + optionalObjectWithOneofs + +
+ + +
+
+
+
+
+ +
+
+ +
+ +`; + +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema, readonly and no formData 1`] = ` +
+
+
+ + test + +
+
+ + nestedObjectOptional + +
+ + +
+
+
+ + deepObjectOptional + +
+ + +
+
+
+
+
+ + deepObject + + * + + +
+ + +
+
+
+
+
+ + deepArrayOptional + +
+
+

+ +

+
+
+
+
+
+ + deepArrayOptional2 + +
+
+

+ +

+
+
+
+
+
+ + deepArray + + * + + +
+
+

+ +

+
+
+
+
+
+
+
+ + nestedArrayOptional + +
+
+

+ +

+
+
+
+
+
+ + nestedObject + + * + + +
+ + +
+
+
+
+
+ + nestedArray + + * + + +
+
+

+ +

+
+
+
+
+ +
+
+ +
+
+
+ + optionalObjectWithOneofs + +
+ + +
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema and formData 1`] = ` +
+
+
+ + test + +
+
+ + nestedObjectOptional + + + + +
+ + +
+
+
+ + deepObjectOptional + + + + +
+
+
+
+ + deepObject + + * + + +
+ + +
+
+
+
+
+ + deepArrayOptional + +
+
+

+ +

+
+
+
+
+
+ + deepArrayOptional2 + + + + +
+
+
+
+
+ + deepArray + + * + + +
+
+

+ +

+
+
+
+
+
+
+
+ + nestedArrayOptional + + + + +
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+

+ +

+
+
+
+
+
+ + nestedObject + + * + + +
+ + +
+
+
+
+
+ + nestedArray + + * + + +
+
+

+ +

+
+
+
+
+ +
+
+ +
+
+
+ + optionalObjectWithOneofs + +
+ + +
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema, readonly and formData 1`] = ` +
+
+
+ + test + +
+
+ + nestedObjectOptional + +
+ + +
+
+
+ + deepObjectOptional + + + No data for optional field + +
+
+
+
+ + deepObject + + * + + +
+ + +
+
+
+
+
+ + deepArrayOptional + +
+
+

+ +

+
+
+
+
+
+ + deepArrayOptional2 + + + No data for optional field + +
+
+
+
+
+ + deepArray + + * + + +
+
+

+ +

+
+
+
+
+
+
+
+ + nestedArrayOptional + +
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+

+ +

+
+
+
+
+
+ + nestedObject + + * + + +
+ + +
+
+
+
+
+ + nestedArray + + * + + +
+
+

+ +

+
+
+
+
+ +
+
+ +
+
+
+ + optionalObjectWithOneofs + +
+ + +
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema and no formData 1`] = ` +
+
+
+ + test + +
+
+ + nestedObjectOptional + + + + +
+
+
+
+ + nestedArrayOptional + + + + +
+
+
+
+
+ + nestedObject + + * + + +
+ + +
+
+
+
+
+ + nestedArray + + * + + +
+
+

+ +

+
+
+
+
+ +
+
+ +
+
+
+ + optionalObjectWithOneofs + +
+ + +
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema, disabled and no formData 1`] = ` +
+
+
+ + test + +
+
+ + nestedObjectOptional + + + No data for optional field + +
+
+
+
+ + nestedArrayOptional + + + No data for optional field + +
+
+
+
+
+ + nestedObject + + * + + +
+ + +
+
+
+
+
+ + nestedArray + + * + + +
+
+

+ +

+
+
+
+
+ +
+
+ +
+
+
+ + optionalObjectWithOneofs + +
+ + +
+
+
+
+
+
+
+
+ +
+ +`; + exports[`single fields password field 1`] = `
, uiOptions, ); + const showOptionalDataControlInTitle = !readonly && !disabled; // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, @@ -84,6 +86,7 @@ export default function ArrayFieldTemplate
+ {!showOptionalDataControlInTitle ? optionalDataControl : undefined}
- {items && - items.map(({ key, ...itemProps }, index) => ( - - ))} + {items.map(({ key, ...itemProps }, index) => ( + + ))} {items && items.length === 0 && canAdd && (
{TranslatableString.EmptyArray}
)} diff --git a/packages/daisyui/src/templates/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx b/packages/daisyui/src/templates/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx index c71e05959f..495568dbf1 100644 --- a/packages/daisyui/src/templates/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx +++ b/packages/daisyui/src/templates/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx @@ -10,6 +10,16 @@ export default function ArrayFieldTitleTemplate< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any, >(props: ArrayFieldTitleProps) { - const { title } = props; - return

{title}

; + const { title, optionalDataControl } = props; + let heading =

{title}

; + if (optionalDataControl) { + heading = ( + <> +
{heading}
+
{optionalDataControl}
+ + ); + } + + return heading; } diff --git a/packages/daisyui/src/templates/ButtonTemplates/AddButton.tsx b/packages/daisyui/src/templates/ButtonTemplates/AddButton.tsx index 2fee45f59e..a23ecbda5e 100644 --- a/packages/daisyui/src/templates/ButtonTemplates/AddButton.tsx +++ b/packages/daisyui/src/templates/ButtonTemplates/AddButton.tsx @@ -23,11 +23,11 @@ export default function AddButton

+ ); } @@ -23,8 +23,8 @@ export function MoveDownButton ); @@ -38,8 +38,8 @@ export function MoveUpButton ); @@ -53,8 +53,8 @@ export function RemoveButton diff --git a/packages/daisyui/src/templates/ObjectFieldTemplate/ObjectFieldTemplate.tsx b/packages/daisyui/src/templates/ObjectFieldTemplate/ObjectFieldTemplate.tsx index 985b92fd25..e5054e5c36 100644 --- a/packages/daisyui/src/templates/ObjectFieldTemplate/ObjectFieldTemplate.tsx +++ b/packages/daisyui/src/templates/ObjectFieldTemplate/ObjectFieldTemplate.tsx @@ -38,6 +38,7 @@ export default function ObjectFieldTemplate< fieldPathId, schema, formData, + optionalDataControl, onAddClick, registry, } = props; @@ -48,6 +49,7 @@ export default function ObjectFieldTemplate< registry, uiOptions, ); + const showOptionalDataControlInTitle = !readonly && !disabled; // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, @@ -66,6 +68,7 @@ export default function ObjectFieldTemplate< schema={schema} uiSchema={uiSchema} registry={registry} + optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined} /> )} {description && ( @@ -78,6 +81,7 @@ export default function ObjectFieldTemplate< /> )}

+ {!showOptionalDataControlInTitle ? optionalDataControl : undefined} {properties.map((element, index) => element.hidden ? ( element.content diff --git a/packages/daisyui/src/templates/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx b/packages/daisyui/src/templates/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx new file mode 100644 index 0000000000..a8843c41b8 --- /dev/null +++ b/packages/daisyui/src/templates/OptionalDataControlsTemplate/OptionalDataControlsTemplate.tsx @@ -0,0 +1,46 @@ +import { faPlus } from '@fortawesome/free-solid-svg-icons'; +import type { IconDefinition } from '@fortawesome/fontawesome-svg-core'; +import { FormContextType, OptionalDataControlsTemplateProps, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; + +import { RemoveButton } from '../ButtonTemplates'; +import DaisyUIButton from '../ButtonTemplates/DaisyUIButton'; + +/** The OptionalDataControlsTemplate renders one of three different states. If + * there is an `onAddClick()` function, it renders the "Add" button. If there is + * an `onRemoveClick()` function, it renders the "Remove" button. Otherwise it + * renders the "No data found" section. All of them use the `label` as either + * the `title` of buttons or simply outputting it. + * + * @param props - The `OptionalDataControlsTemplateProps` for the template + */ +export default function OptionalDataControlsTemplate< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any, +>(props: OptionalDataControlsTemplateProps) { + const { id, registry, label, onAddClick, onRemoveClick } = props; + if (onAddClick) { + return ( + + ); + } else if (onRemoveClick) { + return ( + + ); + } + return {label}; +} diff --git a/packages/daisyui/src/templates/OptionalDataControlsTemplate/index.ts b/packages/daisyui/src/templates/OptionalDataControlsTemplate/index.ts new file mode 100644 index 0000000000..cf4d5a78ee --- /dev/null +++ b/packages/daisyui/src/templates/OptionalDataControlsTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from './OptionalDataControlsTemplate'; +export * from './OptionalDataControlsTemplate'; diff --git a/packages/daisyui/src/templates/Templates.tsx b/packages/daisyui/src/templates/Templates.tsx index 1c5e17a695..666cfe618a 100644 --- a/packages/daisyui/src/templates/Templates.tsx +++ b/packages/daisyui/src/templates/Templates.tsx @@ -13,6 +13,7 @@ import FieldTemplate from './FieldTemplate'; import GridTemplate from './GridTemplate/GridTemplate'; import MultiSchemaFieldTemplate from './MultiSchemaFieldTemplate'; import ObjectFieldTemplate from './ObjectFieldTemplate'; +import OptionalDataControlsTemplate from './OptionalDataControlsTemplate'; import TitleFieldTemplate from './TitleField/TitleField'; import WrapIfAdditionalTemplate from './WrapIfAdditionalTemplate'; @@ -56,6 +57,7 @@ export function generateTemplates< GridTemplate, MultiSchemaFieldTemplate, ObjectFieldTemplate, + OptionalDataControlsTemplate, TitleFieldTemplate, WrapIfAdditionalTemplate, }; diff --git a/packages/daisyui/src/templates/TitleField/TitleField.tsx b/packages/daisyui/src/templates/TitleField/TitleField.tsx index 61e751f6ec..a00dcde49e 100644 --- a/packages/daisyui/src/templates/TitleField/TitleField.tsx +++ b/packages/daisyui/src/templates/TitleField/TitleField.tsx @@ -14,13 +14,22 @@ import { TitleFieldProps, StrictRJSFSchema, RJSFSchema, FormContextType, getUiOp export default function TitleField( props: TitleFieldProps, ) { - const { id, title, uiSchema } = props; + const { id, title, uiSchema, optionalDataControl } = props; const uiOptions = getUiOptions(uiSchema); + let heading =

{uiOptions.title || title}

; + if (optionalDataControl) { + heading = ( +
+
{heading}
+
{optionalDataControl}
+
+ ); + } return (
-

{uiOptions.title || title}

-
+ {heading} +
); } diff --git a/packages/daisyui/test/__snapshots__/Array.test.tsx.snap b/packages/daisyui/test/__snapshots__/Array.test.tsx.snap index f5e33fc7e7..bc1789eeee 100644 --- a/packages/daisyui/test/__snapshots__/Array.test.tsx.snap +++ b/packages/daisyui/test/__snapshots__/Array.test.tsx.snap @@ -1242,7 +1242,7 @@ exports[`with title and description array 1`] = ` Test field
`; +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema and no formData 1`] = ` + +
+
+
+
+

+ test +

+
+
+
+
+
+
+
+
+

+ nestedObjectOptional +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObjectOptional +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional2 +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArrayOptional +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + Option 1 + + + â–¼ + +
+
    +
  • +
    + + Option 1 + +
    +
  • +
  • +
    + + Option 2 + +
    +
  • +
  • +
    + + Option 3 + +
    +
  • +
+
+
+
+
+
+
+
+

+ optionalObjectWithOneofs +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema, readonly and no formData 1`] = ` +
+
+
+
+
+

+ test +

+
+
+
+
+
+
+
+
+

+ nestedObjectOptional +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObjectOptional +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional2 +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArrayOptional +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + Option 1 + + + â–¼ + +
+
    +
  • +
    + + Option 1 + +
    +
  • +
  • +
    + + Option 2 + +
    +
  • +
  • +
    + + Option 3 + +
    +
  • +
+
+
+
+
+
+
+
+

+ optionalObjectWithOneofs +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema and formData 1`] = ` +
+
+
+
+
+

+ test +

+
+
+
+
+
+
+
+
+
+
+

+ nestedObjectOptional +

+
+
+ +
+
+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObjectOptional +

+
+
+ +
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional2 +

+
+
+ +
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArrayOptional +

+
+
+ +
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+ +
+
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + Option 1 + + + â–¼ + +
+
    +
  • +
    + + Option 1 + +
    +
  • +
  • +
    + + Option 2 + +
    +
  • +
  • +
    + + Option 3 + +
    +
  • +
+
+
+
+
+
+
+
+

+ optionalObjectWithOneofs +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema, readonly and formData 1`] = ` +
+
+
+
+
+

+ test +

+
+
+
+
+
+
+
+
+

+ nestedObjectOptional +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObjectOptional +

+
+
+
+ + No data for optional field + +
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArrayOptional2 +

+
+
+
+ + No data for optional field + +
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ deepArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArrayOptional +

+
+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+ +
+
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + Option 1 + + + â–¼ + +
+
    +
  • +
    + + Option 1 + +
    +
  • +
  • +
    + + Option 2 + +
    +
  • +
  • +
    + + Option 3 + +
    +
  • +
+
+
+
+
+
+
+
+

+ optionalObjectWithOneofs +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema and no formData 1`] = ` +
+
+
+
+
+

+ test +

+
+
+
+
+
+
+
+
+
+
+

+ nestedObjectOptional +

+
+
+ +
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArrayOptional +

+
+
+ +
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + Option 1 + + + â–¼ + +
+
    +
  • +
    + + Option 1 + +
    +
  • +
  • +
    + + Option 2 + +
    +
  • +
  • +
    + + Option 3 + +
    +
  • +
+
+
+
+
+
+
+
+

+ optionalObjectWithOneofs +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema, disabled and no formData 1`] = ` +
+
+
+
+
+

+ test +

+
+
+
+
+
+
+
+
+

+ nestedObjectOptional +

+
+
+
+ + No data for optional field + +
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArrayOptional +

+
+
+
+ + No data for optional field + +
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedObject +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+

+ nestedArray +

+
+
+
+
+
+ No items yet. Use the button below to add some. +
+
+
+
+

+ +

+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + Option 1 + + + â–¼ + +
+
    +
  • +
    + + Option 1 + +
    +
  • +
  • +
    + + Option 2 + +
    +
  • +
  • +
    + + Option 3 + +
    +
  • +
+
+
+
+
+
+
+
+

+ optionalObjectWithOneofs +

+
+
+
+
+
+
+ +
+ + +
+
+
    +
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    +
+
+
+
+
+
+
+ +
+ +`; + exports[`single fields password field 1`] = `
Note: Array and object field templates are always rendered inside the FieldTemplate. To fully customize an object field template, you may need to specify both `ui:FieldTemplate` and `ui:ObjectFieldTemplate`. +## OptionalDataControlsTemplate + +Each theme implements a `OptionalDataControlsTemplate` used to render the `Optional Data Controls` when that feature has been enabled + +```tsx +import { OptionalDataControlsTemplateProps, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'test', + properties: { + nestedObjectOptional: { + type: 'object', + properties: { + test: { + type: 'string', + }, + }, + }, + nestedArrayOptional: { + type: 'array', + items: { + type: 'string', + }, + }, + }, +}; +const uiSchema = { + 'ui:globalOptions': { + enableOptionalDataFieldForType: ['object', 'array'], + }, +}; +const experimental_defaultFormStateBehavior = { + // Set the emptyObjectFields to only populate required defaults to highlight the code working + emptyObjectFields: 'populateRequiredDefaults', +}; + +function OptionalDataControlsTemplate(props: OptionalDataControlsTemplateProps) { + const { id, registry, label, onAddClick, onRemoveClick } = props; + if (onAddClick) { + return ( + + ); + } else if (onRemoveClick) { + return ( + + ); + } + return {label}; +} + +render( + , + document.getElementById('app'), +); +``` + +The following props are passed to each `OptionalDataControlsTemplate` as defined by the `OptionalDataControlsTemplateProps` in `@rjsf/utils`: + +- `id`: The generated id for this Optional Data Control instance. +- `label`: The label to use for the Optional Data Control +- `onAddClick`: Optional callback to call when clicking on the Optional Data Control to add data +- `onRemoveClick`: Optional callback to call when clicking on the Optional Data Control to remove data +- `schema`: The schema object for this object. +- `uiSchema`: The uiSchema object for this object field. +- `registry`: The `registry` object. + ## TitleFieldTemplate Each theme implements a `TitleFieldTemplate` used to render the title of a field. diff --git a/packages/docs/docs/api-reference/OptionalDataControlsAdd.png b/packages/docs/docs/api-reference/OptionalDataControlsAdd.png new file mode 100644 index 0000000000..f765ab5423 Binary files /dev/null and b/packages/docs/docs/api-reference/OptionalDataControlsAdd.png differ diff --git a/packages/docs/docs/api-reference/OptionalDataControlsRemove.png b/packages/docs/docs/api-reference/OptionalDataControlsRemove.png new file mode 100644 index 0000000000..44a746aaa2 Binary files /dev/null and b/packages/docs/docs/api-reference/OptionalDataControlsRemove.png differ diff --git a/packages/docs/docs/api-reference/uiSchema.md b/packages/docs/docs/api-reference/uiSchema.md index 4d8a7c1866..b75c887eb7 100644 --- a/packages/docs/docs/api-reference/uiSchema.md +++ b/packages/docs/docs/api-reference/uiSchema.md @@ -244,6 +244,78 @@ const uiSchema: UiSchema = { render(, document.getElementById('app')); ``` +### enableOptionalDataFieldForType + +The `ui:enableOptionalDataFieldForType` uiSchema directive enables support for displaying the `Optional Data Controls` feature. +The intention of this feature is to allow developers to provide a condensed UI for users who don't care to enter an optional list of array items or set of optional object fields (see [examples](#add-optional-data-controls) below). + +This directive takes, as its value, an array in one of four forms: + +1. `[]` - Disables the feature at a global or field level +2. `['array']` - Enables the feature only for optional arrays at a global or field level +3. `['object']` - Enables the feature only for optional object at a global or field level +4. `['array', 'object']`- Enables the feature for both optional object and arrays at a global or field level + +It can be specified in either the `ui:globalOptions` to turn the feature on for everything or in a specific field's `uiSchema` +To work properly this option must be coupled with the [emptyObjectFields](./form-props.md#emptyobjectfields) experimental feature on `Form` using the `populateRequiredDefaults` or `skipDefaults` options. + +When enabled for either (or both) the `array` or `object` types, any optional object or array field which has an "undefined" value in `formData` will NOT render any of the container's UI elements. +Instead the object/array container's field title will have an "Add optional data" icon button that, when clicked will cause an empty container data element to be added to `formData`. + +When enabled for either (or both) the `array` or `object` types, any optional object or array field which has an "defined" value in `formData` will render all of the container's UI elements as normal AND the object/array container's field title will have a "Remove optional data" icon button that, when clicked will set the data for field in the `formData` to "undefined". + +Here is an example of what the UI will look like when enabled using the following `Form` configuration: + +```tsx +const schema: RJSFSchema = { + title: 'test', + properties: { + nestedObjectOptional: { + type: 'object', + properties: { + test: { + type: 'string', + }, + }, + }, + nestedArrayOptional: { + type: 'array', + items: { + type: 'string', + }, + }, + }, +}; +const uiSchema = { + 'ui:globalOptions': { + enableOptionalDataFieldForType: ['object', 'array'], + }, +}; +const experimental_defaultFormStateBehavior = { + // Set the emptyObjectFields to only populate required defaults to highlight the code working + emptyObjectFields: 'populateRequiredDefaults', +}; + +render( + , + document.getElementById('app'), +); +``` + +#### Add Optional Data Controls + +add optional data controls + +#### Remove Optional Data Controls + +remove optional data controls + ### emptyValue The `ui:emptyValue` uiSchema directive provides the default value to use when an input for a field is empty diff --git a/packages/docs/docs/api-reference/utility-functions.md b/packages/docs/docs/api-reference/utility-functions.md index 5cd65688b8..3ea6a67b68 100644 --- a/packages/docs/docs/api-reference/utility-functions.md +++ b/packages/docs/docs/api-reference/utility-functions.md @@ -76,7 +76,7 @@ Return a consistent `id` for the `btn` button element #### Parameters -- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it +- id: FieldPathId | string - The id of the parent component for the option - btn: 'add' | 'copy' | 'moveDown' | 'moveUp' | 'remove' - The button type for which to generate the id #### Returns @@ -596,6 +596,18 @@ This is the case when `schema.items` is a non-empty array that only contains obj - boolean: True if there are fixed items in the schema, false otherwise +### isFormDataAvailable<T = any>() + +Determines whether the given `formData` represents valid form data, such as a primitive type, an array, or a non-empty object. + +#### Parameters + +- formData: T - The data to check + +#### Returns + +- boolean: True if `formData` is not undefined, null, a primitive type or an array or an empty object + ### isObject() Determines whether a `thing` is an object for the purposes of RSJF. @@ -609,6 +621,23 @@ In this case, `thing` is an object if it has the type `object` but is NOT null, - boolean: True if it is a non-null, non-array, non-File object +### isRootSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>() + +Helper to check whether a JSON schema object is the root schema. The schema is a root schema with root `properties` +key or a root `$ref` key. If the `schemaToCompare` has a root `oneOf` property, the function will +return false. Else if `schemaToCompare` and `rootSchema` are the same object or equal, the function will return +`true`. Else if the `rootSchema` has a $ref, it will be resolved using `schemaUtils.resolveSchema` utility. If the +resolved schema matches the `schemaToCompare` the function will return `true`. Otherwise, it will return false. + +#### Parameters + +- registry: Registry<T, S, F> - The `Registry` used to get the `rootSchema` and `schemaUtils` +- schemaToCompare: S - The JSON schema object to check. If `schemaToCompare` is an root schema, the function will return true. + +#### Returns + +- boolean: True if the `uiSchema` describes a custom widget, false otherwise + ### labelValue() Helper function that will return the value to use for a widget `label` based on `hideLabel`. @@ -705,6 +734,19 @@ The difference between mergeSchemas and mergeObjects is that mergeSchemas only c - GenericObjectType: The merged schema object +### optionalControlsId() + +Return a consistent `id` for the optional data controls `element` + +#### Parameters + +- id: string - The id of the parent component for the option +- element: 'Add' | 'Msg' | 'Remove' - The element type for which to generate the id + +#### Returns + +- string: The consistent id for the optional data controls element from the given `id` and `element` type + ### optionId() Return a consistent `id` for the `optionIndex`s of a `Radio` or `Checkboxes` widget @@ -736,7 +778,7 @@ If the schema has a `oneOf` or `anyOf`, then the value is the list of either: #### Parameters - schema: S - The schema from which to extract the options list -- uiSchema: UiSchema<T, S, F> - The optional uiSchema from which to get alternate labels for the options +- [uiSchema]: UiSchema<T, S, F> - The optional uiSchema from which to get alternate labels for the options #### Returns @@ -850,6 +892,23 @@ If either of those two sets are not the same, then the component should be reren - True if boolean: the component should be re-rendered, false otherwise +### shouldRenderOptionalField<T = any, S extends StrictRJSFSchema = RJSFSchema,F extends FormContextType = any>() + +Determines whether the field information from the combination of `schema` and `required` along with the +`enableOptionalDataFieldForType` settings from the global UI options in the `registry` all indicate that this field +should be rendered with the Optional Data Controls UI. + +#### Parameters + +- registry: Registry<T, S, F> - The `registry` object +- schema: S - The schema for the field +- required - Flag indicating whether the field is required +- [uiSchema]: UiSchema<T, S, F> - The optional uiSchema for the field + +#### Returns + +- boolean: True if the field should be rendered with the optional field UI, otherwise false + ### sortedJSONStringify() Stringifies an `object`, sorts object fields in consistent order before stringifying it. diff --git a/packages/docs/docs/migration-guides/v6.x upgrade guide.md b/packages/docs/docs/migration-guides/v6.x upgrade guide.md index e797b610b2..294fe11966 100644 --- a/packages/docs/docs/migration-guides/v6.x upgrade guide.md +++ b/packages/docs/docs/migration-guides/v6.x upgrade guide.md @@ -384,6 +384,12 @@ To help support this change for test writers, a new `getTestRegistry()` function ### Templates BREAKING CHANGES +#### ArrayFieldTemplate POTENTIAL BREAKING CHANGE + +This template was updated to support the new [Optional Data Controls](#optional-data-controls) feature by adding a new `optionalDataControl` prop to the `ArrayFieldTemplateProps` interface. + +If you have your own implementation of `ArrayFieldTemplate` and want to support this new feature, please refer to any of the `ArrayFieldTemplate` implementation for whatever theme you are using and pick up the changes. + #### ArrayFieldTemplateItemType The type `ArrayFieldTemplateItemType` was deprecated in favor of the `ArrayFieldItemTemplateType` type, which matches the type naming pattern properly. @@ -408,6 +414,12 @@ See [ArrayFieldItemButtonTemplate](../advanced-customization/custom-templates.md If you have implemented your own `ArrayFieldItemTemplate` or `ArrayField` then you will have to account for these changes. +#### ArrayFieldTitleTemplate POTENTIAL BREAKING CHANGE + +This template was updated to support the new [Optional Data Controls](#optional-data-controls) feature by adding a new `optionalDataControl` prop to the `ArrayFieldTitleProps` interface. + +If you have your own implementation of `ArrayFieldTitleTemplate` and want to support this new feature, please refer to the `ArrayFieldTitleTemplate` implementation for `@rjsf/core` or whatever theme you are using and pick up the changes. + #### GridTemplate A new, theme-dependent template `GridTemplate` was added to support the new layout feature and must be provided if you are building your own `registry.templates` rather than overloading them via the `templates` props. @@ -418,6 +430,24 @@ This new template was created to extract styling applied to the `MultiSchemaFiel If you have styled your form using the following classNames and you do NOT use the `@rjsf/core` theme, you may need to adjust your styles, as they may have been removed from your theme: `panel`, `panel-default`, `panel-body`, `form-group`. +#### ObjectFieldTemplate POTENTIAL BREAKING CHANGE + +This template was updated to support the new [Optional Data Controls](#optional-data-controls) feature by adding a new `optionalDataControl` prop to the `ObjectFieldTemplateProps` interface. + +If you have your own implementation of `ObjectFieldTemplate` and want to support this new feature, please refer to the `ObjectFieldTemplate` implementation for whatever theme you are using and pick up the changes. + +#### OptionalDataControlsTemplate POTENTIAL BREAKING CHANGE + +This new template was created to support the new [Optional Data Controls](#optional-data-controls) feature. + +If you are implementing your own theme you may need to add this new template if you anticipate supporting this new feature. + +#### TitleFieldTemplate POTENTIAL BREAKING CHANGE + +This template was updated to support the new [Optional Data Controls](#optional-data-controls) feature by adding a new `optionalDataControl` prop to the `TitleFieldProps` interface. + +If you have your own implementation of `TitleFieldTemplate` and want to support this new feature, please refer to the `TitleFieldTemplate` implementation for whatever theme you are using and pick up the changes. + #### SchemaUtilsType Five new functions were added to this type, so if you have your own implementation of this type, you will need to add them to yours. @@ -674,20 +704,29 @@ The generics ordering on the `optionsList()` function was changed from `(formData?: T)(formData?: T): boolean`: Determines whether the given `formData` represents valid form data, such as a primitive type, an array, or a non-empty object. +- `isRootSchema(registry: Registry, schemaToCompare: S): boolean`: Helper to check whether a JSON schema object is the root schema - `lookupFromFormContext(regOrFc: Registry | Registry['formContext'], toLookup: string, fallback?: unknown)`: Given a React JSON Schema Form registry or formContext object, return the value associated with `toLookup` +- `optionalControlsId(id: FieldPathId | string, element: 'Add' | 'Msg' | 'Remove')`: Return a consistent `id` for the optional data controls `element` +- `shouldRenderOptionalField(registry: Registry, schema: S, required: boolean, uiSchema?: UiSchema): boolean`: Determines if this field should be rendered with the Optional Data Controls UI. - `sortedJSONStringify(object: unknown): string`: Stringifies an `object`, sorts object fields in consistent order before stringifying it. - `toFieldPathId(fieldPath: string | number, globalFormOptions: GlobalFormOptions, parentPath?: FieldPathId | FieldPathList)`: Constructs the `FieldPathId` for `fieldPath` and the optional `parentPath`, using `globalFormOptions` @@ -701,7 +740,15 @@ Three new validator-based utility functions are available in `@rjsf/utils`: ### Changes to existing utility functions -- `getDefaultFormState`: Added optional `initialDefaultsGenerated` boolean flag that indicates whether or not initial defaults have been generated +- `getDefaultFormState()`: Added an optional `initialDefaultsGenerated` boolean flag that indicates whether or not initial defaults have been generated +- `retrieveSchema()`: Added an optional `resolveAnyOfOrOneOfRefs` boolean flag that causes the internal `resolveAllSchemas()` to resolve `$ref`s inside of the options of `anyOf`/`oneOf` schemas + - This new optional flag was added to the `SchemaUtilsType` interface's version of `retrieveSchema()` as well. + +### Optional Data Controls + +RJSF 6.x introduces a new feature that allows developers to provide a condensed UI for users who don't care to enter an optional list of array items or set of optional object fields. + +See the documentation for [enableOptionalDataFieldForType](../api-reference/uiSchema.md#enableoptionaldatafieldfortype) for more information. ### Dynamic UI Schema for Array Items diff --git a/packages/fluentui-rc/src/AddButton/AddButton.tsx b/packages/fluentui-rc/src/AddButton/AddButton.tsx index 714c21db11..2ef21d147e 100644 --- a/packages/fluentui-rc/src/AddButton/AddButton.tsx +++ b/packages/fluentui-rc/src/AddButton/AddButton.tsx @@ -8,5 +8,5 @@ export default function AddButton) { const { translateString } = registry; - return +
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ deepArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ nestedObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema, readonly and no formData 1`] = ` +
+
+
+
+
+ test +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+ deepObjectOptional +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ deepObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ deepArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ nestedObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema and formData 1`] = ` +
+
+
+
+
+ test +
+
+
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+
+ +
+
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+ deepObjectOptional +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ deepObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ deepArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+ nestedObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" and "remove" optional controls when turned on in uiSchema, readonly and formData 1`] = ` +
+
+
+
+
+ test +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+ deepObjectOptional +
+
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+ deepObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ deepArrayOptional +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ deepArrayOptional2 +
+
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+ deepArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+
+
+
+
+
+
+ + + + +
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+ nestedObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema and no formData 1`] = ` +
+
+
+
+
+ test +
+
+
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ nestedObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +`; + +exports[`single fields optional data controls shows "add" optional controls when turned on in uiSchema, disabled and no formData 1`] = ` +
+
+
+
+
+ test +
+
+
+
+
+
+
+
+
+ nestedObjectOptional +
+
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+ nestedArrayOptional +
+
+
+
+ + No data for optional field + +
+
+
+
+
+
+
+
+
+ nestedObject +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+ nestedArray +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+ + +
+
+
+
+
+
+
+ optionalObjectWithOneofs +
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ +`; + exports[`single fields password field 1`] = `
Titre 1
diff --git a/packages/fluentui-rc/test/__snapshots__/GridSnap.test.tsx.snap b/packages/fluentui-rc/test/__snapshots__/GridSnap.test.tsx.snap index b2c31c7163..afa601ca87 100644 --- a/packages/fluentui-rc/test/__snapshots__/GridSnap.test.tsx.snap +++ b/packages/fluentui-rc/test/__snapshots__/GridSnap.test.tsx.snap @@ -43,6 +43,11 @@ exports[`Complex grid renders person and address and employment in a complex gri >
Person Info
@@ -1137,6 +1142,11 @@ exports[`Complex grid renders person and address and employment in a complex gri >
Person Info
@@ -2266,6 +2276,11 @@ exports[`Complex grid renders person and address and employment in a complex gri >
Person Info
@@ -3192,6 +3207,11 @@ exports[`Complex grid renders person and address and employment in a complex gri >
Person Info
@@ -4286,6 +4306,11 @@ exports[`Three even column grid renders person and address in three columns, no >
Person Info
@@ -5007,6 +5032,11 @@ exports[`Two even column grid renders person and address in two columns, no empl >
Person Info
diff --git a/packages/fluentui-rc/test/__snapshots__/Object.test.tsx.snap b/packages/fluentui-rc/test/__snapshots__/Object.test.tsx.snap index af432b6a8c..324db82853 100644 --- a/packages/fluentui-rc/test/__snapshots__/Object.test.tsx.snap +++ b/packages/fluentui-rc/test/__snapshots__/Object.test.tsx.snap @@ -484,6 +484,11 @@ exports[`object fields with title and description additionalProperties 1`] = ` >
Test field
@@ -679,6 +684,11 @@ exports[`object fields with title and description from both additionalProperties >
My Field
@@ -874,6 +884,11 @@ exports[`object fields with title and description from both object 1`] = ` >
My Field
@@ -1045,6 +1060,11 @@ exports[`object fields with title and description from uiSchema additionalProper >
My Field
@@ -1240,6 +1260,11 @@ exports[`object fields with title and description from uiSchema object 1`] = ` >
My Field
@@ -1411,6 +1436,11 @@ exports[`object fields with title and description from uiSchema show add button >
My Field
@@ -1606,6 +1636,11 @@ exports[`object fields with title and description object 1`] = ` >
Test field
@@ -1777,6 +1812,11 @@ exports[`object fields with title and description show add button and fields if >
Test field
diff --git a/packages/mantine/src/templates/ArrayFieldTemplate.tsx b/packages/mantine/src/templates/ArrayFieldTemplate.tsx index 9e55847eb5..2f08563c1b 100644 --- a/packages/mantine/src/templates/ArrayFieldTemplate.tsx +++ b/packages/mantine/src/templates/ArrayFieldTemplate.tsx @@ -25,6 +25,7 @@ export default function ArrayFieldTemplate< disabled, fieldPathId, items, + optionalDataControl, onAddClick, readonly, required, @@ -50,6 +51,7 @@ export default function ArrayFieldTemplate< registry, uiOptions, ); + const showOptionalDataControlInTitle = !readonly && !disabled; // Button templates are not overridden in the uiSchema const { ButtonTemplates: { AddButton }, @@ -63,6 +65,7 @@ export default function ArrayFieldTemplate< schema={schema} uiSchema={uiSchema} registry={registry} + optionalDataControl={showOptionalDataControlInTitle ? optionalDataControl : undefined} /> ); @@ -77,14 +80,12 @@ export default function ArrayFieldTemplate< registry={registry} /> )} - - {items && - items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( - - ))} + {!showOptionalDataControlInTitle ? optionalDataControl : undefined} + {items.map(({ key, ...itemProps }: ArrayFieldItemTemplateType) => ( + + ))} - {canAdd && ( )} {description && ( @@ -80,13 +83,13 @@ export default function ObjectFieldTemplate< verticalSpacing={gridVerticalSpacing as MantineSpacing | undefined} mb='sm' > + {!showOptionalDataControlInTitle ? optionalDataControl : undefined} {properties .filter((e) => !e.hidden) .map((element: ObjectFieldTemplatePropertyType) => ( {element.content} ))} - {canExpand(schema, uiSchema, formData) && ( (props: OptionalDataControlsTemplateProps) { + const { id, registry, label, onAddClick, onRemoveClick } = props; + if (onAddClick) { + return ( + + ); + } else if (onRemoveClick) { + return ( + + ); + } + return {label}; +} diff --git a/packages/mantine/src/templates/TitleField.tsx b/packages/mantine/src/templates/TitleField.tsx index 0b7b9fb9c7..bb7119f7f7 100644 --- a/packages/mantine/src/templates/TitleField.tsx +++ b/packages/mantine/src/templates/TitleField.tsx @@ -1,5 +1,5 @@ import { FormContextType, TitleFieldProps, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; -import { Title } from '@mantine/core'; +import { Grid, Title } from '@mantine/core'; /** The `TitleField` is the template to use to render the title of a field * @@ -8,10 +8,19 @@ import { Title } from '@mantine/core'; export default function TitleField( props: TitleFieldProps, ) { - const { id, title } = props; - return title ? ( + const { id, title, optionalDataControl } = props; + let heading = title ? ( {title} ) : null; + if (optionalDataControl) { + heading = ( + + {heading} + {optionalDataControl} + + ); + } + return heading; } diff --git a/packages/mantine/src/templates/index.ts b/packages/mantine/src/templates/index.ts index 2208bcb7f2..7937d1ef8c 100644 --- a/packages/mantine/src/templates/index.ts +++ b/packages/mantine/src/templates/index.ts @@ -12,6 +12,7 @@ import FieldTemplate from './FieldTemplate'; import FieldHelpTemplate from './FieldHelpTemplate'; import GridTemplate from './GridTemplate'; import ObjectFieldTemplate from './ObjectFieldTemplate'; +import OptionalDataControlsTemplate from './OptionalDataControlsTemplate'; import TitleField from './TitleField'; import WrapIfAdditionalTemplate from './WrapIfAdditionalTemplate'; import MultiSchemaFieldTemplate from './MultiSchemaFieldTemplate'; @@ -34,6 +35,7 @@ export function generateTemplates< FieldHelpTemplate, GridTemplate, ObjectFieldTemplate, + OptionalDataControlsTemplate, TitleFieldTemplate: TitleField, WrapIfAdditionalTemplate, MultiSchemaFieldTemplate, diff --git a/packages/mantine/test/__snapshots__/Form.test.tsx.snap b/packages/mantine/test/__snapshots__/Form.test.tsx.snap index 083269b2ea..307ca0c7c2 100644 --- a/packages/mantine/test/__snapshots__/Form.test.tsx.snap +++ b/packages/mantine/test/__snapshots__/Form.test.tsx.snap @@ -4648,6 +4648,13084 @@ exports[`single fields number field 1`] = ` ] `; +exports[`single fields optional data controls does not show optional controls when not turned on in uiSchema and no formData 1`] = ` +[ +