From 899710d176678583ac8c41b088818d42c74dec9e Mon Sep 17 00:00:00 2001 From: Heath C <51679588+heath-freenome@users.noreply.github.com> Date: Sat, 27 Aug 2022 14:36:04 -0700 Subject: [PATCH] Merge the long-lived RJSF v5 branch to master (#3055) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Packages/utils (#2863) * Implemented the utils package - Refactored the `packages/core/src/utils.js` file into separate typescript files in the new `packages/utils/src` * - More changes * - Added all of the non-validation-based utilities and many of the tests * - removed schema related files temporarily * - Added missing tests to get test coverage up to 100% for all but `getWidget()` - Also did some cleanup in the `src` files, moving types into `types.ts`, and exporting all the types * - Fixed getWidget tests * - Update README.md * - update the target to for typescript in * - revert `package-lock.json` for antd, core and playground * - fix build issues * - Added the `rjsf-v5` branch to the `ci.yml` - Added a new `RJSFSchema` as a redefine of `JSONSchema7` to make changing schemas everywhere else easier - Updated all the utils and tests to change `JSONSchema7` to `RJSFSchema` - Fixed test breaks by casting e to Error * - changed tabs to spaces in package.json, fixed bug in deepEquals * - Add `tsdx` to `package.json` to enable running `npm run test` inside of the `packages/utils` directory - Bumped `@types/jest` to match the version in use by `tsdx` - Fixed the `utcToLocal()` test by mocking the `getDate()` and `getHours()` functions to be UTC + 2 hours to avoid server vs local timezone issues * - Began adding documentation to the utility functions - Reordered the logic in `asNumber` to avoid converting to number until we have to - Updated `findSchemaDefinition()` to handle the case where a `$ref` in a schema also contains additional props - Updated `getSubmitButtonOptions()` to export its `DEFAULT_OPTIONS` for testing purposes - Updated `getUiOptions()` to no longer support `ui:widget` objects as it has been deprecated for years - Made some other test fixes * - Finished adding documentation to all of the remaining utils methods * - Minor documentation changes, and allow `findSchemaDefinition()` to support undefined ref name * - Responded to self-review comments * Packages/utils/schema (#2877) * Implemented the utils package - Refactored the `packages/core/src/utils.js` file into separate typescript files in the new `packages/utils/src` * - More changes * - Added all of the non-validation-based utilities and many of the tests * - removed schema related files temporarily * - revert `package-lock.json` for antd, core and playground * - The schema utilities that require validation * - More changes * - completed conversion to Typescript with some changes that were needed * - Updated various files to make some parameters optional, to add generics typing where missed - Created an `index.ts` in the `schema` subdirectory that exports all of the schema related functions - Updated `types.ts` to add the new `SchemaUtilsType` interface - Implemented a `createSchemaUtils()` function that returns a `SchemaUtilsType` interface given a `ValidatorType` and a `rootSchema` * - Implemented createSchemaUtils - Began testing the schema-based utils * - More fixes and adding missing generics * - Converted all the schema based tests over still missing 100% coverage * - Completed 100% unit testing * - Added documentation for most of the files and cleaned up some optionality on some arguments * - Completed all of the documentation of the schema-based utils * - Changed the `_NAME` constants to `_KEY` * - Added missing generics on a few types * - Added `ERRORS_KEY` constant for use in validation * - Fixed types based on implementation of validator * - Added missing generic to the `ValidationData` type for `ErrorSchema` * - Fixed tests for the missing generic type * - Incorporated #2876 by making props for UISchemaSubmitButtonOptions optional * - Added generic `` to the return value of `toIdSchema()` and `toPathSchema()` * Refactored schema to support running schema tests from other packages (#2899) * Refactored schema to support runnings from other packages - Fixed the import of `types` in `mergeSchemas.ts` - Renamed all of the `xxx.test.ts` to `xxxTest.ts` and wrapped them in an outer `xxxTest()` function that takes a `TestValidatorType` - Added a `types.ts` file in the `schema` directory to provide the `TestValidatorType` and `TestValidatorParams` interfaces - Added an `index.ts` file in the `schema` directory to export all of the `xxxTest` functions - Updated `getTestValidator()` to import the types from the `schema/types` - Added a `test/schema.test.ts` to create a `TestValidator` and run all of the `xxxTest()` functions from `schema` * - Fixed the tests based on using the real validator * - Removed the use of `xxx.hasOwnProperty('y')` in favor `'y' in xxx` to eliminate lint warnings - Fixed bug in `stubExistingAdditionalProperties()` related to the `additionalProperties: true` case, adding new test to verify fix * - Removed console.log statement * - Moved `stubExistingAdditionalProperties()` into the `retrieveSchema.ts` file to eliminate a circular dependency - Did the same for the `stubExistingAdditionalPropertiesTest()` function - Updated the `index.ts` files to remove the `stubExistingAdditionalProperties[Test]()` functions - Updated `SchemaUtilsType` and `createSchemaUtils` to remove the `stubExistingAdditionalProperties()` function * Validator ajv6 (#2891) * Added new package for validator-ajv6 - Refactored `packages/core/src/validate.js` into this new package * - Switched to the new `@rjsf/utils` library and types * - Finished types conversion to @rjsf/utils - Began adding tests * - Completed conversion for validator class-based tests. Just need to get to 100% 1 * - Finished 100% test coverage and documentation of the `AJV6Validator` * - Completed the documentation of the remaining methods and types for the library * - Responded to self-review feedback and also fixed tests to hopefully get it to pass * - Fixed the build (this time hopefully) * - Switched to just passing `stack` instead of the whole empty object * - Added hacky run of tests from within the utils directory * - Fixed a few little things * - Fixed bug in custom validation, including adding a test to detect it * - Removed schema utils test for `stubExistingAdditionalPropertiesTest()` as it no longer exists * - Fixed self-review feedback and the import in the `test/createAjvInstance.test.ts` - Also bumped all the packages that made sense * Update utils based on core refactor and update package.jsons (#2903) * Update utils based on core refactor and update package.jsons - Updated the main `package.json` to bump typescript - Updated the utils `package.json` to bump everything but react - Updated `SchemaUtilsType` to add the `getValidator()` and `doesSchemaUtilsDiffer()` functions - Updated `createSchemaUtils()` to implement the new functions and the tests to validate them - Also updated other types to deal with issues found during core refactor - Changed `FormValidation` to `ErrorSchema` as needed - Updated the `Registry` type to remove `definitions` as it is never used and added the `xxxTemplate` props - Updated many interfaces to make previously required props to be optional - Switched to using the `React.ComponentType` which incorporates the `FunctionComponent` and `ClassComponent` both - Fixed a bug in `getDefaultFormState()` by making the `array` defaults use effectively the same logic as it did in `core` but refactored to a function for type safety - Updated the tests to add one that verifies the bug is fixed * - rollback typescript to previous version due to `fluent-ui` issue * - Fixed bug in `getSchemaType()` related to incorrectly defaulting to `string` when no type exists * - Made `uiSchema` optional in `canExpand()`, `getSubmitButtonOptions()` and `getUiOptions()` - Updated the required-ness of a smattering of props in interfaces * - Made all callbacks be required again * - Made label required again * - More updates to make `uiSchema` optional * - Added new `processSelectValue()` utility, refactored from core's `SelectWidget`, with full tests - Also updated the `UIOptionsType` to add optional `title` and `description` props, typed to `string` to eliminate the need to type cast them * - Added documentation for the `[key: string]` prop * - Responded to reviewer feedback * Updated semantic-ui theme to use new @rjsf/utils and @rjsf/validator (#2920) * Updated @rjsf/core to use the new `utils` and `validator-ajv6` libraries - Removed the `index.d.ts` file since all the types are now exported in `@rjsf/utils` - Updated `package*.json` to make changes consistent with pulling utils and validator-ajv6 libraries - Removed `core-js-pure`, `json-schema-merge-allof`, `jsonpointer` and `react-is` from `dependencies` in favor of `@rjsf/utils` - Moved `ajv` and `@types/json-schema` into the `devDependencies` - Added `@rjsf/validator-ajv6`, `@types/lodash` and `tsdx` - Also, removed all mentions of `index.d.ts` - Converted `ErrorList` to typescript, pulling types from `@rjsf/utils` - Converted `Form` to typescript - Built `FormProps` and `FormState` props which are exported - Pulled in all the types from `@rjsf/utils` functions - Removed the `additionalMetaSchemas` and `customFormats` props in favor of the new, required `validator: ValidatorType` prop - Updated `getStateFromProps()` to create a `SchemaUtilsType` object and put it into both the state and the registry as `schemaUtils` - Switched to using the `schemaUtils.getValidator()` to access the `validateFormData()` and `toErrorList()` calls - Switched to using `schemaUtils` to access `getDefaultFormState()`, `toIdSchema()`, `toPathSchema()` and `retrieveSchema()` - Updated `ArrayField` to use the `@rjsf/utils` functions - Also, switched to the `includes` function from `lodash` - Pull the `schemaUtils` from the `registry` and used it for `getDefaultFormState()`, `isMultiSelect()`, `isFilesArray()`, `retrieveSchema()` and `toIdSchema()` - Switched from `xxx.hadOwnProperty('y')` to `'y' in xxx` to remove an eslint warning - Updated `BooleanField`, `NumberField`, `CheckboxWidget`, `DateTimeWidget`, `FileWidget`, `RangeWidget`, `SelectWidget` and `UpDownWidget` to pull utility functions from `@rjsf/utils` - Updated `MultiSchemaField` to use the `@rjsf/utils` functions - Pulled the `schemaUtils` from the `registry` and used it for `getDefaultFormState()` and `getMatchingOption()` - Switched from `xxx.hadOwnProperty('y')` to `'y' in xxx` to remove an eslint warning - Updated `ObjectField` to use the `@rjsf/utils` functions - Pulled the `schemaUtils` from the `registry` and used it for `retrieveSchema()` - Switched from `xxx.hadOwnProperty('y')` to `'y' in xxx` to remove an eslint warning - Updated `SchemaField` to use the `@rjsf/utils` functions - Pulled the `schemaUtils` from the `registry` and used it for `getDisplayLabel()`, `isSelect()`, `retrieveSchema()` and `toIdSchema()` - Switched from `xxx.hadOwnProperty('y')` to `'y' in xxx` to remove an eslint warning - Updated `StringField` to use the `@rjsf/utils` functions - Pulled the `schemaUtils` from the `registry` and used it for `isSelect()` - Updated `AltDateWidget` to use the `@rjsf/utils` functions - Removed `prevState` from `componentDidUpdate()` because it is not used, removing lint error - Updated `TextWidget` to add `bool` as a type for the value to avoid a React error that failed tests - Converted `SubmitButton` to typescript, pulling types from `@rjsf/utils` and exporting it's props type - Converted `getDefaultRegistry()` to typescript, pulling types from `@rjsf/utils` - Changed the export to be `default` - Temporarily needing to cast `fields` and `widgets` to the proper type until they are converted - Converted `withTheme()` to typescript, pulling types from `@rjsf/utils` and the typescript `Form` - Converted the `src/index.js` file to Typescript, exporting both the `Form` and its types along with `withTheme()`, `getDefaultRegistry()` - Updated the `types.js` file to remove `definitions` and add in `schemaUtils` ffor the `registry` type. - Deleted the `src/utils.js`, `src/validate.js` files since they have been replaced with `@rjsf/utils/` and `@rjsf/validator-ajv6` - Removed the `utils_test.js` file entirely and only kept the `Form` integration part of the `validate_test.js` - Updated the tests as follows to make things work with `@rjsf/utils` and `@rjsf/validator-ajv6` - Updated `test_utils.js` to import the default `validator` from `@rjsf/validator-ajv6` and add it to the props for `createFormComponent()` - Updated the `Form_test.js` to import the default `validator` and the `customizeValidator()` function and passed `validator` into props for `
...
` - Updated the checking of `onChangeProp` to add `schemaValidationErrors`, `schemaValidationErrorSchema` and `schemaUtils` to the `calledWith()` check - Updated the checking of `onError` to add `schemaValidationErrors`, `schemaValidationErrorSchema` to the match - Deleted any tests that dealt with the now removed deprecated features - Replaced tests the used the `customFormats` or `additionalMetaSchemas` props with a customized validator with those values set on it - In one place, removed a piece of a test that was reverting the old props since they don't exist anymore - Updated the `SchemaField_test.js` file to check the `registry` in the received props to have `schemaUtils` instead of `definitions` - Fixed the import of `getDefaultRegistry()` - Also removed the test related to `empty definitions` since that isn't in the registry anymore - Updated the `StringField_test.js` to import the utility functions from `@rjsf/utils` - Updated the `uiSchema_test.js` file to deal with the removal of deprecated `ui:widget: {component, options}` feature in `@rjsf/utils` - Switched from `warn` to `error` for spying - Removed the deprecated `ui:widget` configurations in the tests, moving the options into the `ui:options` block instead` - Verified the proper error (instead of warning) is returned * - Temporarily restore `index.d.ts` until next PR when it gets removed * - Export `WithThemeProps` from core * - Converted `AddButton` to Typescript - Switched `SubmitButton` to use `WidgetProps` - Removed `schemaUtils` as a param for `getDefaultRegistry()` - Set generic defaults on `WithThemeProps` - Fixed cast of `SubmitButton` in `Form` * - Updated the type for `withTheme()` * - Refactored `processValue` out of `SelectWidget` and used the new `processSelectValue()` method in utils * - Fixed a few more things found while finishing up the themes conversion * Updated antd theme to use new @rjsf/utils and @rjsf/validator - Updated `package*.json` to add `@rjsf/utils` and `@rjsf/validator` to dev and peer dependencies - Also, Removed a bunch of packages that were never used since the conversion to `tsdx` - Finally, bumped most of the dev dependencies that made sense to the latest version, except for those that cause breaking tests - Removed the `webpack.config.*.js` files since they are no longer needed since the conversion to `tsdx` - Updated all uses of non-schema utilities methods to `@rjsf/utils` and switched to using `registry.schemaUtils.XXX()` for those schema-based utilities - Updated the import of `getDefaultRegistry()` to be directly from `@rjsf/core` - Modified `SelectWidget` to use the new `processSelectValue()` function from `@rjsf/utils` - Updated the tests to import the `validator` from `@rjsf/validator` to pass to the `Form` - Also updated the snapshots via the `test:update` script to deal with the little differences from the conversion * Updated bootstrap-4 theme to use new @rjsf/utils and @rjsf/validator - Updated `package*.json` to add `@rjsf/utils` to dev and peer dependencies and `@rjsf/validator-ajv6` to dev dependencies - Also, Removed a bunch of packages that were never used since the conversion to `tsdx` - Finally, bumped most of the dev dependencies that made sense to the latest version, except for those that cause breaking tests - Updated all uses of non-schema utilities methods to `@rjsf/utils` and switched to using `registry.schemaUtils.XXX()` for those schema-based utilities - Updated the import of `getDefaultRegistry()` to be directly from `@rjsf/core` - Updated components that used the `uiSchema['ui:xxx']` notation to get the `uiOptions` using `getUiOptions(uiSchema)` then doing `uiOptions.xxx` instead - Updated the use of `React.FC` with `React.ComponentType` in `AddButton` and `SubmitButton` - Updated `ArrayFieldTitleProps` and `ArrayFieldDescriptionProps` to make `title`, `required` and `description` optional in the `ArrayFieldTemplate.tsx` file - Also fixed the indentation of components - Updated `WrapIfAdditionalProps` to pick props from `FieldTemplateProps` joining it with `children` to fix type issues - Updated `Form` to use `React.ComponentType` - Modified `SelectWidget` to use the new `processSelectValue()` function from `@rjsf/utils` - Updated the tests to change to using `RJSFSchema` rather than `JSON7Schema` and import the `validator` from `@rjsf/validator` to pass to the `Form` - Also updated the snapshots via the `test:update` script to deal with the little differences from the conversion * Updated chakra-ui theme to use new @rjsf/utils and @rjsf/validator - Updated `package*.json` to add `@rjsf/utils` to dev and peer dependencies and `@rjsf/validator-ajv6` to dev dependencies - Also, Removed a bunch of packages that were never used since the conversion to `tsdx` - Finally, bumped most of the dev dependencies that made sense to the latest version, except for those that cause breaking tests - Updated all uses of non-schema utilities methods to `@rjsf/utils` and switched to using `registry.schemaUtils.XXX()` for those schema-based utilities - Updated the import of `getDefaultRegistry()` to be directly from `@rjsf/core` - Updated components that used the `uiSchema['ui:xxx']` notation to get the `uiOptions` using `getUiOptions(uiSchema)` then doing `uiOptions.xxx` instead - Updated the use of `React.FC` with `React.ComponentType` in `AddButton` and `SubmitButton` - Updated `AltDateWidget` to extend the `AltDateStateType` object from the `DateObject` - Updated `ArrayFieldTitleProps` and `ArrayFieldDescriptionProps` to make `title`, `required` and `description` optional in the `ArrayFieldTemplate.tsx` file - Also fixed the indentation of components - Updated `WrapIfAdditionalProps` to pick props from `FieldTemplateProps` joining it with `children` to fix type issues - Updated `Form` to use `React.ComponentType` - Modified `SelectWidget` to use the new `processSelectValue()` function from `@rjsf/utils` - Updated `utils.js` to remove the custom `ThemeProps` in favor of the new `WithThemeProps` from `@rjsf/core` - Updated the tests to change to using `RJSFSchema` rather than `JSON7Schema` and import the `validator` from `@rjsf/validator` to pass to the `Form` - Also updated the snapshots via the `test:update` script to deal with the little differences from the conversion * Updated fluent-ui theme to use new @rjsf/utils and @rjsf/validator - Updated `package*.json` to add `@rjsf/utils` to dev and peer dependencies and `@rjsf/validator-ajv6` to dev dependencies - Also, Removed a bunch of packages that were never used since the conversion to `tsdx` - Finally, bumped most of the dev dependencies that made sense to the latest version, except for those that cause breaking tests - Updated all uses of non-schema utilities methods to `@rjsf/utils` and switched to using `registry.schemaUtils.XXX()` for those schema-based utilities - Updated the import of `getDefaultRegistry()` to be directly from `@rjsf/core` - Updated `ArrayFieldTitleProps` and `ArrayFieldDescriptionProps` to make `title`, `required` and `description` optional in the `ArrayFieldTemplate.tsx` file - Also fixed the indentation of components - Updated `WrapIfAdditionalProps` to pick props from `FieldTemplateProps` joining it with `children` to fix type issues - Updated `FuiForm` to use `React.ComponentType` - Modified `SelectWidget` to use the new `processSelectValue()` function from `@rjsf/utils` - Updated the tests to change to using `RJSFSchema` rather than `JSON7Schema` and import the `validator` from `@rjsf/validator` to pass to the `Form` - Also updated the snapshots via the `test:update` script to deal with the little differences from the conversion * Updated material-ui theme to use new @rjsf/utils and @rjsf/validator - Updated `package*.json` to add `@rjsf/utils` to dev and peer dependencies and `@rjsf/validator-ajv6` to dev dependencies - Also, Removed a bunch of packages that were never used since the conversion to `tsdx` - Finally, bumped most of the dev dependencies that made sense to the latest version, except for those that cause breaking tests - Updated all uses of non-schema utilities methods to `@rjsf/utils` and switched to using `registry.schemaUtils.XXX()` for those schema-based utilities - Updated the import of `getDefaultRegistry()` to be directly from `@rjsf/core` - Updated components that used the `uiSchema['ui:xxx']` notation to get the `uiOptions` using `getUiOptions(uiSchema)` then doing `uiOptions.xxx` instead - Updated the use of `React.FC` with `React.ComponentType` in `AddButton` and `SubmitButton` - Updated `ArrayFieldTitleProps` and `ArrayFieldDescriptionProps` to make `title`, `required` and `description` optional in the `ArrayFieldTemplate.tsx` file - Also fixed the indentation of components - Updated `WrapIfAdditionalProps` to pick props from `FieldTemplateProps` joining it with `children` to fix type issues - Updated `MuiForm` and `MuiForm5` to use `React.ComponentType` - Modified `SelectWidget` to use the new `processSelectValue()` function from `@rjsf/utils` - Updated the tests to change to using `RJSFSchema` rather than `JSON7Schema` and import the `validator` from `@rjsf/validator` to pass to the `Form` - Also updated the snapshots via the `test:update` script to deal with the little differences from the conversion * Updated semantic-ui theme to use new @rjsf/utils and @rjsf/validator - Bumped the main `package.json` to use the latest version of `Typescript` - Updated `.eslintrc` with what was needed to support the latest eslint version - Updated `package*.json` to add `@rjsf/utils` to dev and peer dependencies and `@rjsf/validator-ajv6` to dev dependencies - Also, Removed a bunch of packages that were never used since the conversion to `tsdx` - Finally, bumped most of the dev dependencies that made sense to the latest version, except for those that cause breaking tests - Updated all uses of non-schema utilities methods to `@rjsf/utils` and switched to using `registry.schemaUtils.XXX()` for those schema-based utilities - Updated the import of `getDefaultRegistry()` to be directly from `@rjsf/core` - Modified `SelectWidget` to use the new `processSelectValue()` function from `@rjsf/utils` - Updated the tests to import the `validator` from `@rjsf/validator` to pass to the `Form` - Also updated the snapshots via the `test:update` script to deal with the little differences from the conversion * - Fixed material-ui build to no longer generate the v4 and v5 versions since the theme will soon be separated into two packages * - Update material-ui package-lock.json to match package.json * Added ajvOptionsOverrides to support user-provided AJV options overriding (#2929) - Updated `CustomValidatorOptionsType` to add `ajvOptionsOverrides` - Updated the `createAjvInstance()` function to spread any `ajvOptionsOverrides` on top of the `AJV_CONFIG` - Updated `AJV6Validator` constructor to pass `ajvOptionsOverrides` to `createAjvInstance()` - Updated tests to add test-case for the `$data` flag mentioned in #1668 * Optimized and updated imports in core package.json (#2931) * Optimized and updated imports in core package.json - Updated `tsdx` build to also run umd, eliminating the need for the one-off webpack version build - Deleted the `test-old` and `build-umd` scripts - Added `@rjsf/utils` to `peerDependencies` - Removed all of the webpack and cross-env related packages no longer needed for the one-off build - Also removed `express`, `gh-pages`, `estraverse*` and `husky` - Updated a bunch of the `peerDependencies` package versions to the latest - Deleted the now unnecessary `webpack.config.dist.js` * - Removed `prettier` from `package.json` as it differs from the version used in the main `package.json` - Ran `cs-format` to fix all of the prettier errors reported by `cs-check` * - Bumped `prettier` to pickup latest typescript support - Switched from `jsxBracketSameLine: true` to `bracketSameLine: false` - Ran `cs-format` over `playground` as well * Added support for node 16, formatting and linting (validator-ajv6) (#2932) * Added support for node 16 and linting - Regenerated the `package-lock.json` file with node-16 - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file * - Ran `cs-format` on the `validator-ajv6` source to fix build * - Switched the `no-unused-vars` rule to `@typescript-eslint/no-unused-vars` in `.eslintrc` * Added support for node 16, formatting and linting (utils) (#2933) * Added support for node 16, formatting and linting - Regenerated the `package-lock.json` file with node-16 - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Ran `cs-format` over the `src` and `test` directories to fix the build * - Switched the `no-unused-vars` rule to `@typescript-eslint/no-unused-vars` in `.eslintrc` * Added support for node 16, formatting and linting (bootstrap-4) (#2936) * Added support for node 16, formatting and linting - Regenerated the `package-lock.json` file with node-16 - Also added packages to support linting - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Ran `eslint --fix` and `cs-format` over the `src` and `test` directories to fix the build - Added a slight adaptation of the `.eslintrc` file from `core` to this package * - Fixed build * Added support for node 16, formatting and linting (fluent-ui) (#2938) * Added support for node 16, formatting and linting - Regenerated the `package-lock.json` file with node-16 - Also added packages to support linting - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Ran `eslint --fix` and `cs-format` over the `src` and `test` directories to fix the build - Added a slight adaptation of the `.eslintrc` file from `core` to this package * - Fix build, hopefully * Added support for node 16, formatting and linting (semantic-ui) (#2939) - Regenerated the `package-lock.json` file with node-16 - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Ran `cs-format` over the `src` and `test` directories to fix the build * Added support for node 16, formatting and linting (#2937) - Regenerated the `package-lock.json` file with node-16 - Also added packages to support linting - Explicity added the latest `prettier` because it in implicitly picking up the wrong one - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Ran `eslint --fix` and `cs-format` over the `src` and `test` directories to fix the build - Added a slight adaptation of the `.eslintrc` file from `core` to this package - Added `.npmrc` to enable `legacy-peer-deps` to allow things to work with node 16 - Deleted `.prettierrc` since the override is no longer needed * Added support for node 16, formatting and linting (antd) (#2935) * Added support for node 16, formatting and linting - Regenerated the `package-lock.json` file with node-16 - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Added `@babel/eslint-parser` and removed `babel-parser` - Ran `cs-format` over the `src` and `test` directories to fix the build - Updated `.eslintrc` to switch to using the `@babel/eslint-parser` with the necessary `parserOptions` * - Fix `package.json` formatting * Updated the playground to allow a validator selection (#2941) * Updated the playground to allow a validator selection - Defaults to the `ajv6` validator - Updated `package*.json` to add `@rjsf/utils` and `@rjsf/validator-ajv6` - Also removed a bunch of unnecessary packages - Bumped a bunch of other packages to the latest minor and patch version - Bumped a few select packages to the latest major version - Updated `.eslintrc` to switch from `babel-eslint` to `@babel/eslint-parser` - Updated the `index.js` file to add a `validators` object containing the `AJV6` validator choice, passing it into `Playground` - Updated the `app.js` file to get `shouldRender()` from `@rjsf/utils` instead of copying it from core - Also extracted `validators` from the props for `Playground`, storing `validator` in the state, initially set to `AJV6` - Added a `ValidatorSelector` component that is used to update the selected `validator` in state - Rendered a `ValidagtorSelector` just before the `CopyLink` component - Passed `validators[validator]` as the `validator` prop on `FormComponent` * - Ran `cs-format` to fix formatting issues and fix the build * Split out material-ui v5 theme as @rjsf/mui (#2948) * Split out material-ui v5 theme as @rjsf/mui - Copied the `material-ui` directory and removed the `@material-ui` dependencies - Deleted the `MuiComponentContext`, `MuiForm5`, `Theme5` and `ThemeCommon` directories (moving the contents of `ThemeCommon/index.js` directly into `Theme`) - Deleted the `MaterialUIContext` and `MaterialUIContextProps` files and everything in `Theme.tsx` that related to them - Replaced all fetching of the Material UI components from the `useMuiComponent()` hook with actual imports from `@mui/material` and `@mui/icons-material` - Regenerated the `package-lock.json` file with node-16 - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Copied the `.eslintrc` file from `core` - This involved adding `@typescript-eslint`, `eslint` and `eslint-plugin-*` - Ran `eslint --fix` and `cs-format` over the `src` and `test` directories to fix the build * - Fix build by fixing a few little things * - Fixed playground imports to read from new repo * Made @rjsf/material-ui only be for Material UI 4 (#2949) - Deleted the `MuiComponentContext`, `MuiForm5`, `Theme5` and `ThemeCommon` directories (moving the contents of `ThemeCommon/index.js` directly into `Theme`) - Deleted the `MaterialUIContext` and `MaterialUIContextProps` files and everything in `Theme.tsx` that related to them - Replaced all fetching of the Material UI components from the `useMuiComponent()` hook with actual imports from `@material-ui/core` and `@material-ui/icons` - Deleted the `tests/mui-5` directory and fixed up the tests to work with the simple `Form` - Regenerated the `package-lock.json` file with node-16 - Added the `cs-check`, `cs-format` and `lint` scripts along with `lint-staged` to the `package.json` file - Copied the `.eslintrc` file from `core` - This involved adding `@typescript-eslint`, `eslint` and `eslint-plugin-*` - Ran `eslint --fix` and `cs-format` over the `src` and `test` directories to fix the build * Get node 16 build working, centralize lint configs and switch to dts-cli (#2951) * Get node 16 build working and centralize lint configs - Added `.eslintrc-javascript` for the common configs needed for `antd`, `playground` and `semantic-ui` - Added `.eslintrc-typescript` for the common configs needed for the rest of the packages - Updated `.github/workflows/ci.yml` to add node 16 and to build the playground using it instead of 14 - Updated `.gitignore` to add the few items from the `.gitignore` files in sub-packages - Removed the `.gitignore` in the sub-packages, along with the two `.editorconfig` files - Updated all of the `.eslintrc` files in the packages to extend the appropriate `.eslintrc-*script` file - Left the `plugins` array definitions in each `.eslintrc` file - Avoids an issue where eslint found the base and sub-package implementation of the plugins and complained when they were in the base - Updated the main `package*.json` to add the packages needed for linting so that they can be removed in the sub-packages - Updated each sub-package `package*.json` files to remove all but the `eslint` package (leaving it locally so that it can be run in the subdirectory) - Also bumped any out-of-date packages related to `babel` or `eslint` * - Replaced `tsdx` with its most current forked cousin `dts-cli` - This removed the need for the `.npmrc` file in `chakra-ui` * - Re-ran `npm run cs-format` due to prettier upgrades provided by `dts-cli` - Also fixed some typescript issues in `fluent-ui` related to object spreading by casting `options.props as object` * - Fixed tests due to change to `dts-cli` - Added `jest-environment-jsdom` and `ts-jest` that matches the jest version `dts-cli` uses in the main `package.json` - Updated `package.json`s to remove incompatible jest related packages - Updated and/or moved `jest.config.js` files to add `testEnvironment` and `testEnvironmentOptions` for `jsdom` - Updated `chakra-ui` and `mui` to add missing libraries for emotion and jest - Redid the `mui` snapshots after changes * - Rollback `semantic-ui` so that it still uses `tsdx` due to test failures using `dts-cli` * - Bumped `eslint` to 8.20 * Bumped the dependencies for semantic-ui (#2972) - Fixed react 16.14 adding >=17 in peer dependencies - Didn't bump to react 17 officially to avoid peer dependencies issues with `semantic-ui` which is stuck on 16 - Bumped nanoid to the latest minor version * Bump dependencies for both material-ui themes (#2971) - In `material-ui`, fixed react 16.14 in peer dependencies - In `mui`, bumped `@mui/material` to the latest - Removed `react-dom` and `@types/react` from the peer dependencies - Bumped eslint to latest release - Removed the types for jest as it was unnecessary * Bumped fluent-ui dependencies (#2970) - Bumped to latest minor version for `fluent-ui` - Bumped react to 17, fixing react 16.14 in peer dependencies - Removed unnecessary types for jest - Updated `SelectWidget` to properly use the right `defaultSelectedKey[s]` prop based on multiple flag - Updated test snapshots due to dependency bumps * Bumping dependencies for utils (#2969) - Bumped react to 17, fixing react 16.14 in peer dependencies - Removed `react-dom` because it wasn't needed * Bumping dependencies for core (#2968) - Bumped nanoid to latest - Bumped react to 17, fixing react 16.14 in peer dependencies * Bumped the dependencies for bootstrap-4 (#2967) - Can't bump to bootstrap-2, so bumped to latest 1.x version - Bumped react to 17, fixing react 16.14 in peer dependencies - Bumped `react-icons` to latest - Updated test snapshots due to changes from bumps * Bumped some of the dependencies for chakra-ui (#2965) - Can't upgrade to chakra-ui 2.0 because it requires react 18 - Locked peerDependencies for react to ^16.14.0 or >=17 - Bumped minor versions of `react-select`, `chakra-react-select` and `framer-motion` - Updated test snapshot as a result * Upgraded to latest antd code (#2963) * Upgraded to latest antd code - Added an additional test for the custom `DatePicker` - Fixed the `tests` for checkboxes in array that broke with upgrade by implementing a required ref - Updated all the test snapshots due to upgrade changes * - Fix build by running `cs-format` * - Bumped react to 17, fixing react 16.14 in peer dependencies * Switched playground to webpack 5 and other small fixes (#2958) * Switched playground to webpack 5 and other small fixes - Updated `.github/workflows/release.yml` to use node 16 - Updated the main `package.json` to remove `webpack` and `webpack-cli` as they are only needed by `playground` - Updated all of the `package.json` files for the themes to fix the `build` script to change `--format cjs,es,umd` to `--format cjs,esm,umd` - This is because `dts-cli` changed `es` to `esm` - Also updated `material-ui` to add that missing flag to `build` - Updated `.babelrc` to get it working with webpack 5 - Updated `package.json` for playground to update (or remove) `webpack` and all of its plugins and utilities - Explicitly added `ajv8` since `webpack-dev-server` uses it and the `validator-ajv6` has an earlier version - Updated the `webpack.config.*.js` files to support webpack 5 - Updated the `index.js` for playground to organize the themes in alphabetical order (after default) * - Bumped `antd` libraries to latest * - Updated theme libraries to match the ones in the updated theme `package.json` files * Update package-locks (#2973) - After merging all the package.json cleanups, some of the package-lock.json files were a bit out of date, updating them * Updated documentation for the v5 release (#2974) * Updated documentation for the v5 release - Updated `/latest/` with `/stable` for all `.md` files, mirroring changes made on master - Changed all uses of `
` in existing documentation to add the required `validator` from `@rjsf/validator-ajv6` - Updated the `validation.md` docs to cover v5 changes and additions - Added a new `utility-function.md` to document the `@rjsf/utils` function, constants and types - Deleted the `customizing-material-ui.md` file since we split apart the two theme versions - Added the version 5 migration document - Updated `@rjsf/utils` to add or improve documentation - Also refactored out the `TemplateTypes` interfaces to help support future work related to expanding templates - Added a utility type, `MakeUIType` and refactored out `UIOptionsBaseType` in order to dry out the `UiOptionsType` and `UiSchema` types - Updated `Form` in `@rjsf/core` to move the `IChangeEvent` type from `utils` extending it from `FormState` - The props `validate` was renamed to `customValidate` - Also, updated `FormProps` to extend the new `TemplatesType` interface - Updated `withTheme` to add the missing generics onto `Form` * - Added placeholders for `core`'s missing documentation on the Typescript files * - Completed the documentation of all the Typescript based files in `core` - Responded to reviewer feedback - Added a few more constants in `@rjsf/utils`, using them as appropriate in utils and core * Fix the docs for formElement in Form (#2983) - Added an explanation for why the `any` type is specified * fix: core SubmitButton button option props * chore: remove duplicate settings from semantic-ui package.json * fix: missing error class on semantic-ui fields * Consolidate templates into a single location in registry (#2981) * Consolidate templates into a single location in registry - Updated `.eslint-typescript` to turn off two warnings that were noisy - Updated the `@rjsf/utils` types as follows to support a consolidated `templates` object: - Updated the `Registry` type to no longer extend `TemplateTypes`, but instead have it as a new `templates` property. - Updated the `TemplateTypes` type to consolidate more templates as follows: - Made all but `ArrayFieldTemplate` required - Refactored `ErrorList` from the `FormProps` as `ErrorListTemplate` - Added `TitleFieldTemplate` and `DescriptionFieldTemplate` - Updated `TitleFieldProps` to `registry` since all templates require a back-pointer to the `registry` - Also added `uiSchema` to support capabilities in use by several themes - Updated `DescriptionFieldProps` to add `registry` since all templates require a back-pointer to the `registry` - Updated the `ArrayFieldTemplateProps` and `ObjectFieldTemplateProps` to remove `TitleField` and `DescriptionField` since they can now be obtained from the `templates` - Also, updated `UiSchema` to add `Partial<>` around `TemplateTypes`, since we want the `ui:` versions to all be optional - Updated `@rjsf/core` to add `templates` to `Form` and `makeTheme` props - Removed the `ErrorList`, `ArrayFieldTemplate`, `ObjectFieldTemplate` and `FieldTemplate` from the props - Also modified `Form` to pull `ErrorListTemplate` from the `templates` prop - Created a new `templates` directory, moving in `TitleField` and `DescriptionField` from the `fields` directory - Created a `templates/FieldTemplate` directory, refactoring out the `FieldTemplate`, `Label` and `WrapIfAdditional` components from the `SchemaField.js` file - Converted these components to Typescript - Inlined the code from `LabelInput` directly into `WrapIfAdditional` - Updated `SchemaField.js` to pull `FieldTemplate` from `registry.templates` - Moved the `ErrorList.tsx` file into this directory - Refactored `ObjectFieldTemplate` component from the `ObjectField.js` file - Converted this to Typescript - Updated `ObjectField.js` to pull `DescriptionFieldTemplate`, `ObjectFieldTemplate` and `TitleFieldTemplate` from `registry.templates`, passing in `registry` - Updated `ArrayField.ts` to pull `DescriptionFieldTemplate` and `TitleFieldTemplate` from `registry.templates`, passing in `registry` - Updated `BooleanField` to no longer pass `DescriptionField` to the `Widget` - Updated `CheckboxWidget` to pull `DescriptionFieldTemplate` from `registry.templates`, passing in `registry` - Updated `getDefaultRegistry()` to import the new `templates` directory `index.ts` instead of all the separate templates, exporting it on the default `registry` - Fixed up all the tests to deal with this consolidation - Updated `@rjsf/antd` to consolidate `templates` as follows: - Moved `ErrorList.js` into the `templates/ErrorList` directory as `index.js` - Moved `DescriptionField` and `TitleField` into the `templates` directory - Removed the now, unnecessary commented out `FieldProps` from `DescriptionField` and `TitleField` - Also extracted `formContext` out of `registry` in `TitleField` - Updated the base `index.js` file to export `templates` by combining default `templates` with the files from the `templates` directories - Updated `@rjsf/bootstrap-4` to consolidate `templates` as follows: - Updated `DescriptionField` and `TitleField` to use the `DescriptionFieldProps` and `TitleFieldProps` from `@rjsf/utils` instead of `Partial` - Updated `ArrayFieldTemplate.tsx` and `ObjectFieldTemplate.tsx` to pull `DescriptionFieldTemplate` and `TitleFieldTemplate` from `registry.templates` - Also, pass `registry` (and `uiSchema`) to the `DescriptionFieldTemplate` and `TitleFieldTemplate` - Renamed `Fields/Fields.ts` to `Templates/Templates.ts` - Also added `ArrayFieldTemplate`, `ErrorList` (as `ErrorListTemplate`), `FieldTemplate` and `ObjectFieldTemplate` to the `Templates` - Updated `Theme` to export `templates` from the `Templates` directory - Updated tests to deal with the consolidation - Updated `@rjsf/chakra-ui` to consolidate `templates` as follows: - Updated `DescriptionField` and `TitleField` to use the `DescriptionFieldProps` and `TitleFieldProps` from `@rjsf/utils` instead of `Partial` - Updated `ArrayFieldTemplate.tsx` and `ObjectFieldTemplate.tsx` to pull `DescriptionFieldTemplate` and `TitleFieldTemplate` from `registry.templates` - Also, pass `registry` to the `DescriptionFieldTemplate` and `TitleFieldTemplate` - Renamed `Fields/Fields.ts` to `Templates/Templates.ts` - Also added `ArrayFieldTemplate`, `ErrorList` (as `ErrorListTemplate`), `FieldTemplate` and `ObjectFieldTemplate` to the `Templates` - Updated `Theme` to export `templates` from the `Templates` directory - Updated the base `index.ts` file to export the `Templates` directory in place of the `Fields` and individual templates, as well as fixed the `Form` export - Updated `@rjsf/fluent-ui` to consolidate `templates` as follows: - Updated `DescriptionField` and `TitleField` to use the `DescriptionFieldProps` and `TitleFieldProps` from `@rjsf/utils` instead of `Partial` - Updated `ArrayFieldTemplate.tsx` and `ObjectFieldTemplate.tsx` to pull `DescriptionFieldTemplate` and `TitleFieldTemplate` from `registry.templates` - Also, pass `registry` to the `DescriptionFieldTemplate` and `TitleFieldTemplate` - Renamed `Fields/Fields.ts` to `Templates/Templates.ts` - Also added `ArrayFieldTemplate`, `ErrorList` (as `ErrorListTemplate`), `FieldTemplate` and `ObjectFieldTemplate` to the `Templates` - Updated `Theme` to export `templates` from the `Templates` directory - Updated the base `index.ts` file to export the `Templates` directory in place of the `Fields` and individual templates, as well as fixed the `Form` export - Updated `@rsjf/material-ui` and `@rjsf/mui` to considate `templates` as follows: - Updated `DescriptionField` and `TitleField` to use the `DescriptionFieldProps` and `TitleFieldProps` from `@rjsf/utils` instead of `Partial` - Updated `ArrayFieldTemplate.tsx` and `ObjectFieldTemplate.tsx` to pull `DescriptionFieldTemplate` and `TitleFieldTemplate` from `registry.templates` - Also, pass `registry` to the `DescriptionFieldTemplate` and `TitleFieldTemplate` - Renamed `Fields/Fields.ts` to `Templates/Templates.ts` - Also added `ArrayFieldTemplate`, `ErrorList` (as `ErrorListTemplate`), `FieldTemplate` and `ObjectFieldTemplate` to the `Templates` - Updated `Theme` to export `templates` from the `Templates` directory - Updated the base `index.ts` file to export the `Templates` directory in place of the `Fields` and individual templates, as well as fixed the `Form` export - Fixed the tests as well - Updated the `@rjsf/semantic-ui` to consolidate `templates` as follows: - Updated `ArrayFieldTemplate.tsx` and `ObjectFieldTemplate.tsx` to pull `DescriptionFieldTemplate` and `TitleFieldTemplate` from `registry.templates` - Also, pass `registry` (and `uiSchema`) to the `DescriptionFieldTemplate` and `TitleFieldTemplate` - Renamed `Fields/Fields.ts` to `Templates/Templates.ts` - Also added `ArrayFieldTemplate`, `ErrorList` (as `ErrorListTemplate`), `FieldTemplate` and `ObjectFieldTemplate` to the `Templates` - Updated `FieldTemplate` to get the `DescriptionFieldTemplate` from `registry.templates` - Updated `Theme` to export `templates` from the `Templates` directory - Updated `TitleField` to get the `ui:options` from the `uiSchema` instead of having them passed directly - Updated the base `index.ts` file to export the `Templates` directory in place of the `Fields` and individual templates, as well as fixed the `Form` export * - Changed the name of `DescriptionField` and `TitleField` to append `Template` onto it only in association with the `templates` - Also, made them both render `id` for all the themes - Updated tests and snapshots accordingly * - Added documentation for the new typescript files in `core` * - Responded to self and other reviewer feedback * - Fixed bad commit in core imported by rebase * Prepare utils and tests for upcoming BaseInputTemplate work (#2986) * Prepare utils and tests for upcoming BaseInputTemplate work - Added the `BaseInputTemplate` type into the `TemplatesType` - Refactored code from `BaseInput` in `@rjsf/core` as `getInputProps()` - Added 100% unit tests - Consolidated all the various tests in different themes into all of the other themes - Updated the snapshots for all the new tests in all themes * - Fixed up test for material-ui themes by adding missing ref's required by the components - Also, for `material-ui` 4, add mock of `findDOMNode()` so that tests are all successful * - Updated all the snapshot due to the new and fixed tests in all the themes * - Fix chakra-ui's `WrapIfAdditional`, `CheckboxesWidget` and `RadioWidget` to generate stable label ids - Updated snapshots accordingly * - Updated `RadioWidget` in semantic UI to generate a stable names * Implement BaseInputTemplate in core (#2987) * Implement BaseInputTemplate in core - Updated `TemplateType` to make `BaseInputTemplate` required now - Refactored the `TextWidget.js` file into `BaseInputTemplate.tsx`, adding support for number transforms - Refactored (and converted to Typescript) the following widgets to use the `BaseInputTemplate` for their implementations - `ColorWidget`, `DateTimeWidget`, `DateWidget`, `EmailWidget`, `PasswordWidget`, `RangeWidget`, `TextWidget`, `URLWidget` and `UpDownWidget` - Updated all of the tests to use `BaseInputWidget` in `templates` instead of `BaseInput` in `widgets` - Updated `bootstrap-4`, `material-ui` and `mui` themes to add `TextWidget` as the `BaseInputTemplate` temporarily to fix tests * - Updated `semantic-ui` test snapshot due to changes in core * Remove Node 12, use Node 16 as default engine, add Node 18 to build (#2996) * Deprecate Node 12, use Node 16 as default engine * Add engine to validator-ajv6 * Implement BaseInputTemplate in bootstrap-4 (#2990) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `ColorWidget`, `DateTimeWidget`, `DateWidget`, `EmailWidget`, `PasswordWidget`, `URLWidget`, `UpDownWidget` - Updated the `widgets` overrides in `Widgets.js` to remove the deleted class references - Updated `WrapIfAdditional` to add missing `htmlFor` - Updated `FileWidget` and `RangeWidget` to use the `BaseInputTemplate` - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` - Also deleted some tests and snapshots that were for now deleted widgets * Implement BaseInputTemplate in chakra-ui (#2991) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `ColorWidget`, `DateTimeWidget`, `DateWidget`, `EmailWidget`, `PasswordWidget`, `URLWidget` - Updated the `widgets` overrides in `Widgets.tsx` to remove the deleted class references - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` * Implement BaseInputTemplate in fluent-ui (#2992) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `AltDateTimeWidget`, `AltDateWidget`, `EmailWidget`, `PasswordWidget`, `URLWidget` - Updated the `widgets` overrides in `Widgets.tsx` to remove the deleted class references - Updated `TextareaWidget` to use the `BaseInputTemplate` - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` * Implement BaseInputTemplate in material-ui (#2993) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `ColorWidget`, `EmailWidget`, `PasswordWidget`, `URLWidget`, `UpDownWidget` - Updated the `widgets` overrides in `Widgets.tsx` to remove the deleted class references - Updated `CheckboxesWidget`, `RadioWidget` to add missing `id` associated with the `htmlFor` - Updated `DateTimeWidget` `DateWidget` and `TextareaWidget` to use the `BaseInputTemplate` - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` - Also deleted some tests and snapshots that were for now deleted widgets * Implement BaseInputTemplate in mui (#2994) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `ColorWidget`, `EmailWidget`, `PasswordWidget`, `URLWidget`, `UpDownWidget` - Updated the `widgets` overrides in `Widgets.tsx` to remove the deleted class references - Updated `CheckboxesWidget`, `RadioWidget` to add missing `id` associated with the `htmlFor` - Updated `DateTimeWidget` `DateWidget` and `TextareaWidget` to use the `BaseInputTemplate` - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` - Also deleted some tests and snapshots that were for now deleted widgets * Implement BaseInputTemplate in semantic-ui (#2995) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Yes, git thinks it was the `EmailWidget` but it was actually `TextWidget` - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `DateTimeWidget`, `DateWidget`, `EmailWidget`, `PasswordWidget`, `URLWidget`, `UpDownWidget` - Updated the `widgets` overrides in `Widgets.tsx` to remove the deleted class references - Updated `RadioWidget` to improve the name of the `Radio` buttons - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` - Also deleted some tests and snapshots that were for now deleted widgets * Implement BaseInputTemplate in antd (#2989) - Refactored `TextWidget` as `BaseInputTemplate`, using the `getInputProps()` to implement `core` feature - Deleted the following widgets because they are now just duplicate code to what is implemented with the template in `core` - `ColorWidget`, `EmailWidget`, `URLWidget`, `UpDownWidget` - Updated the `widgets` overrides in `index.js` to remove the deleted class references - Updated the test snapshots to match the subtle little changes caused by the `getInputProps()` feature and increased use of the `BaseInputTemplate` * Add precommit script to all packages missing it (#3004) - Copied the `precommit: lint-staged` from `core` into all of the packages missing it - Also updated to husky v8 and lint-staged to v13 * Remove unnecessary lodash uses (#2997) * Remove unnecessary lodash dependencies * revert some changes * readd newline * Refactored the ArrayFieldTemplate into 4 templates (#3001) * Refactored the ArrayFieldTemplate into 4 templates - Updated the `types` in `@rjsf/utils` to make `ArrayFieldTemplate` required as well as adding the following 3 new templates: - `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` - Also added to new types `ArrayFieldDescriptionProps` and `ArrayFieldTitleProps` - Updated the `core` theme to support the updated `ArrayFeildTemplate`s as follows: - Refactored the `ArrayFieldDescription` and `ArrayFieldTitle` from `ArrayField.js` as `ArrayFieldDescriptionTemplate` and `ArrayFieldTitleTemplate` - These new Typescript classes were added into the `Templates` directory - These two new templates were essentially the same across all themes, but made a template just in case and so they can be used in all themes - Refactored the `DefaultArrayItem` component from `ArrayField.js` as `ArrayFieldItemTemplate` as a new Typescript file in the `Templates` directory - Refactored the `DefaultNormalArrayFieldTemplate` from `ArrayField.js` as `ArrayFieldTemplate` as a new Typescript file in the `Templates` directory - Turns out the `DefaultFixedArrayFieldTemplate` was essentially the same as the other template (and was never customized in any of the themes) - As a result, this template was deemed unnecessary - Updated the `antd` theme to support the updated `ArrayFieldTemplate`s as follows: - Renamed the `ArrayFieldTemplateItem` component as `ArrayFieldItemTemplate` in its own directory - Renamed the `NormalArrayFieldTemplate` as `ArrayFieldTemplate` (ignore git) - Switched to using the `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` from the templates directory - Deleted the main `ArrayFieldTemplate/index.js` and `FixedArrayFieldTemplate.js` files from the directory - Updated the `Templates.tsx` file to add the `ArrayFieldItemTemplate` into the `templates` object - Updated the `bootstrap-4` theme to support the updated `ArrayFieldTemplates`s as follows: - Refactored the `DefaultArrayItem` component from `ArrayFieldTemplate` as `ArrayFieldItemTemplate` in its own directory - Updated `ArrayFieldTemplate` by deleting all the unnecessary code, turning the `DefaultNormalArrayFieldTemplate` into the `ArrayFieldTemplate` - Used the `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` from `registry.templates` - Updated the `Templates.tsx` file to add the `ArrayFieldItemTemplate` into the `templates` object - Deleted the test and snapshot for `ArrayFieldTemplates` since it was already covered elsewhere - Updated the `registry` mock to pull `templates` from the `getDefaultRegistry()`, overriding with the theme `Templates` - Updated the `chakra-ui` theme to support the updated `ArrayFieldTemplates`s as follows: - Refactored the `DefaultArrayItem` component from `ArrayFieldTemplate` as `ArrayFieldItemTemplate` in its own directory - Updated `ArrayFieldTemplate` by deleting all the unnecessary code, turning the `DefaultNormalArrayFieldTemplate` into the `ArrayFieldTemplate` - Used the `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` from `registry.templates` - Updated the `Templates.tsx` file to add the `ArrayFieldItemTemplate` into the `templates` object - Updated the `chakra-ui` theme to support the updated `ArrayFieldTemplates`s as follows: - Refactored the `DefaultArrayItem` component from `ArrayFieldTemplate` as `ArrayFieldItemTemplate` in its own directory - Updated `ArrayFieldTemplate` by deleting all the unnecessary code, turning the `DefaultNormalArrayFieldTemplate` into the `ArrayFieldTemplate` - Used the `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` from `registry.templates` - Updated the `Templates.tsx` file to add the `ArrayFieldItemTemplate` into the `templates` object - Updated the snapshot for the array templates to pick up the little changes from the refactor - Updated the `material-ui` and `mui` themes to support the updated `ArrayFieldTemplates`s as follows: - Refactored the `DefaultArrayItem` component from `ArrayFieldTemplate` as `ArrayFieldItemTemplate` in its own directory - Updated `ArrayFieldTemplate` by deleting all the unnecessary code, turning the `DefaultNormalArrayFieldTemplate` into the `ArrayFieldTemplate` - Used the `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` from `registry.templates` - Updated the `Templates.tsx` file to add the `ArrayFieldItemTemplate` into the `templates` object - Deleted the `UpDownWidget` tests and snapshots because they are duplicated in the `Form` tests - Updated the `semantic-ui` theme to support the updated `ArrayFieldTemplates`s as follows: - Refactored the `DefaultArrayItem` component from `ArrayFieldTemplate` as `ArrayFieldItemTemplate` in its own directory - Updated `ArrayFieldTemplate` by deleting all the unnecessary code, turning the `DefaultNormalArrayFieldTemplate` into the `ArrayFieldTemplate` - Used the `ArrayFieldDescriptionTemplate`, `ArrayFieldItemTemplate` and `ArrayFieldTitleTemplate` from `registry.templates` - Updated the `Templates.tsx` file to add the `ArrayFieldItemTemplate` into the `templates` object * - Responded to reviewer feedback * add nx to monorepo (#2998) * add nx to monorepo * fixed lockfile issue * remove nx cloud access token Co-authored-by: Heath C <51679588+heath-freenome@users.noreply.github.com> Co-authored-by: Heath C <51679588+heath-freenome@users.noreply.github.com> * Migrate core widget folder to typescript (#3006) * Migrate core widget folder to typescript * Adressed PR feedback * Addressed additional PR comments * Addressed additional PR comments * fix : semantic-ui error class on fields (#3009) * Converted core fields to Typescript (#3007) * Converted the fields to Typescript - Updated the `@rjsf/utils` types and functions based on necessary changes needed for the conversion as follows: - In `types.ts` some improvements and new types were discovered as follows: - Modified the `RJSFSchema` to add the non-standard `enumNames` property onto the `JSONSchema7` to support the `Field`s - Added a new `EnumOptionsType` required for some of the fields - Added a new `UnsupportedFieldProps` type for the new `UnsupportedFieldTemplate` on `TemplatesType` - Removed the `fields` property on `FieldTemplateProps` since that data can be easily obtained from the `registry` - Added the `rawErrors` property to `ArrayFieldTemplateProps` since it was needed `ArrayField` - Added the missing `T` generic on a few uses of `IdSchema` properties on a few types - Updated the `WidgetProps` type to combine the `options` property with an additional, optional `enumOptions` property as needed by widgets - Updated the `UIOptionsBaseType` to have it combined with the `TemplatesType` making it require the `T` and `F` generics as well as adding the following new properties: - `classNames` was added as a breaking change (it used to simply be `classNames` in `UiSchema` but now it will be `ui:classNames` or `ui:options: { classNames }` - This makes `classNames` consistent with all the other ui options - `orderable` and `removable` were added to support the `ArrayField` - `widget` was added to support many of the `Field`s - Updated `UIOptionsType` to also take the `T` and `F` generics - Updated `SchemaUtilsType.retrieveSchema()` to make the `formData` parameter optional, like it already is on the wrapped function - Updated the `getUiOptions()` function to add the `T` and `F` generics to the return value type - Updated `getWidget()` to make the `widget` property optional, updating the tests accordingly - Updated `isCustomWidget()` to make `uiSchema` default to an empty object if missing, updating the tests accordingly - Updated `optionsList` to remove the `enumNames` hack and to return the new `EnumOptionsType[] | undefined` type - Updated `FieldTemplate` for `antd` to remove the commented out `fields` variable since it was removed from the `FieldTemplateProps` - Refactored `ArrayField.js` to `ArrayField.tsx` converting things to typescript - Made the `FieldProps` use the `T[]` generic based on the `ArrayField`'s `T` generic since `formData` should always be an array - There were many places where type safety checks were required along with custom casts to deal with `T` vs `T[]` issues - Exported `ArrayField` cast as a `Field` to allow it to be used properly in the `index.ts` - Refactored `BooleanField.js` to `BooleanField.tsx` converting things to typescript - Refactored `MultiSchemaField.js` to `MultiSchemaField.tsx` converting things to typescript - Refactored `NullField.js` to `NullField.tsx` converting things to typescript - Refactored `NumberField.js` to `NumberField.tsx` converting things to typescript as well as making it a stateless functional component with `useState()` instead of a class - Refactored `ObjectField.js` to `ObjectField.tsx` converting things to typescript - Refactored `SchemaField.js` to `SchemaField.tsx` converting things to typescript - Updated the code to deal with the `classNames` now coming from `ui:` options, including updating tests accordingly adding a new one for the new case inside of `ui:options` - Refactored `StringField.js` to `StringField.tsx` converting things to typescript - Refactored `fields/index.js` to `fields/index.ts` adding the proper type for the returned object - Updated `ArrayFieldTemplate` to add the missing `T` and `F` generics required for `getUiOptions()` - Updated `ObjectFieldTemplate` to add the `T` and `F` generics onto `getUiOptions()` - Refactored `fields/UnsupportedField.js` to `templates/UnsupportedField.tsx` converting things to typescript - Added this to `templates/index.ts` as `UnsupportedFieldTemplate` - Also updated tests to use `templates.UnsupportedFieldTemplate` instead of `fields.UnsupportedField` - Updated `getDefaultRegistry()` to remove the cast on `fields` since they are now properly typed - Updated the test snapshots in the themes to deal with minor formatting updates due to these changes - Renamed the `ArrayFieldTemplate.js` file in the `antd` theme to `index.js` to match all the other files - Updated many of the `ObjectFieldTemplate`s to also recognize and support rendering the `description` from `uiOptions` * - Added `registry` to the `ArrayFieldTemplateItemType` type, as well as documenting `ArrayField` * - Added missing generics to the `ArrayFieldItemTemplate` * - Removed unused types.js * - Responded to self-review feedback * - Added generics to `getUiOptions()` * Add getTemplate() function to utils (#3018) * Moved buttons into the registry.templates under ButtonTemplates (#3014) * Moved buttons into the registry.templates under ButtonTemplates - Updated `@rjsf/utils` `types.ts` as follows: - Added two new types for buttons `SubmitButtonProps` and `IconButtonProps` - Updated `TemplatesType` to add a new `ButtonTemplates` sub-section that contains the `AddButton`, `MoveDownButton`, `MoveUpButton`, `RemoveButton` and `SubmitButton` - Update `@rjsf/core` to move the buttons into the `templates` as follows: - Moved `AddButton` into the `src/templates/ButtonTemplates` directory, fixing up the type to use as `IconButtonProps` - Moved `SubmitButton` into the `src/templates/ButtonTemplates` directory, fixing up the type to use as `SubmitButtonProps` - Moved `IconButton.js` into the `src/templates/ButtonTemplates` directory, converting it to Typescript - Also exported the `MoveDownButton`, `MoveUpButton` and `RemoveButton` components as the specific implementations of `IconButton` derived from the other templates - Updated `templates/index.ts` to create the `ButtonTemplates` inner object for `templates` - Updated `widgets/index.ts` to remove `SubmitButton` from it - Updated `WrapIfAdditional` to pull the `RemoveButton` from the `registry.templates.ButtonTemplates` and use it in place of the `IconButton` - Updated `ArrayFieldItemTemplate` to refactor the `MoveDownButton`, `MoveUpButton` and `RemoveButton`s into `IconButton`, pulling them out of `registry.templates.ButtonTemplates` - Updated `ArrayFieldTemplate` to use `AddButton` from `registry.templates.ButtonTemplates` - Updated `ObjectFieldTemplate` to use `AddButton` from `registry.templates.ButtonTemplates` - Updated `Form` to pull `SubmitButton` from `registry.templates.ButtonTemplates` - Updated the main `index.ts` file to no longer export `AddButtonProps` - Updated `@rjsf/antd` to move the buttons into the `templates` as follows: - Renamed the `SubmitButton.js` file to `index.js` to match the naming convention in the package for files, while moving it from `widget` to `templates` - Created the `IconButton/index.js` file in `src/templates` by refactoring the `AddButton`, `MoveDownButton`, `MoveUpButton` and `RemoveButton` implementations from other templates - Updated `ArrayFieldItemTemplate` to use the `MoveDownButton`, `MoveUpButton` and `RemoveButton` from `registry.templates.ButtonTemplates` - Added `title` properties on all icons, removing `Add Item` text shown to the user - Updated `ArrayFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `ObjectFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `FieldTemplate` to pass `registry` to `WrapIfAdditional` - Updated `WrapIfAdditional` to use the `RemoveButton` from `registry.templates.ButtonTemplates` - Updated the main `index.js` to properly export the `templates.ButtonTemplates` - Updated the test snapshots due to the `IconButton` refactor - Updated `@rjsf/bootstrap-4` to move the buttons into the `templates` as follows: - Updated `AddButton` to use `IconButtonProps` instead of `AddButtonProps`, adding a `title` to match core - Updated `SubmitButton` to use the `SubmitButtonProps` type - Updated `IconButton` to export `MoveDownButton`, `MoveUpButton` and `RemoveButton` components as the specific implementations of `IconButton` derived from the other templates - Updated `Templates.ts` to create the `ButtonTemplates` inner object for `templates` - Updated `Widgets.ts` to remove `SubmitButton` from it - Updated `ArrayFieldItemTemplate` to refactor the `MoveDownButton`, `MoveUpButton` and `RemoveButton`s into `IconButton`, pulling them out of `registry.templates.ButtonTemplates` - Updated `ArrayFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `ObjectFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `FieldTemplate` to pass `registry` to `WrapIfAdditional` - Updated `WrapIfAdditional` to use the `RemoveButton` from `registry.templates.ButtonTemplates` - Updated test snapshots to pick up the little differences due to the `IconButton` refactor - Also deleted the `IconButton.test.ts` because it wasn't needed - Updated `@rjsf/chakra-ui` to move the buttons into the `templates` as follows: - Updated `AddButton` to use `IconButtonProps` instead of `AddButtonProps`, moving the text to a `title` to match core - Updated `SubmitButton` to use the `SubmitButtonProps` type - Updated `IconButton` to export `MoveDownButton`, `MoveUpButton` and `RemoveButton` components as the specific implementations of `IconButton` derived from the other templates - Updated `Templates.ts` to create the `ButtonTemplates` inner object for `templates` - Updated `Widgets.ts` to remove `SubmitButton` from it - Updated `ArrayFieldItemTemplate` to refactor the `MoveDownButton`, `MoveUpButton` and `RemoveButton`s into `IconButton`, pulling them out of `registry.templates.ButtonTemplates` - Updated `ArrayFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `ObjectFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `FieldTemplate` to pass `registry` to `WrapIfAdditional` - Updated `WrapIfAdditional` to use the `RemoveButton` from `registry.templates.ButtonTemplates` - Updated test snapshots to pick up the little differences due to the `IconButton` refactor - Updated `@rjsf/fluent-ui` to move the buttons into the `templates` as follows: - Updated `AddButton` to use `IconButtonProps` instead of `AddButtonProps`, moving the text to a `title` to match core - Updated `SubmitButton` to use the `SubmitButtonProps` type - Updated `IconButton` to export `MoveDownButton`, `MoveUpButton` and `RemoveButton` components as the specific implementations of `IconButton` derived from the other templates - Updated `Templates.ts` to create the `ButtonTemplates` inner object for `templates` - Updated `Widgets.ts` to remove `SubmitButton` from it - Updated `ArrayFieldItemTemplate` to refactor the `MoveDownButton`, `MoveUpButton` and `RemoveButton`s into `IconButton`, pulling them out of `registry.templates.ButtonTemplates` - Updated `ArrayFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated test snapshots to pick up the little differences due to the `IconButton` refactor - Updated `@rjsf/material-ui` and `@rjsf/mui` to move the buttons into the `templates` as follows: - Updated `AddButton` to use `IconButtonProps` instead of `AddButtonProps`, moving the text to a `title` to match core - Updated `SubmitButton` to use the `SubmitButtonProps` type - Implemented `IconButton` to export `MoveDownButton`, `MoveUpButton` and `RemoveButton` components as the specific implementations of `IconButton` derived from the other templates - Updated `Templates.ts` to create the `ButtonTemplates` inner object for `templates` - Updated `Widgets.ts` to remove `SubmitButton` from it - Updated `ArrayFieldItemTemplate` to refactor the `MoveDownButton`, `MoveUpButton` and `RemoveButton`s into `IconButton`, pulling them out of `registry.templates.ButtonTemplates` - Updated `ArrayFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `ObjectFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `FieldTemplate` to pass `registry` to `WrapIfAdditional` - Updated `WrapIfAdditional` to use the `RemoveButton` from `registry.templates.ButtonTemplates` - Updated test snapshots to pick up the little differences due to the `IconButton` refactor - Updated `@rjsf/semantic-ui` to move the buttons into the `templates` as follows: - Updated `AddButton` moving the text to a `title` to match core - Updated `IconButton` to export `MoveDownButton`, `MoveUpButton` and `RemoveButton` components as the specific implementations of `IconButton` derived from the other templates - Updated `Templates.ts` to create the `ButtonTemplates` inner object for `templates` - Updated `Widgets.ts` to remove `SubmitButton` from it - Updated `ArrayFieldItemTemplate` to refactor the `MoveDownButton`, `MoveUpButton` and `RemoveButton`s into `IconButton`, pulling them out of `registry.templates.ButtonTemplates` - Updated `ArrayFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `ObjectFieldTemplate` to use the `AddButton` from `registry.templates.ButtonTemplates` - Updated `FieldTemplate` to pass `registry` to `WrapIfAdditional` - Updated `WrapIfAdditional` to use the `RemoveButton` from `registry.templates.ButtonTemplates` - Updated test snapshots to pick up the little differences due to the `IconButton` refactor * - Omit button templates from the extension of `TemplatesType` on `UIOptionsBaseType` * - Responded to reviewer feedback by making all buttons accessible by removing tabIndex * Bump dependencies in all packages (#3024) - Updated `package*.json` to bump to the latest minor and patch dependencies - Updated the snapshots for `mui` due to class name ordering changes from upgrade * fix(@rjsf/core): custom field that is any of displays twice (#2890) * Create playground example *Any Of with Custom Field* * Fix Bug: Custom field that is anyOf displays twice https://github.com/rjsf-team/react-jsonschema-form/issues/2691 * Update CHANGELOG.md * Avoid breaking anyOf/oneOf select with ObjectField * Verify custom field is only rendered once with anyOf/oneOf * Verify select is not rendered when custom field set * Example without imports * Cleanup * Fix merge conflict * Delete SchemaField.js * Update changelog * Run cs-format * Use ui:emptyValue for SelectWidget (#3026) * Use ui:emptyValue for SelectWidget - This is a reimplementation of https://github.com/rjsf-team/react-jsonschema-form/pull/2251 - Fixes #1041 * - Added `processSelectValue()` to `fluent-ui` for single select * - Fixed documentation for `emptyValue` * - Responded to self-feedback * Fixed Form and withTheme to properly merge ButtonTemplates (#3027) * Fixed Form and withTheme to properly merge ButtonTemplates - Updated `Form` to update the `templates` prop to make `ButtonTemplates` optional (via `Omit<>` and explicit add) - Updated the `getRegistry()` function to merge `ButtonTemplates` from `props.templates.ButtonProps` and the default `templates.ButtonProps` - Updated the `withTheme()` function to merge `ButtonTemplates` from the theme and user props - Added tests to ensure the merge is happening - Updated all the themes no longer pull the `getDefaultRegistry()` in as the registry merge happens properly in the two core components * - Responded to self-review * fix(semantic-ui): update main field (#3022) * backport PR #2631 to take into account additionalProperties set to false (#2940) * backport PR #2631 to take into account additionalProperties set to false in schema # Conflicts: # packages/utils/src/schema/toPathSchema.ts # packages/utils/test/schema/toPathSchemaTest.ts * move to fix from #2853 * fix linting error * run cs-format on modified files * Update packages/utils/src/schema/toPathSchema.ts Fix formatting (hopefully) * Update packages/utils/src/schema/toPathSchema.ts Second try fixing formatting Co-authored-by: LAUSSEL Loic INNOV/IT-S Co-authored-by: Heath C <51679588+heath-freenome@users.noreply.github.com> * Convert NullField and NumberField to functional components (#3030) - Added or updated `jest.config.js` files to all themes that add `moduleNameMapper` for `react` and `react-dom` to avoid hooks issues - Updated `NullField` and `NumberField` to be stateless functional components * Migrate altdatewidget to functional component (#3013) * Migrate core widget folder to typescript * Adressed PR feedback * Addressed additional PR comments * Migrate AltDateWidget to functional component * Add types to DateElement * Migrate filewidget to functional component (#3017) * Updated main package.json (#3033) - Bumped the dev dependencies in the main package.jsop * Setup react hooks linting (#3034) * Set up linting for react hooks * revert formatting * fix linting issues in themes * more linting issues * Improve performance by wrapping event handlers in useCallback in rjsf/core (#3035) * Implemented classNames in all theme where it was missing (#3032) - Updated the `WrapIfAdditional` component to add `classNames` to the outer wrapper in a manner consistent with the `core` theme, for the following themes: - bootstrap-4, chakra-ui, material-ui, mui and semantic-ui - Updated the snapshots to add the missing `classNames` classes * Remove enumNames (#3031) * Reimplement fix originally in #2199 (#3039) - Replicated the fix made in #2199 since it is a breaking change and we are doing a bunch of them - Also updated the `CHANGELOG.md` * Fix #2962 to properly build esm version for antd (#3044) - Updated `package*.json` to add `@rollup/plugin-replace` - Added a `dts.config.js` file that caused `antd/lib` and `rc-picker/lib` to be replaced with `antd/es` and `rc-picker/es` - Updated the `CHANGELOG.md` file for the fix * Fix hidden widget in several themes and SelectWidget in bootstrap-4 (#3036) * Fix hidden widget in several themes and SelectWidget in bootstrap-4 - Updated the `FieldTemplate` in `chakra-ui`, `material-ui`, `mui` and `semantic-ui` to properly implement the hidden field - Updated `SelectWidget` in `bootstrap-4` to fix missing `htmlFor` and the `disabled` state when `readonly` - Updated snapshots to verify fixes - Also removed the `test:update` script from `core`, `utils` and `validator-ajv6` because they are useless * - Responded to reviewer feedback * Properly pass formContext to SchemaField (#3040) * Properly pass formContext to SchemaField - Updated `ArrayField`, `MultiSchemaField`, `ObjectField` and `SchemaField` to pass `formContext` down the hierarchy properly - Updated tests to validate `formContext` is properly passed to `SchemaField` - Updated the `CHANGELOG.md` file with the fix mentioned * Update packages/core/test/allOf_test.js * Revert removing enumnames (#3042) * Feature: Add new prop duplicateKeySuffixSeparator for additionalProperties (#3048) * Fixed #1596 by adapting the fix from #2002 into rjsf v5 (#3047) * Fixed #1596 by adapting the fix from #2002 into rjsf v5 - Added a new `mergeValidationData()` method in `@rjsf/utils` to handle the appending of errors onto the end of the validationData from an additional error schema - Added this to the `schema` directory `index.ts` along with exposing it on the `SchemaUtils` type and implementation - Also fixed the type of `toErrorList()` in `ValidatorType` to change from `fieldName: string` to `fieldPath: string[]` - Added reusable `mergeValidationDataTest.ts`, calling it in the utils - Update the `@rjsf/validator-ajv6` to pick up the breaking change from #2002 around `AJV6Validator.toErrorList()` - Also modified the `validateFormData()` function to return the result of `mergeValidationData()` when the user has a custom validator - Updated tests for the new structure of the `toErrorList()` data - Also updated the `schema.tests` to add the new `mergeValidationDataTest()` - Updated `Form` to use the `mergeValidationData()` function in the few places where `extraErrors` was being merged into the schema validation - Updated tests for the new structor of the `toErrorList()` data - Updated the `CHANGELOG.md` to describe this fix - Updated the `5.x upgrade guide.md` to describe all the new utility functions added and describe util.js and validator.js breaking changes - Updated the `validation.md` documentation for the `ErrorListTemplate` change along with making the `RJSFValidationError` interface describe the optional properties * - Responded to reviewer feedback... also, removed the `:` after the property in the `stack` to match AJV stack, adding `message` to also match AJV - Added migration guide changes * Restored uiSchema.classNames with deprecation warning (#3041) * Restored uiSchema.classNames with deprecation warning - Updated `SchemaField` to restore support for `uiSchema.classNames` with big fat deprecation warning - Updated the existing `classNames` test to verify restored code and deprecation warning - NOTE: Will fix up the documentation in the other PR * - Responded to reviewer feedback * - Adjusted warning message * - Responded to reviewer feedback and updated migration guide * Reimplement #1755 and and #2460 in new Form.tsx (#3052) - Reimplement two fixes related to `onChange` in the new `Form.tsx` - #1755 fixes the calling of the proper `onChange` during props update - #2460 fixes race condition on calling `onChange` after setState. * Update documentation for template consolidation work (#3028) * Update documentation for template consolidation work - Updated the 5.x upgrade guide for the work done around template consolidation - Updated the advanced customization guides for the work done around template consolidation (slightly incomplete) - Updated the Form properties for the work done around template consolidation - Updated the UiSchema docs for the work done around template consolidation - Updated the Utililty function documentation for the work done around template consolidation - Updated the array documentation for work done around template consolidation * - Additional documentation * - More changes for CHANGELOG.md as I review issues * - Made the `classNames` change a deprecation instead of a break - Restored description of `RJSFSchema` * - Additional cleanup of documentation after closer self-review * Fixed a few warnings in material ui tests (#3054) - Changed the color for the add button from `secondary` (i.e. red) to `primary` (i.e. dark gray) in both themes - Changed the `RemoveButton` to have color `secondary` and to use the `medium` font size to avoid two errors - Updated the snapshots accordingly * Updated dependencies to latest in preparation for beta release (#3053) * Updated dependencies to latest in preparation for beta release - Also removed an extraneous console.log() from test * - Added cast to fix new Typescript error caused by the Typescript update * - Added `htmlType` to the `SubmitButton` in the `antd` theme to ensure the `type` of the HTML button is submit, consistently - Updated the snapshots accordingly * - Adding back 12.x to the `ci.yml` to allow build to be made - Also added new files to mkdocs.yml Co-authored-by: Jacques Nel Co-authored-by: Jimmy Callin Co-authored-by: Amir H. Khanjani <72540492+ahkhanjani@users.noreply.github.com> Co-authored-by: Jakob Klepp <1183303+truh@users.noreply.github.com> Co-authored-by: Bjorn Lu Co-authored-by: Laussel Loïc Co-authored-by: LAUSSEL Loic INNOV/IT-S Co-authored-by: Nick Grosenbacher --- .eslintrc-javascript | 34 + .eslintrc-typescript | 42 + .github/workflows/ci.yml | 18 +- .github/workflows/release.yml | 4 +- .gitignore | 3 + .husky/pre-commit | 5 + .node-version | 2 +- .nvmrc | 2 +- .prettierrc.yaml | 5 + CHANGELOG.md | 95 +- docs/3.x upgrade guide.md | 2 +- docs/4.x upgrade guide.md | 2 +- docs/5.x upgrade guide.md | 493 + .../custom-templates.md | 675 +- docs/advanced-customization/custom-themes.md | 31 +- .../custom-widgets-fields.md | 76 +- docs/advanced-customization/internals.md | 7 +- .../material-ui/customizing-material-ui.md | 106 - docs/api-reference/form-props.md | 76 +- .../themes/semantic-ui/uiSchema.md | 4 +- docs/api-reference/uiSchema.md | 154 +- docs/api-reference/utility-functions.md | 545 + docs/index.md | 14 +- docs/quickstart.md | 25 +- docs/usage/arrays.md | 56 +- docs/usage/definitions.md | 4 +- docs/usage/dependencies.md | 18 +- docs/usage/objects.md | 19 +- docs/usage/oneof.md | 12 +- docs/usage/single.md | 69 +- docs/usage/themes.md | 9 +- docs/usage/validation.md | 128 +- docs/usage/widgets.md | 48 +- lerna.json | 9 +- mkdocs.yml | 4 + nx.json | 36 + package-lock.json | 45097 +++++---- package.json | 51 +- packages/antd/.eslintrc | 31 +- packages/antd/README.md | 4 +- packages/antd/dts.config.js | 16 + packages/antd/jest.config.js | 6 + packages/antd/package-lock.json | 59705 +++++++----- packages/antd/package.json | 96 +- .../antd/src/components/DatePicker/index.js | 4 +- .../antd/src/fields/DescriptionField/index.js | 21 - packages/antd/src/index.js | 93 +- .../index.js} | 39 +- .../FixedArrayFieldTemplate.js | 98 - .../NormalArrayFieldTemplate.js | 98 - .../src/templates/ArrayFieldTemplate/index.js | 229 +- .../BaseInputTemplate}/index.js | 20 +- .../src/templates/DescriptionField/index.js | 9 + .../ErrorList/index.js} | 10 +- .../FieldTemplate/WrapIfAdditional.js | 29 +- .../antd/src/templates/FieldTemplate/index.js | 14 +- .../antd/src/templates/IconButton/index.js | 46 + .../templates/ObjectFieldTemplate/index.js | 98 +- .../antd/src/templates/SubmitButton/index.js | 19 + .../{fields => templates}/TitleField/index.js | 38 +- .../src/widgets/AltDateTimeWidget/index.js | 1 - .../antd/src/widgets/AltDateWidget/index.js | 12 +- .../antd/src/widgets/CheckboxWidget/index.js | 6 +- .../src/widgets/CheckboxesWidget/index.js | 7 +- .../antd/src/widgets/ColorWidget/index.js | 49 - .../antd/src/widgets/DateTimeWidget/index.js | 8 +- packages/antd/src/widgets/DateWidget/index.js | 10 +- .../antd/src/widgets/EmailWidget/index.js | 50 - .../antd/src/widgets/PasswordWidget/index.js | 10 +- .../antd/src/widgets/RadioWidget/index.js | 6 +- .../antd/src/widgets/RangeWidget/index.js | 12 +- .../antd/src/widgets/SelectWidget/index.js | 56 +- .../src/widgets/SubmitButton/SubmitButton.js | 12 - .../antd/src/widgets/SubmitButton/index.js | 2 - .../antd/src/widgets/TextareaWidget/index.js | 8 +- packages/antd/src/widgets/URLWidget/index.js | 50 - .../antd/src/widgets/UpDownWidget/index.js | 48 - packages/antd/test/Array.test.js | 55 +- packages/antd/test/Form.test.js | 275 +- packages/antd/test/Object.test.js | 27 +- .../test/__snapshots__/Array.test.js.snap | 910 +- .../antd/test/__snapshots__/Form.test.js.snap | 1682 +- .../test/__snapshots__/Object.test.js.snap | 646 +- packages/antd/webpack.config.base.js | 74 - packages/antd/webpack.config.dev.js | 18 - packages/antd/webpack.config.dist.js | 39 - packages/bootstrap-4/.eslintrc | 9 + packages/bootstrap-4/README.md | 4 +- packages/bootstrap-4/jest.config.js | 6 + packages/bootstrap-4/package-lock.json | 44513 ++++++++- packages/bootstrap-4/package.json | 67 +- .../bootstrap-4/src/AddButton/AddButton.tsx | 13 +- packages/bootstrap-4/src/AddButton/index.ts | 4 +- .../ArrayFieldItemTemplate.tsx | 73 + .../src/ArrayFieldItemTemplate/index.ts | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.tsx | 266 +- .../src/ArrayFieldTemplate/index.ts | 4 +- .../BaseInputTemplate.tsx} | 27 +- .../src/BaseInputTemplate/index.ts | 2 + .../src/CheckboxWidget/CheckboxWidget.tsx | 32 +- .../bootstrap-4/src/CheckboxWidget/index.ts | 4 +- .../src/CheckboxesWidget/CheckboxesWidget.tsx | 22 +- .../bootstrap-4/src/CheckboxesWidget/index.ts | 4 +- .../src/ColorWidget/ColorWidget.tsx | 10 - packages/bootstrap-4/src/ColorWidget/index.ts | 2 - .../src/DateTimeWidget/DateTimeWidget.tsx | 24 - .../bootstrap-4/src/DateWidget/DateWidget.tsx | 15 - .../src/DescriptionField/DescriptionField.tsx | 16 +- .../bootstrap-4/src/DescriptionField/index.ts | 4 +- .../src/EmailWidget/EmailWidget.tsx | 10 - packages/bootstrap-4/src/EmailWidget/index.ts | 2 - .../bootstrap-4/src/ErrorList/ErrorList.tsx | 4 +- packages/bootstrap-4/src/ErrorList/index.ts | 4 +- .../src/FieldTemplate/FieldTemplate.tsx | 24 +- .../src/FieldTemplate/WrapIfAdditional.tsx | 60 +- .../bootstrap-4/src/FieldTemplate/index.ts | 4 +- packages/bootstrap-4/src/Fields/Fields.ts | 7 - packages/bootstrap-4/src/Fields/index.ts | 2 - .../bootstrap-4/src/FileWidget/FileWidget.tsx | 12 +- packages/bootstrap-4/src/FileWidget/index.ts | 4 +- packages/bootstrap-4/src/Form/Form.tsx | 5 +- .../bootstrap-4/src/IconButton/IconButton.tsx | 53 +- packages/bootstrap-4/src/IconButton/index.ts | 4 +- .../ObjectFieldTemplate.tsx | 54 +- .../src/ObjectFieldTemplate/index.ts | 4 +- .../src/PasswordWidget/PasswordWidget.tsx | 55 - .../bootstrap-4/src/PasswordWidget/index.ts | 2 - .../src/RadioWidget/RadioWidget.tsx | 7 +- packages/bootstrap-4/src/RadioWidget/index.ts | 4 +- .../src/RangeWidget/RangeWidget.tsx | 59 +- packages/bootstrap-4/src/RangeWidget/index.ts | 4 +- .../src/SelectWidget/SelectWidget.tsx | 56 +- .../bootstrap-4/src/SelectWidget/index.ts | 4 +- .../src/SubmitButton/SubmitButton.tsx | 21 +- .../bootstrap-4/src/SubmitButton/index.ts | 4 +- .../bootstrap-4/src/Templates/Templates.ts | 29 + packages/bootstrap-4/src/Templates/index.ts | 2 + packages/bootstrap-4/src/TextWidget/index.ts | 2 - .../src/TextareaWidget/TextareaWidget.tsx | 8 +- .../bootstrap-4/src/TextareaWidget/index.ts | 4 +- packages/bootstrap-4/src/Theme/Theme.tsx | 22 +- packages/bootstrap-4/src/Theme/index.ts | 4 +- .../bootstrap-4/src/TitleField/TitleField.tsx | 10 +- packages/bootstrap-4/src/TitleField/index.ts | 4 +- .../bootstrap-4/src/URLWidget/URLWidget.tsx | 10 - packages/bootstrap-4/src/URLWidget/index.ts | 2 - .../src/UpDownWidget/UpDownWidget.tsx | 52 - .../bootstrap-4/src/UpDownWidget/index.ts | 2 - packages/bootstrap-4/src/Widgets/Widgets.ts | 18 - packages/bootstrap-4/src/Widgets/index.ts | 4 +- packages/bootstrap-4/src/index.ts | 4 +- .../test/AdditionalProperties.test.tsx | 30 +- packages/bootstrap-4/test/Array.test.tsx | 52 +- .../test/ArrayFieldTemplate.test.tsx | 37 - .../test/CheckboxesWidget.test.tsx | 4 +- .../bootstrap-4/test/ColorWidget.test.tsx | 13 - .../bootstrap-4/test/DateTimeWidget.test.tsx | 15 - packages/bootstrap-4/test/DateWidget.test.tsx | 13 - .../test/DescriptionField.test.tsx | 20 +- packages/bootstrap-4/test/Form.test.tsx | 226 +- packages/bootstrap-4/test/IconButton.test.tsx | 26 - packages/bootstrap-4/test/Object.test.tsx | 32 +- packages/bootstrap-4/test/TextWidget.test.tsx | 13 - packages/bootstrap-4/test/TitleField.test.tsx | 9 +- .../bootstrap-4/test/UpDownWidget.test.tsx | 13 - .../__snapshots__/AddButton.test.tsx.snap | 10 +- .../AdditionalProperties.test.tsx.snap | 220 +- .../test/__snapshots__/Array.test.tsx.snap | 715 +- .../ArrayFieldTemplate.test.tsx.snap | 71 - .../CheckboxesWidget.test.tsx.snap | 18 +- .../__snapshots__/ColorWidget.test.tsx.snap | 28 - .../DateTimeWidget.test.tsx.snap | 28 - .../__snapshots__/DateWidget.test.tsx.snap | 28 - .../DescriptionField.test.tsx.snap | 1 + .../test/__snapshots__/Form.test.tsx.snap | 1522 +- .../__snapshots__/IconButton.test.tsx.snap | 59 - .../test/__snapshots__/Object.test.tsx.snap | 311 +- .../__snapshots__/TextWidget.test.tsx.snap | 28 - .../__snapshots__/TitleField.test.tsx.snap | 1 + .../__snapshots__/UpDownWidget.test.tsx.snap | 27 - .../bootstrap-4/test/helpers/createMocks.ts | 31 +- packages/chakra-ui/.eslintrc | 9 + packages/chakra-ui/.prettierrc | 7 - packages/chakra-ui/README.md | 8 +- packages/chakra-ui/jest.config.js | 12 + packages/chakra-ui/package-lock.json | 76527 ++++++++++++++-- packages/chakra-ui/package.json | 79 +- .../chakra-ui/src/AddButton/AddButton.tsx | 8 +- .../AltDateTimeWidget/AltDateTimeWidget.tsx | 2 +- .../src/AltDateWidget/AltDateWidget.tsx | 29 +- .../ArrayFieldItemTemplate.tsx | 67 + .../src/ArrayFieldItemTemplate/index.ts | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.tsx | 270 +- .../BaseInputTemplate.tsx} | 19 +- .../chakra-ui/src/BaseInputTemplate/index.ts | 2 + .../chakra-ui/src/ChakraFrameProvider.tsx | 38 +- .../src/CheckboxWidget/CheckboxWidget.tsx | 2 +- .../src/CheckboxesWidget/CheckboxesWidget.tsx | 11 +- .../chakra-ui/src/ColorWidget/ColorWidget.tsx | 10 - packages/chakra-ui/src/ColorWidget/index.ts | 2 - .../chakra-ui/src/DateTimeWidget/index.ts | 2 - .../chakra-ui/src/DateWidget/DateWidget.tsx | 10 - packages/chakra-ui/src/DateWidget/index.ts | 2 - .../src/DescriptionField/DescriptionField.tsx | 16 +- .../chakra-ui/src/EmailWidget/EmailWidget.tsx | 10 - packages/chakra-ui/src/EmailWidget/index.ts | 2 - .../chakra-ui/src/ErrorList/ErrorList.tsx | 14 +- .../src/FieldTemplate/FieldTemplate.tsx | 6 +- .../src/FieldTemplate/WrapIfAdditional.tsx | 53 +- packages/chakra-ui/src/Fields/Fields.ts | 7 - packages/chakra-ui/src/Fields/index.ts | 2 - packages/chakra-ui/src/Form/Form.tsx | 6 +- .../chakra-ui/src/IconButton/IconButton.tsx | 45 +- .../ObjectFieldTemplate.tsx | 49 +- .../src/PasswordWidget/PasswordWidget.tsx | 10 - .../chakra-ui/src/PasswordWidget/index.ts | 2 - .../chakra-ui/src/RadioWidget/RadioWidget.tsx | 7 +- .../chakra-ui/src/RangeWidget/RangeWidget.tsx | 11 +- .../src/SelectWidget/SelectWidget.tsx | 49 +- .../src/SubmitButton/SubmitButton.tsx | 42 +- packages/chakra-ui/src/SubmitButton/index.ts | 4 +- packages/chakra-ui/src/Templates/Templates.ts | 29 + packages/chakra-ui/src/Templates/index.ts | 2 + packages/chakra-ui/src/TextWidget/index.ts | 2 - .../src/TextareaWidget/TextareaWidget.tsx | 9 +- packages/chakra-ui/src/Theme/Theme.tsx | 25 +- .../chakra-ui/src/TitleField/TitleField.tsx | 8 +- .../chakra-ui/src/URLWidget/URLWidget.tsx | 10 - packages/chakra-ui/src/URLWidget/index.ts | 2 - .../src/UpDownWidget/UpDownWidget.tsx | 9 +- packages/chakra-ui/src/Widgets/Widgets.ts | 16 - packages/chakra-ui/src/index.tsx | 12 +- packages/chakra-ui/src/utils.ts | 9 +- packages/chakra-ui/test/Array.test.tsx | 38 +- packages/chakra-ui/test/Form.test.tsx | 316 +- packages/chakra-ui/test/Object.test.tsx | 24 +- .../test/__snapshots__/Array.test.tsx.snap | 792 +- .../test/__snapshots__/Form.test.tsx.snap | 2869 +- .../test/__snapshots__/Object.test.tsx.snap | 408 +- packages/core/.editorconfig | 6 - packages/core/.eslintrc | 42 +- packages/core/README.md | 4 +- packages/core/index.d.ts | 500 - packages/core/jest.config.js | 12 +- packages/core/package-lock.json | 46427 +++++----- packages/core/package.json | 110 +- packages/core/src/components/Form.js | 562 - packages/core/src/components/Form.tsx | 792 + packages/core/src/components/IconButton.js | 13 - .../core/src/components/fields/ArrayField.js | 851 - .../core/src/components/fields/ArrayField.tsx | 866 + .../src/components/fields/BooleanField.js | 82 - .../src/components/fields/BooleanField.tsx | 107 + .../src/components/fields/MultiSchemaField.js | 204 - .../components/fields/MultiSchemaField.tsx | 233 + .../core/src/components/fields/NullField.js | 20 - .../core/src/components/fields/NullField.tsx | 20 + .../core/src/components/fields/NumberField.js | 99 - .../src/components/fields/NumberField.tsx | 84 + .../core/src/components/fields/ObjectField.js | 291 - .../src/components/fields/ObjectField.tsx | 331 + .../core/src/components/fields/SchemaField.js | 450 - .../src/components/fields/SchemaField.tsx | 390 + .../{StringField.js => StringField.tsx} | 47 +- .../core/src/components/fields/TitleField.js | 24 - .../components/fields/{index.js => index.ts} | 12 +- .../ArrayFieldDescriptionTemplate.tsx | 34 + .../templates/ArrayFieldItemTemplate.tsx | 71 + .../templates/ArrayFieldTemplate.tsx | 82 + .../templates/ArrayFieldTitleTemplate.tsx | 38 + .../templates/BaseInputTemplate.tsx | 92 + .../ButtonTemplates/AddButton.tsx} | 15 +- .../templates/ButtonTemplates/IconButton.tsx | 49 + .../ButtonTemplates/SubmitButton.tsx | 28 + .../templates/ButtonTemplates/index.ts | 15 + .../DescriptionField.tsx} | 19 +- .../{ErrorList.js => templates/ErrorList.tsx} | 10 +- .../templates/FieldTemplate/FieldTemplate.tsx | 38 + .../templates/FieldTemplate/Label.tsx | 29 + .../FieldTemplate/WrapIfAdditional.tsx | 79 + .../templates/FieldTemplate/index.ts | 3 + .../templates/ObjectFieldTemplate.tsx | 76 + .../src/components/templates/TitleField.tsx | 20 + .../UnsupportedField.tsx} | 20 +- .../core/src/components/templates/index.ts | 31 + .../components/widgets/AltDateTimeWidget.js | 26 - .../components/widgets/AltDateTimeWidget.tsx | 17 + .../src/components/widgets/AltDateWidget.js | 200 - .../src/components/widgets/AltDateWidget.tsx | 213 + .../core/src/components/widgets/BaseInput.js | 121 - .../src/components/widgets/CheckboxWidget.js | 65 - .../src/components/widgets/CheckboxWidget.tsx | 78 + .../components/widgets/CheckboxesWidget.js | 86 - .../components/widgets/CheckboxesWidget.tsx | 76 + .../src/components/widgets/ColorWidget.js | 28 - .../src/components/widgets/ColorWidget.tsx | 25 + .../src/components/widgets/DateTimeWidget.js | 29 - .../src/components/widgets/DateTimeWidget.tsx | 26 + .../core/src/components/widgets/DateWidget.js | 26 - .../src/components/widgets/DateWidget.tsx | 22 + .../src/components/widgets/EmailWidget.js | 15 - .../src/components/widgets/EmailWidget.tsx | 18 + .../core/src/components/widgets/FileWidget.js | 131 - .../src/components/widgets/FileWidget.tsx | 143 + .../src/components/widgets/HiddenWidget.js | 25 - .../src/components/widgets/HiddenWidget.tsx | 19 + .../src/components/widgets/PasswordWidget.js | 15 - .../src/components/widgets/PasswordWidget.tsx | 18 + .../src/components/widgets/RadioWidget.js | 82 - .../src/components/widgets/RadioWidget.tsx | 82 + .../src/components/widgets/RangeWidget.js | 28 - .../src/components/widgets/RangeWidget.tsx | 24 + .../src/components/widgets/SelectWidget.js | 132 - .../src/components/widgets/SelectWidget.tsx | 93 + .../src/components/widgets/SubmitButton.js | 19 - .../core/src/components/widgets/TextWidget.js | 16 - .../src/components/widgets/TextWidget.tsx | 16 + .../src/components/widgets/TextareaWidget.js | 63 - .../src/components/widgets/TextareaWidget.tsx | 62 + .../core/src/components/widgets/URLWidget.js | 15 - .../core/src/components/widgets/URLWidget.tsx | 16 + .../src/components/widgets/UpDownWidget.js | 21 - .../src/components/widgets/UpDownWidget.tsx | 18 + .../components/widgets/{index.js => index.ts} | 11 +- packages/core/src/defaultRegistry.js | 12 - packages/core/src/getDefaultRegistry.ts | 22 + packages/core/src/index.js | 12 - packages/core/src/index.ts | 8 + packages/core/src/types.js | 37 - packages/core/src/utils.js | 1366 - packages/core/src/validate.js | 316 - packages/core/src/withTheme.js | 27 - packages/core/src/withTheme.tsx | 45 + packages/core/test/ArrayFieldTemplate_test.js | 20 +- packages/core/test/ArrayField_test.js | 166 +- packages/core/test/BooleanField_test.js | 23 +- packages/core/test/DescriptionField_test.js | 2 +- packages/core/test/FieldTemplate_test.js | 12 +- packages/core/test/FormContext_test.js | 30 +- packages/core/test/Form_test.js | 268 +- packages/core/test/NumberField_test.js | 2 +- .../core/test/ObjectFieldTemplate_test.js | 40 +- packages/core/test/ObjectField_test.js | 86 +- packages/core/test/SchemaField_test.js | 132 +- packages/core/test/StringField_test.js | 94 +- packages/core/test/TitleField_test.js | 2 +- packages/core/test/allOf_test.js | 34 + packages/core/test/anyOf_test.js | 61 +- packages/core/test/oneOf_test.js | 94 +- packages/core/test/setup-jsdom.js | 7 +- packages/core/test/test_utils.js | 5 +- packages/core/test/uiSchema_test.js | 94 +- packages/core/test/utils_test.js | 4501 - packages/core/test/validate_test.js | 503 +- packages/core/test/withTheme_test.js | 99 +- packages/core/webpack.config.dist.js | 52 - packages/fluent-ui/.eslintrc | 9 + packages/fluent-ui/.gitignore | 1 - packages/fluent-ui/README.md | 4 +- packages/fluent-ui/jest.config.js | 14 +- packages/fluent-ui/package-lock.json | 45758 ++++++++- packages/fluent-ui/package.json | 71 +- .../fluent-ui/src/AddButton/AddButton.tsx | 11 +- packages/fluent-ui/src/AddButton/index.ts | 4 +- .../AltDateTimeWidget/AltDateTimeWidget.tsx | 12 - .../fluent-ui/src/AltDateTimeWidget/index.ts | 2 - .../src/AltDateWidget/AltDateWidget.tsx | 12 - packages/fluent-ui/src/AltDateWidget/index.ts | 2 - .../ArrayFieldItemTemplate.tsx | 56 + .../src/ArrayFieldItemTemplate/index.ts | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.tsx | 210 +- .../fluent-ui/src/ArrayFieldTemplate/index.ts | 4 +- .../BaseInputTemplate.tsx} | 15 +- .../fluent-ui/src/BaseInputTemplate/index.ts | 2 + .../src/CheckboxWidget/CheckboxWidget.tsx | 37 +- .../fluent-ui/src/CheckboxWidget/index.ts | 4 +- .../src/CheckboxesWidget/CheckboxesWidget.tsx | 37 +- .../fluent-ui/src/CheckboxesWidget/index.ts | 4 +- .../fluent-ui/src/ColorWidget/ColorWidget.tsx | 4 +- .../src/DateTimeWidget/DateTimeWidget.tsx | 16 +- .../fluent-ui/src/DateTimeWidget/index.ts | 4 +- .../fluent-ui/src/DateWidget/DateWidget.tsx | 31 +- packages/fluent-ui/src/DateWidget/index.ts | 4 +- .../src/DescriptionField/DescriptionField.tsx | 8 +- .../fluent-ui/src/DescriptionField/index.ts | 4 +- .../fluent-ui/src/EmailWidget/EmailWidget.tsx | 27 - packages/fluent-ui/src/EmailWidget/index.ts | 2 - .../fluent-ui/src/ErrorList/ErrorList.tsx | 5 +- packages/fluent-ui/src/ErrorList/index.ts | 4 +- .../src/FieldTemplate/FieldTemplate.tsx | 10 +- packages/fluent-ui/src/FieldTemplate/index.ts | 4 +- packages/fluent-ui/src/Fields/Fields.ts | 7 - packages/fluent-ui/src/Fields/index.ts | 2 - packages/fluent-ui/src/FuiForm/FuiForm.tsx | 8 +- packages/fluent-ui/src/FuiForm/index.ts | 4 +- .../fluent-ui/src/IconButton/IconButton.tsx | 44 +- packages/fluent-ui/src/IconButton/index.ts | 4 +- .../ObjectFieldTemplate.tsx | 34 +- .../src/ObjectFieldTemplate/index.ts | 4 +- .../src/PasswordWidget/PasswordWidget.tsx | 27 - .../fluent-ui/src/PasswordWidget/index.ts | 2 - .../fluent-ui/src/RadioWidget/RadioWidget.tsx | 24 +- packages/fluent-ui/src/RadioWidget/index.ts | 4 +- .../fluent-ui/src/RangeWidget/RangeWidget.tsx | 9 +- packages/fluent-ui/src/RangeWidget/index.ts | 4 +- .../src/SelectWidget/SelectWidget.tsx | 29 +- packages/fluent-ui/src/SelectWidget/index.ts | 4 +- .../src/SubmitButton/SubmitButton.tsx | 16 +- packages/fluent-ui/src/SubmitButton/index.ts | 4 +- packages/fluent-ui/src/Templates/Templates.ts | 29 + packages/fluent-ui/src/Templates/index.ts | 2 + packages/fluent-ui/src/TextWidget/index.ts | 2 - .../src/TextareaWidget/TextareaWidget.tsx | 26 +- .../fluent-ui/src/TextareaWidget/index.ts | 4 +- packages/fluent-ui/src/Theme/Theme.ts | 24 +- packages/fluent-ui/src/Theme/index.ts | 4 +- .../fluent-ui/src/TitleField/TitleField.tsx | 12 +- packages/fluent-ui/src/TitleField/index.ts | 4 +- .../fluent-ui/src/URLWidget/URLWidget.tsx | 27 - packages/fluent-ui/src/URLWidget/index.ts | 2 - .../src/UpDownWidget/UpDownWidget.tsx | 16 +- packages/fluent-ui/src/UpDownWidget/index.ts | 4 +- packages/fluent-ui/src/Widgets/Widgets.ts | 14 - packages/fluent-ui/src/Widgets/index.ts | 4 +- packages/fluent-ui/src/index.ts | 8 +- packages/fluent-ui/test/Array.test.tsx | 52 +- packages/fluent-ui/test/Form.test.tsx | 318 +- packages/fluent-ui/test/Object.test.tsx | 32 +- .../test/__snapshots__/Array.test.tsx.snap | 466 +- .../test/__snapshots__/Form.test.tsx.snap | 2382 +- .../test/__snapshots__/Object.test.tsx.snap | 142 +- packages/material-ui/.eslintrc | 9 + packages/material-ui/.gitignore | 1 - packages/material-ui/README.md | 122 +- packages/material-ui/jest.config.js | 6 + packages/material-ui/package-lock.json | 47534 ++++++++-- packages/material-ui/package.json | 100 +- .../material-ui/src/AddButton/AddButton.tsx | 18 +- packages/material-ui/src/AddButton/index.ts | 4 +- .../ArrayFieldItemTemplate.tsx | 69 + .../src/ArrayFieldItemTemplate/index.ts | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.tsx | 226 +- .../src/ArrayFieldTemplate/index.ts | 4 +- .../BaseInputTemplate/BaseInputTemplate.tsx | 62 + .../src/BaseInputTemplate/index.ts | 2 + .../src/CheckboxWidget/CheckboxWidget.tsx | 39 +- .../material-ui/src/CheckboxWidget/index.ts | 4 +- .../src/CheckboxesWidget/CheckboxesWidget.tsx | 50 +- .../material-ui/src/CheckboxesWidget/index.ts | 4 +- .../src/ColorWidget/ColorWidget.tsx | 10 - packages/material-ui/src/ColorWidget/index.ts | 2 - .../src/DateTimeWidget/DateTimeWidget.tsx | 17 +- .../material-ui/src/DateWidget/DateWidget.tsx | 14 +- .../src/DescriptionField/DescriptionField.tsx | 12 +- .../material-ui/src/DescriptionField/index.ts | 4 +- .../src/EmailWidget/EmailWidget.tsx | 10 - packages/material-ui/src/EmailWidget/index.ts | 2 - .../material-ui/src/ErrorList/ErrorList.tsx | 15 +- packages/material-ui/src/ErrorList/index.ts | 4 +- .../src/FieldTemplate/FieldTemplate.tsx | 23 +- .../src/FieldTemplate/WrapIfAdditional.tsx | 74 +- .../material-ui/src/FieldTemplate/index.ts | 4 +- packages/material-ui/src/Fields/Fields.ts | 7 - packages/material-ui/src/Fields/index.ts | 2 - .../material-ui/src/IconButton/IconButton.tsx | 55 + packages/material-ui/src/IconButton/index.ts | 2 + .../MuiComponentContext.tsx | 8 - .../src/MuiComponentContext/index.ts | 3 - .../MuiComponentContext/useMuiComponent.ts | 16 - packages/material-ui/src/MuiForm/MuiForm.tsx | 8 +- packages/material-ui/src/MuiForm/index.ts | 4 +- .../material-ui/src/MuiForm5/MuiForm5.tsx | 8 - packages/material-ui/src/MuiForm5/index.ts | 2 - .../ObjectFieldTemplate.tsx | 61 +- .../src/ObjectFieldTemplate/index.ts | 4 +- .../src/PasswordWidget/PasswordWidget.tsx | 11 - .../material-ui/src/PasswordWidget/index.ts | 2 - .../src/RadioWidget/RadioWidget.tsx | 25 +- packages/material-ui/src/RadioWidget/index.ts | 4 +- .../src/RangeWidget/RangeWidget.tsx | 26 +- packages/material-ui/src/RangeWidget/index.ts | 4 +- .../src/SelectWidget/SelectWidget.tsx | 66 +- .../material-ui/src/SelectWidget/index.ts | 4 +- .../src/SubmitButton/SubmitButton.tsx | 28 +- .../material-ui/src/SubmitButton/index.ts | 4 +- .../material-ui/src/Templates/Templates.ts | 29 + packages/material-ui/src/Templates/index.ts | 2 + .../material-ui/src/TextWidget/TextWidget.tsx | 58 - packages/material-ui/src/TextWidget/index.ts | 2 - .../src/TextareaWidget/TextareaWidget.tsx | 54 +- .../material-ui/src/TextareaWidget/index.ts | 4 +- .../src/Theme/MaterialUIContext.tsx | 108 - .../src/Theme/MaterialUIContextProps.ts | 60 - packages/material-ui/src/Theme/Theme.tsx | 35 +- packages/material-ui/src/Theme/index.ts | 4 +- .../material-ui/src/Theme5/Mui5Context.tsx | 108 - .../src/Theme5/Mui5ContextProps.ts | 60 - packages/material-ui/src/Theme5/Theme5.tsx | 34 - packages/material-ui/src/Theme5/index.ts | 2 - packages/material-ui/src/ThemeCommon/index.ts | 23 - .../material-ui/src/TitleField/TitleField.tsx | 14 +- packages/material-ui/src/TitleField/index.ts | 4 +- .../material-ui/src/URLWidget/URLWidget.tsx | 10 - packages/material-ui/src/URLWidget/index.ts | 2 - .../src/UpDownWidget/UpDownWidget.tsx | 41 - .../material-ui/src/UpDownWidget/index.ts | 2 - packages/material-ui/src/Widgets/Widgets.ts | 14 - packages/material-ui/src/Widgets/index.ts | 4 +- packages/material-ui/src/index.ts | 19 +- packages/material-ui/src/v4.ts | 14 - packages/material-ui/src/v5.ts | 13 - packages/material-ui/test/Array.test.tsx | 46 +- packages/material-ui/test/Form.test.tsx | 254 +- packages/material-ui/test/Object.test.tsx | 26 +- .../material-ui/test/UpDownWidget.test.tsx | 54 - .../test/__snapshots__/Array.test.tsx.snap | 997 +- .../test/__snapshots__/Form.test.tsx.snap | 2228 +- .../test/__snapshots__/Object.test.tsx.snap | 382 +- .../__snapshots__/UpDownWidget.test.tsx.snap | 41 - packages/material-ui/test/mui-5/Form.test.tsx | 242 - .../material-ui/test/mui-5/Object.test.tsx | 30 - .../test/mui-5/UpDownWidget.test.tsx | 54 - .../mui-5/__snapshots__/Array.test.tsx.snap | 892 - .../mui-5/__snapshots__/Form.test.tsx.snap | 1917 - .../mui-5/__snapshots__/Object.test.tsx.snap | 414 - .../__snapshots__/UpDownWidget.test.tsx.snap | 58 - packages/material-ui/tsdx.config.js | 92 - packages/mui/.eslintrc | 9 + packages/mui/README.md | 137 + packages/mui/babel.config.js | 3 + packages/mui/jest.config.js | 15 + packages/mui/logo.png | Bin 0 -> 82145 bytes packages/mui/package-lock.json | 47200 ++++++++++ packages/mui/package.json | 88 + .../screenshot5.png => mui/screenshot.png} | Bin packages/mui/src/AddButton/AddButton.tsx | 14 + packages/mui/src/AddButton/index.ts | 2 + .../ArrayFieldItemTemplate.tsx | 68 + .../mui/src/ArrayFieldItemTemplate/index.ts | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.tsx | 89 + packages/mui/src/ArrayFieldTemplate/index.ts | 2 + .../BaseInputTemplate/BaseInputTemplate.tsx | 62 + packages/mui/src/BaseInputTemplate/index.ts | 2 + .../mui/src/CheckboxWidget/CheckboxWidget.tsx | 51 + packages/mui/src/CheckboxWidget/index.ts | 2 + .../src/CheckboxesWidget/CheckboxesWidget.tsx | 90 + packages/mui/src/CheckboxesWidget/index.ts | 2 + .../src/DateTimeWidget/DateTimeWidget.tsx | 17 +- .../src/DateTimeWidget/index.ts | 0 packages/mui/src/DateWidget/DateWidget.tsx | 22 + .../src/DateWidget/index.ts | 0 .../src/DescriptionField/DescriptionField.tsx | 17 + packages/mui/src/DescriptionField/index.ts | 2 + packages/mui/src/ErrorList/ErrorList.tsx | 34 + packages/mui/src/ErrorList/index.ts | 2 + .../mui/src/FieldTemplate/FieldTemplate.tsx | 73 + .../src/FieldTemplate/WrapIfAdditional.tsx | 88 + packages/mui/src/FieldTemplate/index.ts | 2 + packages/mui/src/IconButton/IconButton.tsx | 55 + packages/mui/src/IconButton/index.ts | 2 + packages/mui/src/MuiForm/MuiForm.tsx | 8 + packages/mui/src/MuiForm/index.ts | 2 + .../ObjectFieldTemplate.tsx | 90 + packages/mui/src/ObjectFieldTemplate/index.ts | 2 + packages/mui/src/RadioWidget/RadioWidget.tsx | 67 + packages/mui/src/RadioWidget/index.ts | 2 + packages/mui/src/RangeWidget/RangeWidget.tsx | 47 + packages/mui/src/RangeWidget/index.ts | 2 + .../mui/src/SelectWidget/SelectWidget.tsx | 70 + packages/mui/src/SelectWidget/index.ts | 2 + .../mui/src/SubmitButton/SubmitButton.tsx | 29 + packages/mui/src/SubmitButton/index.ts | 2 + packages/mui/src/Templates/Templates.ts | 29 + packages/mui/src/Templates/index.ts | 2 + .../mui/src/TextareaWidget/TextareaWidget.tsx | 20 + packages/mui/src/TextareaWidget/index.ts | 2 + packages/mui/src/Theme/Theme.tsx | 11 + packages/mui/src/Theme/index.ts | 2 + packages/mui/src/TitleField/TitleField.tsx | 16 + packages/mui/src/TitleField/index.ts | 2 + packages/mui/src/Widgets/Widgets.ts | 19 + packages/mui/src/Widgets/index.ts | 2 + packages/mui/src/index.ts | 8 + .../test/mui-5 => mui/test}/Array.test.tsx | 46 +- packages/mui/test/Form.test.tsx | 411 + packages/mui/test/Object.test.tsx | 34 + .../test/__snapshots__/Array.test.tsx.snap | 2804 + .../mui/test/__snapshots__/Form.test.tsx.snap | 10976 +++ .../test/__snapshots__/Object.test.tsx.snap | 1702 + packages/mui/tsconfig.json | 12 + packages/playground/.babelrc | 11 +- packages/playground/.eslintrc | 42 +- packages/playground/.npmrc | 2 + packages/playground/package-lock.json | 45260 +++------ packages/playground/package.json | 147 +- packages/playground/src/DemoFrame.js | 2 +- packages/playground/src/app.js | 185 +- packages/playground/src/index.js | 47 +- .../playground/src/samples/alternatives.js | 7 +- .../playground/src/samples/customArray.js | 8 +- .../src/samples/customFieldAnyOf.js | 112 + .../playground/src/samples/customObject.js | 5 +- packages/playground/src/samples/index.js | 2 + .../src/samples/propertyDependencies.js | 6 +- .../src/samples/schemaDependencies.js | 3 +- packages/playground/src/samples/validation.js | 2 +- packages/playground/src/samples/widgets.js | 20 +- packages/playground/webpack.config.dev.js | 19 +- packages/playground/webpack.config.dist.js | 10 +- packages/playground/webpack.config.prod.js | 12 +- packages/semantic-ui/.editorconfig | 6 - packages/semantic-ui/.eslintrc | 50 +- packages/semantic-ui/README.md | 6 +- packages/semantic-ui/jest.config.js | 6 + packages/semantic-ui/package-lock.json | 70457 +++++++------- packages/semantic-ui/package.json | 101 +- .../semantic-ui/src/AddButton/AddButton.js | 3 +- packages/semantic-ui/src/AddButton/index.js | 4 +- .../ArrayFieldItemTemplate.js | 87 + .../src/ArrayFieldItemTemplate/index.js | 2 + .../ArrayFieldTemplate/ArrayFieldTemplate.js | 252 +- .../src/ArrayFieldTemplate/index.js | 4 +- .../BaseInputTemplate.js} | 30 +- .../src/BaseInputTemplate/index.js | 3 + .../src/CheckboxWidget/CheckboxWidget.js | 15 +- .../semantic-ui/src/CheckboxWidget/index.js | 4 +- .../src/CheckboxesWidget/CheckboxesWidget.js | 23 +- .../semantic-ui/src/CheckboxesWidget/index.js | 4 +- .../src/DateTimeWidget/DateTimeWidget.js | 60 - .../semantic-ui/src/DateTimeWidget/index.js | 2 - .../semantic-ui/src/DateWidget/DateWidget.js | 58 - packages/semantic-ui/src/DateWidget/index.js | 2 - .../src/DescriptionField/DescriptionField.js | 8 +- .../semantic-ui/src/DescriptionField/index.js | 4 +- .../src/EmailWidget/EmailWidget.js | 59 - packages/semantic-ui/src/EmailWidget/index.js | 2 - packages/semantic-ui/src/ErrorList/index.js | 4 +- .../src/FieldTemplate/FieldTemplate.js | 31 +- .../src/FieldTemplate/WrapIfAdditional.js | 80 +- .../semantic-ui/src/FieldTemplate/index.js | 4 +- packages/semantic-ui/src/Fields/Fields.js | 7 - packages/semantic-ui/src/Fields/index.js | 3 - packages/semantic-ui/src/HelpField/index.js | 4 +- .../semantic-ui/src/IconButton/IconButton.js | 24 +- packages/semantic-ui/src/IconButton/index.js | 4 +- .../ObjectFieldTemplate.js | 46 +- .../src/ObjectFieldTemplate/index.js | 4 +- .../src/PasswordWidget/PasswordWidget.js | 60 - .../semantic-ui/src/PasswordWidget/index.js | 3 - .../src/RadioWidget/RadioWidget.js | 20 +- packages/semantic-ui/src/RadioWidget/index.js | 4 +- .../src/RangeWidget/RangeWidget.js | 21 +- packages/semantic-ui/src/RangeWidget/index.js | 4 +- .../semantic-ui/src/RawErrors/RawErrors.js | 9 +- packages/semantic-ui/src/RawErrors/index.js | 4 +- .../src/SelectWidget/SelectWidget.js | 49 +- .../semantic-ui/src/SelectWidget/index.js | 4 +- .../src/SemanticUIForm/SemanticUIForm.js | 2 +- .../semantic-ui/src/SemanticUIForm/index.js | 4 +- .../src/SubmitButton/SubmitButton.js | 23 +- .../semantic-ui/src/SubmitButton/index.js | 4 +- .../semantic-ui/src/Templates/Templates.js | 29 + packages/semantic-ui/src/Templates/index.js | 3 + packages/semantic-ui/src/TextWidget/index.js | 3 - .../src/TextareaWidget/TextareaWidget.js | 15 +- packages/semantic-ui/src/Theme/Theme.js | 17 +- packages/semantic-ui/src/Theme/index.js | 4 +- .../semantic-ui/src/TitleField/TitleField.js | 29 +- packages/semantic-ui/src/TitleField/index.js | 4 +- .../semantic-ui/src/URLWidget/URLWidget.js | 58 - packages/semantic-ui/src/URLWidget/index.js | 2 - .../src/UpDownWidget/UpDownWidget.js | 60 - .../semantic-ui/src/UpDownWidget/index.js | 3 - packages/semantic-ui/src/Widgets/Widgets.js | 16 - packages/semantic-ui/src/Widgets/index.js | 4 +- packages/semantic-ui/src/index.js | 13 +- packages/semantic-ui/src/util.js | 30 +- packages/semantic-ui/test/Array.test.js | 44 +- packages/semantic-ui/test/Form.test.js | 366 +- packages/semantic-ui/test/Object.test.js | 28 +- .../test/__snapshots__/Array.test.js.snap | 565 +- .../test/__snapshots__/Form.test.js.snap | 1572 +- .../test/__snapshots__/Object.test.js.snap | 246 +- packages/semantic-ui/test/util.test.js | 155 +- packages/utils/.eslintrc | 9 + packages/utils/README.md | 106 + packages/utils/babel.config.js | 3 + packages/utils/jest.config.js | 31 + packages/utils/logo.png | Bin 0 -> 82145 bytes packages/utils/package-lock.json | 17728 ++++ packages/utils/package.json | 78 + packages/utils/src/allowAdditionalItems.ts | 15 + packages/utils/src/asNumber.ts | 38 + packages/utils/src/canExpand.ts | 31 + packages/utils/src/constants.ts | 27 + packages/utils/src/createSchemaUtils.ts | 252 + packages/utils/src/dataURItoBlob.ts | 38 + packages/utils/src/deepEquals.ts | 19 + packages/utils/src/findSchemaDefinition.ts | 57 + packages/utils/src/getInputProps.ts | 51 + packages/utils/src/getSchemaType.ts | 37 + packages/utils/src/getSubmitButtonOptions.ts | 32 + packages/utils/src/getTemplate.ts | 25 + packages/utils/src/getUiOptions.ts | 29 + packages/utils/src/getWidget.tsx | 131 + packages/utils/src/guessType.ts | 28 + packages/utils/src/hasWidget.ts | 31 + packages/utils/src/index.ts | 76 + packages/utils/src/isConstant.ts | 15 + packages/utils/src/isCustomWidget.ts | 18 + packages/utils/src/isFixedItems.ts | 16 + packages/utils/src/isObject.ts | 12 + packages/utils/src/localToUTC.ts | 8 + .../utils/src/mergeDefaultsWithFormData.ts | 45 + packages/utils/src/mergeObjects.ts | 28 + packages/utils/src/mergeSchemas.ts | 41 + packages/utils/src/optionsList.ts | 45 + packages/utils/src/orderProperties.ts | 53 + packages/utils/src/pad.ts | 13 + packages/utils/src/parseDateString.ts | 36 + packages/utils/src/processSelectValue.ts | 51 + packages/utils/src/rangeSpec.ts | 22 + .../utils/src/schema/getDefaultFormState.ts | 291 + packages/utils/src/schema/getDisplayLabel.ts | 46 + .../utils/src/schema/getMatchingOption.ts | 74 + packages/utils/src/schema/index.ts | 23 + packages/utils/src/schema/isFilesArray.ts | 31 + packages/utils/src/schema/isMultiSelect.ts | 25 + packages/utils/src/schema/isSelect.ts | 28 + .../utils/src/schema/mergeValidationData.ts | 36 + packages/utils/src/schema/retrieveSchema.ts | 508 + packages/utils/src/schema/toIdSchema.ts | 78 + packages/utils/src/schema/toPathSchema.ts | 74 + packages/utils/src/schemaRequiresTrueValue.ts | 41 + packages/utils/src/shouldRender.ts | 20 + packages/utils/src/toConstant.ts | 23 + packages/utils/src/toDateString.ts | 15 + packages/utils/src/types.ts | 862 + packages/utils/src/utcToLocal.ts | 30 + packages/utils/test/.eslintrc | 16 + .../utils/test/allowAdditionalItems.test.ts | 32 + packages/utils/test/asNumber.test.ts | 45 + packages/utils/test/canExpand.test.ts | 49 + packages/utils/test/createSchemaUtils.test.ts | 50 + packages/utils/test/dataURItoBlob.test.ts | 28 + packages/utils/test/deepEquals.test.ts | 15 + .../utils/test/findSchemaDefinition.test.ts | 52 + packages/utils/test/getInputProps.test.ts | 67 + packages/utils/test/getSchemaType.test.ts | 79 + .../utils/test/getSubmitButtonOptions.test.ts | 56 + packages/utils/test/getTemplate.test.ts | 95 + packages/utils/test/getUiOptions.test.ts | 69 + packages/utils/test/getWidget.test.tsx | 160 + packages/utils/test/guessType.test.ts | 31 + packages/utils/test/hasWidget.test.ts | 38 + packages/utils/test/isConstant.test.ts | 23 + packages/utils/test/isCustomWidget.test.ts | 13 + packages/utils/test/isFixedItems.test.ts | 16 + packages/utils/test/localToUTC.test.ts | 10 + .../test/mergeDefaultsWithFormData.test.ts | 92 + packages/utils/test/mergeObjects.test.ts | 91 + packages/utils/test/mergeSchemas.test.ts | 121 + packages/utils/test/optionsList.test.ts | 107 + packages/utils/test/orderProperties.test.ts | 58 + packages/utils/test/pad.test.ts | 10 + packages/utils/test/parseDateString.test.ts | 51 + .../utils/test/processSelectValue.test.ts | 107 + packages/utils/test/rangeSpec.test.ts | 20 + packages/utils/test/schema.test.ts | 26 + .../test/schema/getDefaultFormStateTest.ts | 1201 + .../utils/test/schema/getDisplayLabelTest.ts | 69 + .../test/schema/getMatchingOptionTest.ts | 118 + packages/utils/test/schema/index.ts | 25 + .../utils/test/schema/isFilesArrayTest.ts | 28 + .../utils/test/schema/isMultiSelectTest.ts | 67 + packages/utils/test/schema/isSelectTest.ts | 38 + .../test/schema/mergeValidationDataTest.ts | 64 + .../utils/test/schema/retrieveSchemaTest.ts | 1603 + packages/utils/test/schema/toIdSchemaTest.ts | 303 + .../utils/test/schema/toPathSchemaTest.ts | 615 + packages/utils/test/schema/types.ts | 12 + .../test/schemaRequiresTrueValue.test.ts | 79 + packages/utils/test/shouldRender.test.tsx | 109 + .../utils/test/testUtils/getTestValidator.ts | 62 + packages/utils/test/toConstant.test.ts | 22 + packages/utils/test/toDateString.test.ts | 29 + packages/utils/test/utcToLocal.test.ts | 31 + packages/utils/tsconfig.json | 12 + packages/validator-ajv6/.eslintrc | 9 + packages/validator-ajv6/README.md | 191 + packages/validator-ajv6/babel.config.js | 3 + packages/validator-ajv6/jest.config.js | 31 + packages/validator-ajv6/logo.png | Bin 0 -> 82145 bytes packages/validator-ajv6/package-lock.json | 26387 ++++++ packages/validator-ajv6/package.json | 75 + .../validator-ajv6/src/createAjvInstance.ts | 52 + .../validator-ajv6/src/customizeValidator.ts | 15 + packages/validator-ajv6/src/index.ts | 6 + packages/validator-ajv6/src/types.ts | 14 + packages/validator-ajv6/src/validator.ts | 378 + packages/validator-ajv6/test/.eslintrc | 16 + .../test/createAjvInstance.test.ts | 109 + .../test/customizeValidator.test.ts | 32 + .../test/utilsTests/getTestValidator.ts | 43 + .../test/utilsTests/schema.test.ts | 27 + .../validator-ajv6/test/validator.test.ts | 549 + packages/validator-ajv6/tsconfig.json | 12 + tsconfig.base.json | 2 +- 808 files changed, 477394 insertions(+), 178811 deletions(-) create mode 100644 .eslintrc-javascript create mode 100644 .eslintrc-typescript create mode 100755 .husky/pre-commit create mode 100644 .prettierrc.yaml create mode 100644 docs/5.x upgrade guide.md delete mode 100644 docs/advanced-customization/material-ui/customizing-material-ui.md create mode 100644 docs/api-reference/utility-functions.md create mode 100644 nx.json create mode 100644 packages/antd/dts.config.js create mode 100644 packages/antd/jest.config.js delete mode 100644 packages/antd/src/fields/DescriptionField/index.js rename packages/antd/src/templates/{ArrayFieldTemplate/ArrayFieldTemplateItem.js => ArrayFieldItemTemplate/index.js} (58%) delete mode 100644 packages/antd/src/templates/ArrayFieldTemplate/FixedArrayFieldTemplate.js delete mode 100644 packages/antd/src/templates/ArrayFieldTemplate/NormalArrayFieldTemplate.js rename packages/antd/src/{widgets/TextWidget => templates/BaseInputTemplate}/index.js (74%) create mode 100644 packages/antd/src/templates/DescriptionField/index.js rename packages/antd/src/{ErrorList.js => templates/ErrorList/index.js} (73%) create mode 100644 packages/antd/src/templates/IconButton/index.js create mode 100644 packages/antd/src/templates/SubmitButton/index.js rename packages/antd/src/{fields => templates}/TitleField/index.js (51%) delete mode 100644 packages/antd/src/widgets/ColorWidget/index.js delete mode 100644 packages/antd/src/widgets/EmailWidget/index.js delete mode 100644 packages/antd/src/widgets/SubmitButton/SubmitButton.js delete mode 100644 packages/antd/src/widgets/SubmitButton/index.js delete mode 100644 packages/antd/src/widgets/URLWidget/index.js delete mode 100644 packages/antd/src/widgets/UpDownWidget/index.js delete mode 100644 packages/antd/webpack.config.base.js delete mode 100644 packages/antd/webpack.config.dev.js delete mode 100644 packages/antd/webpack.config.dist.js create mode 100644 packages/bootstrap-4/.eslintrc create mode 100644 packages/bootstrap-4/jest.config.js create mode 100644 packages/bootstrap-4/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx create mode 100644 packages/bootstrap-4/src/ArrayFieldItemTemplate/index.ts rename packages/bootstrap-4/src/{TextWidget/TextWidget.tsx => BaseInputTemplate/BaseInputTemplate.tsx} (74%) create mode 100644 packages/bootstrap-4/src/BaseInputTemplate/index.ts delete mode 100644 packages/bootstrap-4/src/ColorWidget/ColorWidget.tsx delete mode 100644 packages/bootstrap-4/src/ColorWidget/index.ts delete mode 100644 packages/bootstrap-4/src/DateTimeWidget/DateTimeWidget.tsx delete mode 100644 packages/bootstrap-4/src/DateWidget/DateWidget.tsx delete mode 100644 packages/bootstrap-4/src/EmailWidget/EmailWidget.tsx delete mode 100644 packages/bootstrap-4/src/EmailWidget/index.ts delete mode 100644 packages/bootstrap-4/src/Fields/Fields.ts delete mode 100644 packages/bootstrap-4/src/Fields/index.ts delete mode 100644 packages/bootstrap-4/src/PasswordWidget/PasswordWidget.tsx delete mode 100644 packages/bootstrap-4/src/PasswordWidget/index.ts create mode 100644 packages/bootstrap-4/src/Templates/Templates.ts create mode 100644 packages/bootstrap-4/src/Templates/index.ts delete mode 100644 packages/bootstrap-4/src/TextWidget/index.ts delete mode 100644 packages/bootstrap-4/src/URLWidget/URLWidget.tsx delete mode 100644 packages/bootstrap-4/src/URLWidget/index.ts delete mode 100644 packages/bootstrap-4/src/UpDownWidget/UpDownWidget.tsx delete mode 100644 packages/bootstrap-4/src/UpDownWidget/index.ts delete mode 100644 packages/bootstrap-4/test/ArrayFieldTemplate.test.tsx delete mode 100644 packages/bootstrap-4/test/ColorWidget.test.tsx delete mode 100644 packages/bootstrap-4/test/DateTimeWidget.test.tsx delete mode 100644 packages/bootstrap-4/test/DateWidget.test.tsx delete mode 100644 packages/bootstrap-4/test/IconButton.test.tsx delete mode 100644 packages/bootstrap-4/test/TextWidget.test.tsx delete mode 100644 packages/bootstrap-4/test/UpDownWidget.test.tsx delete mode 100644 packages/bootstrap-4/test/__snapshots__/ArrayFieldTemplate.test.tsx.snap delete mode 100644 packages/bootstrap-4/test/__snapshots__/ColorWidget.test.tsx.snap delete mode 100644 packages/bootstrap-4/test/__snapshots__/DateTimeWidget.test.tsx.snap delete mode 100644 packages/bootstrap-4/test/__snapshots__/DateWidget.test.tsx.snap delete mode 100644 packages/bootstrap-4/test/__snapshots__/IconButton.test.tsx.snap delete mode 100644 packages/bootstrap-4/test/__snapshots__/TextWidget.test.tsx.snap delete mode 100644 packages/bootstrap-4/test/__snapshots__/UpDownWidget.test.tsx.snap create mode 100644 packages/chakra-ui/.eslintrc delete mode 100644 packages/chakra-ui/.prettierrc create mode 100644 packages/chakra-ui/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx create mode 100644 packages/chakra-ui/src/ArrayFieldItemTemplate/index.ts rename packages/chakra-ui/src/{TextWidget/TextWidget.tsx => BaseInputTemplate/BaseInputTemplate.tsx} (83%) create mode 100644 packages/chakra-ui/src/BaseInputTemplate/index.ts delete mode 100644 packages/chakra-ui/src/ColorWidget/ColorWidget.tsx delete mode 100644 packages/chakra-ui/src/ColorWidget/index.ts delete mode 100644 packages/chakra-ui/src/DateTimeWidget/index.ts delete mode 100644 packages/chakra-ui/src/DateWidget/DateWidget.tsx delete mode 100644 packages/chakra-ui/src/DateWidget/index.ts delete mode 100644 packages/chakra-ui/src/EmailWidget/EmailWidget.tsx delete mode 100644 packages/chakra-ui/src/EmailWidget/index.ts delete mode 100644 packages/chakra-ui/src/Fields/Fields.ts delete mode 100644 packages/chakra-ui/src/Fields/index.ts delete mode 100644 packages/chakra-ui/src/PasswordWidget/PasswordWidget.tsx delete mode 100644 packages/chakra-ui/src/PasswordWidget/index.ts create mode 100644 packages/chakra-ui/src/Templates/Templates.ts create mode 100644 packages/chakra-ui/src/Templates/index.ts delete mode 100644 packages/chakra-ui/src/TextWidget/index.ts delete mode 100644 packages/chakra-ui/src/URLWidget/URLWidget.tsx delete mode 100644 packages/chakra-ui/src/URLWidget/index.ts delete mode 100644 packages/core/.editorconfig delete mode 100644 packages/core/index.d.ts delete mode 100644 packages/core/src/components/Form.js create mode 100644 packages/core/src/components/Form.tsx delete mode 100644 packages/core/src/components/IconButton.js delete mode 100644 packages/core/src/components/fields/ArrayField.js create mode 100644 packages/core/src/components/fields/ArrayField.tsx delete mode 100644 packages/core/src/components/fields/BooleanField.js create mode 100644 packages/core/src/components/fields/BooleanField.tsx delete mode 100644 packages/core/src/components/fields/MultiSchemaField.js create mode 100644 packages/core/src/components/fields/MultiSchemaField.tsx delete mode 100644 packages/core/src/components/fields/NullField.js create mode 100644 packages/core/src/components/fields/NullField.tsx delete mode 100644 packages/core/src/components/fields/NumberField.js create mode 100644 packages/core/src/components/fields/NumberField.tsx delete mode 100644 packages/core/src/components/fields/ObjectField.js create mode 100644 packages/core/src/components/fields/ObjectField.tsx delete mode 100644 packages/core/src/components/fields/SchemaField.js create mode 100644 packages/core/src/components/fields/SchemaField.tsx rename packages/core/src/components/fields/{StringField.js => StringField.tsx} (57%) delete mode 100644 packages/core/src/components/fields/TitleField.js rename packages/core/src/components/fields/{index.js => index.ts} (70%) create mode 100644 packages/core/src/components/templates/ArrayFieldDescriptionTemplate.tsx create mode 100644 packages/core/src/components/templates/ArrayFieldItemTemplate.tsx create mode 100644 packages/core/src/components/templates/ArrayFieldTemplate.tsx create mode 100644 packages/core/src/components/templates/ArrayFieldTitleTemplate.tsx create mode 100644 packages/core/src/components/templates/BaseInputTemplate.tsx rename packages/core/src/components/{AddButton.js => templates/ButtonTemplates/AddButton.tsx} (56%) create mode 100644 packages/core/src/components/templates/ButtonTemplates/IconButton.tsx create mode 100644 packages/core/src/components/templates/ButtonTemplates/SubmitButton.tsx create mode 100644 packages/core/src/components/templates/ButtonTemplates/index.ts rename packages/core/src/components/{fields/DescriptionField.js => templates/DescriptionField.tsx} (54%) rename packages/core/src/components/{ErrorList.js => templates/ErrorList.tsx} (50%) create mode 100644 packages/core/src/components/templates/FieldTemplate/FieldTemplate.tsx create mode 100644 packages/core/src/components/templates/FieldTemplate/Label.tsx create mode 100644 packages/core/src/components/templates/FieldTemplate/WrapIfAdditional.tsx create mode 100644 packages/core/src/components/templates/FieldTemplate/index.ts create mode 100644 packages/core/src/components/templates/ObjectFieldTemplate.tsx create mode 100644 packages/core/src/components/templates/TitleField.tsx rename packages/core/src/components/{fields/UnsupportedField.js => templates/UnsupportedField.tsx} (53%) create mode 100644 packages/core/src/components/templates/index.ts delete mode 100644 packages/core/src/components/widgets/AltDateTimeWidget.js create mode 100644 packages/core/src/components/widgets/AltDateTimeWidget.tsx delete mode 100644 packages/core/src/components/widgets/AltDateWidget.js create mode 100644 packages/core/src/components/widgets/AltDateWidget.tsx delete mode 100644 packages/core/src/components/widgets/BaseInput.js delete mode 100644 packages/core/src/components/widgets/CheckboxWidget.js create mode 100644 packages/core/src/components/widgets/CheckboxWidget.tsx delete mode 100644 packages/core/src/components/widgets/CheckboxesWidget.js create mode 100644 packages/core/src/components/widgets/CheckboxesWidget.tsx delete mode 100644 packages/core/src/components/widgets/ColorWidget.js create mode 100644 packages/core/src/components/widgets/ColorWidget.tsx delete mode 100644 packages/core/src/components/widgets/DateTimeWidget.js create mode 100644 packages/core/src/components/widgets/DateTimeWidget.tsx delete mode 100644 packages/core/src/components/widgets/DateWidget.js create mode 100644 packages/core/src/components/widgets/DateWidget.tsx delete mode 100644 packages/core/src/components/widgets/EmailWidget.js create mode 100644 packages/core/src/components/widgets/EmailWidget.tsx delete mode 100644 packages/core/src/components/widgets/FileWidget.js create mode 100644 packages/core/src/components/widgets/FileWidget.tsx delete mode 100644 packages/core/src/components/widgets/HiddenWidget.js create mode 100644 packages/core/src/components/widgets/HiddenWidget.tsx delete mode 100644 packages/core/src/components/widgets/PasswordWidget.js create mode 100644 packages/core/src/components/widgets/PasswordWidget.tsx delete mode 100644 packages/core/src/components/widgets/RadioWidget.js create mode 100644 packages/core/src/components/widgets/RadioWidget.tsx delete mode 100644 packages/core/src/components/widgets/RangeWidget.js create mode 100644 packages/core/src/components/widgets/RangeWidget.tsx delete mode 100644 packages/core/src/components/widgets/SelectWidget.js create mode 100644 packages/core/src/components/widgets/SelectWidget.tsx delete mode 100644 packages/core/src/components/widgets/SubmitButton.js delete mode 100644 packages/core/src/components/widgets/TextWidget.js create mode 100644 packages/core/src/components/widgets/TextWidget.tsx delete mode 100644 packages/core/src/components/widgets/TextareaWidget.js create mode 100644 packages/core/src/components/widgets/TextareaWidget.tsx delete mode 100644 packages/core/src/components/widgets/URLWidget.js create mode 100644 packages/core/src/components/widgets/URLWidget.tsx delete mode 100644 packages/core/src/components/widgets/UpDownWidget.js create mode 100644 packages/core/src/components/widgets/UpDownWidget.tsx rename packages/core/src/components/widgets/{index.js => index.ts} (89%) delete mode 100644 packages/core/src/defaultRegistry.js create mode 100644 packages/core/src/getDefaultRegistry.ts delete mode 100644 packages/core/src/index.js create mode 100644 packages/core/src/index.ts delete mode 100644 packages/core/src/types.js delete mode 100644 packages/core/src/utils.js delete mode 100644 packages/core/src/validate.js delete mode 100644 packages/core/src/withTheme.js create mode 100644 packages/core/src/withTheme.tsx delete mode 100644 packages/core/test/utils_test.js delete mode 100644 packages/core/webpack.config.dist.js create mode 100644 packages/fluent-ui/.eslintrc delete mode 100644 packages/fluent-ui/.gitignore delete mode 100644 packages/fluent-ui/src/AltDateTimeWidget/AltDateTimeWidget.tsx delete mode 100644 packages/fluent-ui/src/AltDateTimeWidget/index.ts delete mode 100644 packages/fluent-ui/src/AltDateWidget/AltDateWidget.tsx delete mode 100644 packages/fluent-ui/src/AltDateWidget/index.ts create mode 100644 packages/fluent-ui/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx create mode 100644 packages/fluent-ui/src/ArrayFieldItemTemplate/index.ts rename packages/fluent-ui/src/{TextWidget/TextWidget.tsx => BaseInputTemplate/BaseInputTemplate.tsx} (85%) create mode 100644 packages/fluent-ui/src/BaseInputTemplate/index.ts delete mode 100644 packages/fluent-ui/src/EmailWidget/EmailWidget.tsx delete mode 100644 packages/fluent-ui/src/EmailWidget/index.ts delete mode 100644 packages/fluent-ui/src/Fields/Fields.ts delete mode 100644 packages/fluent-ui/src/Fields/index.ts delete mode 100644 packages/fluent-ui/src/PasswordWidget/PasswordWidget.tsx delete mode 100644 packages/fluent-ui/src/PasswordWidget/index.ts create mode 100644 packages/fluent-ui/src/Templates/Templates.ts create mode 100644 packages/fluent-ui/src/Templates/index.ts delete mode 100644 packages/fluent-ui/src/TextWidget/index.ts delete mode 100644 packages/fluent-ui/src/URLWidget/URLWidget.tsx delete mode 100644 packages/fluent-ui/src/URLWidget/index.ts create mode 100644 packages/material-ui/.eslintrc delete mode 100644 packages/material-ui/.gitignore create mode 100644 packages/material-ui/jest.config.js create mode 100644 packages/material-ui/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx create mode 100644 packages/material-ui/src/ArrayFieldItemTemplate/index.ts create mode 100644 packages/material-ui/src/BaseInputTemplate/BaseInputTemplate.tsx create mode 100644 packages/material-ui/src/BaseInputTemplate/index.ts delete mode 100644 packages/material-ui/src/ColorWidget/ColorWidget.tsx delete mode 100644 packages/material-ui/src/ColorWidget/index.ts delete mode 100644 packages/material-ui/src/EmailWidget/EmailWidget.tsx delete mode 100644 packages/material-ui/src/EmailWidget/index.ts delete mode 100644 packages/material-ui/src/Fields/Fields.ts delete mode 100644 packages/material-ui/src/Fields/index.ts create mode 100644 packages/material-ui/src/IconButton/IconButton.tsx create mode 100644 packages/material-ui/src/IconButton/index.ts delete mode 100644 packages/material-ui/src/MuiComponentContext/MuiComponentContext.tsx delete mode 100644 packages/material-ui/src/MuiComponentContext/index.ts delete mode 100644 packages/material-ui/src/MuiComponentContext/useMuiComponent.ts delete mode 100644 packages/material-ui/src/MuiForm5/MuiForm5.tsx delete mode 100644 packages/material-ui/src/MuiForm5/index.ts delete mode 100644 packages/material-ui/src/PasswordWidget/PasswordWidget.tsx delete mode 100644 packages/material-ui/src/PasswordWidget/index.ts create mode 100644 packages/material-ui/src/Templates/Templates.ts create mode 100644 packages/material-ui/src/Templates/index.ts delete mode 100644 packages/material-ui/src/TextWidget/TextWidget.tsx delete mode 100644 packages/material-ui/src/TextWidget/index.ts delete mode 100644 packages/material-ui/src/Theme/MaterialUIContext.tsx delete mode 100644 packages/material-ui/src/Theme/MaterialUIContextProps.ts delete mode 100644 packages/material-ui/src/Theme5/Mui5Context.tsx delete mode 100644 packages/material-ui/src/Theme5/Mui5ContextProps.ts delete mode 100644 packages/material-ui/src/Theme5/Theme5.tsx delete mode 100644 packages/material-ui/src/Theme5/index.ts delete mode 100644 packages/material-ui/src/ThemeCommon/index.ts delete mode 100644 packages/material-ui/src/URLWidget/URLWidget.tsx delete mode 100644 packages/material-ui/src/URLWidget/index.ts delete mode 100644 packages/material-ui/src/UpDownWidget/UpDownWidget.tsx delete mode 100644 packages/material-ui/src/UpDownWidget/index.ts delete mode 100644 packages/material-ui/src/v4.ts delete mode 100644 packages/material-ui/src/v5.ts delete mode 100644 packages/material-ui/test/UpDownWidget.test.tsx delete mode 100644 packages/material-ui/test/__snapshots__/UpDownWidget.test.tsx.snap delete mode 100644 packages/material-ui/test/mui-5/Form.test.tsx delete mode 100644 packages/material-ui/test/mui-5/Object.test.tsx delete mode 100644 packages/material-ui/test/mui-5/UpDownWidget.test.tsx delete mode 100644 packages/material-ui/test/mui-5/__snapshots__/Array.test.tsx.snap delete mode 100644 packages/material-ui/test/mui-5/__snapshots__/Form.test.tsx.snap delete mode 100644 packages/material-ui/test/mui-5/__snapshots__/Object.test.tsx.snap delete mode 100644 packages/material-ui/test/mui-5/__snapshots__/UpDownWidget.test.tsx.snap delete mode 100644 packages/material-ui/tsdx.config.js create mode 100644 packages/mui/.eslintrc create mode 100644 packages/mui/README.md create mode 100644 packages/mui/babel.config.js create mode 100644 packages/mui/jest.config.js create mode 100644 packages/mui/logo.png create mode 100644 packages/mui/package-lock.json create mode 100644 packages/mui/package.json rename packages/{material-ui/screenshot5.png => mui/screenshot.png} (100%) create mode 100644 packages/mui/src/AddButton/AddButton.tsx create mode 100644 packages/mui/src/AddButton/index.ts create mode 100644 packages/mui/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx create mode 100644 packages/mui/src/ArrayFieldItemTemplate/index.ts create mode 100644 packages/mui/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx create mode 100644 packages/mui/src/ArrayFieldTemplate/index.ts create mode 100644 packages/mui/src/BaseInputTemplate/BaseInputTemplate.tsx create mode 100644 packages/mui/src/BaseInputTemplate/index.ts create mode 100644 packages/mui/src/CheckboxWidget/CheckboxWidget.tsx create mode 100644 packages/mui/src/CheckboxWidget/index.ts create mode 100644 packages/mui/src/CheckboxesWidget/CheckboxesWidget.tsx create mode 100644 packages/mui/src/CheckboxesWidget/index.ts rename packages/{chakra-ui => mui}/src/DateTimeWidget/DateTimeWidget.tsx (52%) rename packages/{bootstrap-4 => mui}/src/DateTimeWidget/index.ts (100%) create mode 100644 packages/mui/src/DateWidget/DateWidget.tsx rename packages/{bootstrap-4 => mui}/src/DateWidget/index.ts (100%) create mode 100644 packages/mui/src/DescriptionField/DescriptionField.tsx create mode 100644 packages/mui/src/DescriptionField/index.ts create mode 100644 packages/mui/src/ErrorList/ErrorList.tsx create mode 100644 packages/mui/src/ErrorList/index.ts create mode 100644 packages/mui/src/FieldTemplate/FieldTemplate.tsx create mode 100644 packages/mui/src/FieldTemplate/WrapIfAdditional.tsx create mode 100644 packages/mui/src/FieldTemplate/index.ts create mode 100644 packages/mui/src/IconButton/IconButton.tsx create mode 100644 packages/mui/src/IconButton/index.ts create mode 100644 packages/mui/src/MuiForm/MuiForm.tsx create mode 100644 packages/mui/src/MuiForm/index.ts create mode 100644 packages/mui/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx create mode 100644 packages/mui/src/ObjectFieldTemplate/index.ts create mode 100644 packages/mui/src/RadioWidget/RadioWidget.tsx create mode 100644 packages/mui/src/RadioWidget/index.ts create mode 100644 packages/mui/src/RangeWidget/RangeWidget.tsx create mode 100644 packages/mui/src/RangeWidget/index.ts create mode 100644 packages/mui/src/SelectWidget/SelectWidget.tsx create mode 100644 packages/mui/src/SelectWidget/index.ts create mode 100644 packages/mui/src/SubmitButton/SubmitButton.tsx create mode 100644 packages/mui/src/SubmitButton/index.ts create mode 100644 packages/mui/src/Templates/Templates.ts create mode 100644 packages/mui/src/Templates/index.ts create mode 100644 packages/mui/src/TextareaWidget/TextareaWidget.tsx create mode 100644 packages/mui/src/TextareaWidget/index.ts create mode 100644 packages/mui/src/Theme/Theme.tsx create mode 100644 packages/mui/src/Theme/index.ts create mode 100644 packages/mui/src/TitleField/TitleField.tsx create mode 100644 packages/mui/src/TitleField/index.ts create mode 100644 packages/mui/src/Widgets/Widgets.ts create mode 100644 packages/mui/src/Widgets/index.ts create mode 100644 packages/mui/src/index.ts rename packages/{material-ui/test/mui-5 => mui/test}/Array.test.tsx (50%) create mode 100644 packages/mui/test/Form.test.tsx create mode 100644 packages/mui/test/Object.test.tsx create mode 100644 packages/mui/test/__snapshots__/Array.test.tsx.snap create mode 100644 packages/mui/test/__snapshots__/Form.test.tsx.snap create mode 100644 packages/mui/test/__snapshots__/Object.test.tsx.snap create mode 100644 packages/mui/tsconfig.json create mode 100644 packages/playground/.npmrc create mode 100644 packages/playground/src/samples/customFieldAnyOf.js delete mode 100644 packages/semantic-ui/.editorconfig create mode 100644 packages/semantic-ui/jest.config.js create mode 100644 packages/semantic-ui/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.js create mode 100644 packages/semantic-ui/src/ArrayFieldItemTemplate/index.js rename packages/semantic-ui/src/{TextWidget/TextWidget.js => BaseInputTemplate/BaseInputTemplate.js} (69%) create mode 100644 packages/semantic-ui/src/BaseInputTemplate/index.js delete mode 100644 packages/semantic-ui/src/DateTimeWidget/DateTimeWidget.js delete mode 100644 packages/semantic-ui/src/DateTimeWidget/index.js delete mode 100644 packages/semantic-ui/src/DateWidget/DateWidget.js delete mode 100644 packages/semantic-ui/src/DateWidget/index.js delete mode 100644 packages/semantic-ui/src/EmailWidget/EmailWidget.js delete mode 100644 packages/semantic-ui/src/EmailWidget/index.js delete mode 100644 packages/semantic-ui/src/Fields/Fields.js delete mode 100644 packages/semantic-ui/src/Fields/index.js delete mode 100644 packages/semantic-ui/src/PasswordWidget/PasswordWidget.js delete mode 100644 packages/semantic-ui/src/PasswordWidget/index.js create mode 100644 packages/semantic-ui/src/Templates/Templates.js create mode 100644 packages/semantic-ui/src/Templates/index.js delete mode 100644 packages/semantic-ui/src/TextWidget/index.js delete mode 100644 packages/semantic-ui/src/URLWidget/URLWidget.js delete mode 100644 packages/semantic-ui/src/URLWidget/index.js delete mode 100644 packages/semantic-ui/src/UpDownWidget/UpDownWidget.js delete mode 100644 packages/semantic-ui/src/UpDownWidget/index.js create mode 100644 packages/utils/.eslintrc create mode 100644 packages/utils/README.md create mode 100644 packages/utils/babel.config.js create mode 100644 packages/utils/jest.config.js create mode 100644 packages/utils/logo.png create mode 100644 packages/utils/package-lock.json create mode 100644 packages/utils/package.json create mode 100644 packages/utils/src/allowAdditionalItems.ts create mode 100644 packages/utils/src/asNumber.ts create mode 100644 packages/utils/src/canExpand.ts create mode 100644 packages/utils/src/constants.ts create mode 100644 packages/utils/src/createSchemaUtils.ts create mode 100644 packages/utils/src/dataURItoBlob.ts create mode 100644 packages/utils/src/deepEquals.ts create mode 100644 packages/utils/src/findSchemaDefinition.ts create mode 100644 packages/utils/src/getInputProps.ts create mode 100644 packages/utils/src/getSchemaType.ts create mode 100644 packages/utils/src/getSubmitButtonOptions.ts create mode 100644 packages/utils/src/getTemplate.ts create mode 100644 packages/utils/src/getUiOptions.ts create mode 100644 packages/utils/src/getWidget.tsx create mode 100644 packages/utils/src/guessType.ts create mode 100644 packages/utils/src/hasWidget.ts create mode 100644 packages/utils/src/index.ts create mode 100644 packages/utils/src/isConstant.ts create mode 100644 packages/utils/src/isCustomWidget.ts create mode 100644 packages/utils/src/isFixedItems.ts create mode 100644 packages/utils/src/isObject.ts create mode 100644 packages/utils/src/localToUTC.ts create mode 100644 packages/utils/src/mergeDefaultsWithFormData.ts create mode 100644 packages/utils/src/mergeObjects.ts create mode 100644 packages/utils/src/mergeSchemas.ts create mode 100644 packages/utils/src/optionsList.ts create mode 100644 packages/utils/src/orderProperties.ts create mode 100644 packages/utils/src/pad.ts create mode 100644 packages/utils/src/parseDateString.ts create mode 100644 packages/utils/src/processSelectValue.ts create mode 100644 packages/utils/src/rangeSpec.ts create mode 100644 packages/utils/src/schema/getDefaultFormState.ts create mode 100644 packages/utils/src/schema/getDisplayLabel.ts create mode 100644 packages/utils/src/schema/getMatchingOption.ts create mode 100644 packages/utils/src/schema/index.ts create mode 100644 packages/utils/src/schema/isFilesArray.ts create mode 100644 packages/utils/src/schema/isMultiSelect.ts create mode 100644 packages/utils/src/schema/isSelect.ts create mode 100644 packages/utils/src/schema/mergeValidationData.ts create mode 100644 packages/utils/src/schema/retrieveSchema.ts create mode 100644 packages/utils/src/schema/toIdSchema.ts create mode 100644 packages/utils/src/schema/toPathSchema.ts create mode 100644 packages/utils/src/schemaRequiresTrueValue.ts create mode 100644 packages/utils/src/shouldRender.ts create mode 100644 packages/utils/src/toConstant.ts create mode 100644 packages/utils/src/toDateString.ts create mode 100644 packages/utils/src/types.ts create mode 100644 packages/utils/src/utcToLocal.ts create mode 100644 packages/utils/test/.eslintrc create mode 100644 packages/utils/test/allowAdditionalItems.test.ts create mode 100644 packages/utils/test/asNumber.test.ts create mode 100644 packages/utils/test/canExpand.test.ts create mode 100644 packages/utils/test/createSchemaUtils.test.ts create mode 100644 packages/utils/test/dataURItoBlob.test.ts create mode 100644 packages/utils/test/deepEquals.test.ts create mode 100644 packages/utils/test/findSchemaDefinition.test.ts create mode 100644 packages/utils/test/getInputProps.test.ts create mode 100644 packages/utils/test/getSchemaType.test.ts create mode 100644 packages/utils/test/getSubmitButtonOptions.test.ts create mode 100644 packages/utils/test/getTemplate.test.ts create mode 100644 packages/utils/test/getUiOptions.test.ts create mode 100644 packages/utils/test/getWidget.test.tsx create mode 100644 packages/utils/test/guessType.test.ts create mode 100644 packages/utils/test/hasWidget.test.ts create mode 100644 packages/utils/test/isConstant.test.ts create mode 100644 packages/utils/test/isCustomWidget.test.ts create mode 100644 packages/utils/test/isFixedItems.test.ts create mode 100644 packages/utils/test/localToUTC.test.ts create mode 100644 packages/utils/test/mergeDefaultsWithFormData.test.ts create mode 100644 packages/utils/test/mergeObjects.test.ts create mode 100644 packages/utils/test/mergeSchemas.test.ts create mode 100644 packages/utils/test/optionsList.test.ts create mode 100644 packages/utils/test/orderProperties.test.ts create mode 100644 packages/utils/test/pad.test.ts create mode 100644 packages/utils/test/parseDateString.test.ts create mode 100644 packages/utils/test/processSelectValue.test.ts create mode 100644 packages/utils/test/rangeSpec.test.ts create mode 100644 packages/utils/test/schema.test.ts create mode 100644 packages/utils/test/schema/getDefaultFormStateTest.ts create mode 100644 packages/utils/test/schema/getDisplayLabelTest.ts create mode 100644 packages/utils/test/schema/getMatchingOptionTest.ts create mode 100644 packages/utils/test/schema/index.ts create mode 100644 packages/utils/test/schema/isFilesArrayTest.ts create mode 100644 packages/utils/test/schema/isMultiSelectTest.ts create mode 100644 packages/utils/test/schema/isSelectTest.ts create mode 100644 packages/utils/test/schema/mergeValidationDataTest.ts create mode 100644 packages/utils/test/schema/retrieveSchemaTest.ts create mode 100644 packages/utils/test/schema/toIdSchemaTest.ts create mode 100644 packages/utils/test/schema/toPathSchemaTest.ts create mode 100644 packages/utils/test/schema/types.ts create mode 100644 packages/utils/test/schemaRequiresTrueValue.test.ts create mode 100644 packages/utils/test/shouldRender.test.tsx create mode 100644 packages/utils/test/testUtils/getTestValidator.ts create mode 100644 packages/utils/test/toConstant.test.ts create mode 100644 packages/utils/test/toDateString.test.ts create mode 100644 packages/utils/test/utcToLocal.test.ts create mode 100644 packages/utils/tsconfig.json create mode 100644 packages/validator-ajv6/.eslintrc create mode 100644 packages/validator-ajv6/README.md create mode 100644 packages/validator-ajv6/babel.config.js create mode 100644 packages/validator-ajv6/jest.config.js create mode 100644 packages/validator-ajv6/logo.png create mode 100644 packages/validator-ajv6/package-lock.json create mode 100644 packages/validator-ajv6/package.json create mode 100644 packages/validator-ajv6/src/createAjvInstance.ts create mode 100644 packages/validator-ajv6/src/customizeValidator.ts create mode 100644 packages/validator-ajv6/src/index.ts create mode 100644 packages/validator-ajv6/src/types.ts create mode 100644 packages/validator-ajv6/src/validator.ts create mode 100644 packages/validator-ajv6/test/.eslintrc create mode 100644 packages/validator-ajv6/test/createAjvInstance.test.ts create mode 100644 packages/validator-ajv6/test/customizeValidator.test.ts create mode 100644 packages/validator-ajv6/test/utilsTests/getTestValidator.ts create mode 100644 packages/validator-ajv6/test/utilsTests/schema.test.ts create mode 100644 packages/validator-ajv6/test/validator.test.ts create mode 100644 packages/validator-ajv6/tsconfig.json diff --git a/.eslintrc-javascript b/.eslintrc-javascript new file mode 100644 index 0000000000..a5068c33e6 --- /dev/null +++ b/.eslintrc-javascript @@ -0,0 +1,34 @@ +{ + "extends": "eslint:recommended", + "parser": "@babel/eslint-parser", + "parserOptions": { + "babelOptions": { + "presets": ["@babel/preset-react"] + } + }, + "rules": { + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2, + "react/jsx-tag-spacing": [1, { + "beforeSelfClosing": "always" + }], + "curly": [2], + "linebreak-style": [2, "unix"], + "semi": [2, "always"], + "comma-dangle": [0], + "no-unused-vars": [2, { + "vars": "all", + "args": "none", + "ignoreRestSiblings": true + }], + "no-console": [0], + "object-curly-spacing": [2, "always"], + "keyword-spacing": ["error"] + }, + "env": { + "es6": true, + "browser": true, + "node": true + } +} diff --git a/.eslintrc-typescript b/.eslintrc-typescript new file mode 100644 index 0000000000..d0d394b6da --- /dev/null +++ b/.eslintrc-typescript @@ -0,0 +1,42 @@ +{ + "parser": "@typescript-eslint/parser", + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react-hooks/recommended" + ], + "rules": { + "react/prop-types": 0, + "react/no-find-dom-node": 0, + "react/display-name": 0, + "react/jsx-uses-react": 2, + "react/jsx-uses-vars": 2, + "react/react-in-jsx-scope": 2, + "react/jsx-tag-spacing": [1, { + "beforeSelfClosing": "always" + }], + "curly": [2], + "linebreak-style": [2, "unix"], + "semi": [2, "always"], + "comma-dangle": [0], + "@typescript-eslint/no-unused-vars": [2, { + "vars": "all", + "args": "none", + "ignoreRestSiblings": true + }], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "no-console": [0], + "object-curly-spacing": [2, "always"], + "keyword-spacing": ["error"], + "no-prototype-builtins": "warn", + "@typescript-eslint/no-empty-function": "warn", + "@typescript-eslint/no-var-requires": "warn" + }, + "env": { + "es6": true, + "browser": true, + "node": true + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b86905f214..2d3b094a28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,16 +2,16 @@ name: CI on: push: - branches: [ master ] + branches: [ master, rjsf-v5 ] pull_request: - branches: [ master ] + branches: [ master, rjsf-v5 ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - node-version: [12.x, 14.x] + node-version: [12.x, 14.x, 16.x, 18.x] steps: - uses: actions/checkout@v3 @@ -22,7 +22,7 @@ jobs: - run: npm ci - run: npm run lint - run: npm run cs-check - + - name: Build with Netlify badge if: github.ref != 'refs/heads/master' run: npm run build @@ -31,14 +31,14 @@ jobs: - name: Build if: github.ref == 'refs/heads/master' run: npm run build - - - if: matrix.node-version == '14.x' + + - if: matrix.node-version == '16.x' uses: actions/upload-artifact@v2 with: name: dist path: packages/playground/build - run: npm test - + deploy_preview: runs-on: ubuntu-latest if: github.ref != 'refs/heads/master' @@ -58,7 +58,7 @@ jobs: NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} - + deploy_playground: runs-on: ubuntu-latest if: github.ref == 'refs/heads/master' @@ -78,7 +78,7 @@ jobs: build_dir: dist env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - + # deploy_canary: # runs-on: ubuntu-latest # if: github.ref == 'refs/heads/master' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e01e437a76..0f2c4ee99a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,10 +9,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Use Node.js 14.x + - name: Use Node.js 16.x uses: actions/setup-node@v3 with: - node-version: 14.x + node-version: 16.x - run: npm ci - run: npm run build - run: npm test diff --git a/.gitignore b/.gitignore index 21cab454a6..c3e05d6f25 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,7 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk +.rts2_** # End of https://www.gitignore.io/api/osx,node,linux,windows @@ -127,6 +128,7 @@ yarn.lock .vscode .idea *.iml +.editorconfig # Code coverage coverage @@ -134,3 +136,4 @@ coverage venv *.orig +out/ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000..5341e4121d --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" +# Hopefully this disables husky on github CI +[ -n "$CI" ] && exit 0 +npm run pre-commit:husky diff --git a/.node-version b/.node-version index 8351c19397..b6a7d89c68 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -14 +16 diff --git a/.nvmrc b/.nvmrc index 8351c19397..b6a7d89c68 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -14 +16 diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000000..2759974a6f --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,5 @@ +bracketSameLine: false +trailingComma: es5 +useTabs: false +semi: true +tabWidth: 2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 917fddec1e..328e99ac57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,98 @@ it according to semantic versioning. For example, if your PR adds a breaking cha should change the heading of the (upcoming) version to include a major version bump. --> -# v5.0.0 (coming soon) +# v5.0.0-beta.1 + +## Global changes across all themes: +- Node 16 is now the default node engine for all packages, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2687) +- Refactored all themes to use the new `@rjsf/utils` library functions and types +- Refactored the individual theme forms to consolidate `templates` as part of the fix for https://github.com/rjsf-team/react-jsonschema-form/issues/2526 + - All the work implementing the `BaseInputTemplate` should fix (https://github.com/rjsf-team/react-jsonschema-form/issues/2926, https://github.com/rjsf-team/react-jsonschema-form/issues/2889, https://github.com/rjsf-team/react-jsonschema-form/issues/2875, https://github.com/rjsf-team/react-jsonschema-form/issues/2223) + - Also made the display of `title` and `description` consistent across themes, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2481, https://github.com/rjsf-team/react-jsonschema-form/issues/2363, https://github.com/rjsf-team/react-jsonschema-form/issues/2219) + - This change also ensures that all templates are properly exported, resolving (https://github.com/rjsf-team/react-jsonschema-form/issues/2365) +- Bumped most devDependencies to the latest versions where possible +- Switched all repos `package.json` and `package-lock.json` files to be built and maintained by Node 16. +- Adding button templates help to change text for buttons (https://github.com/rjsf-team/react-jsonschema-form/issues/2082, https://github.com/rjsf-team/react-jsonschema-form/issues/2357) + +## @rjsf/utils +- New package created by refactoring and converting to Typescript the `utils.js` file from `core` into independent functions. + - Resolves (https://github.com/rjsf-team/react-jsonschema-form/issues/1655, https://github.com/rjsf-team/react-jsonschema-form/issues/2480, https://github.com/rjsf-team/react-jsonschema-form/issues/2341) +- Updated `types` from `core` in `utils` to better match the implementation across all themes + - Included adding a bunch of new types for existing and new features + - The type updates should fix (https://github.com/rjsf-team/react-jsonschema-form/issues/2871, https://github.com/rjsf-team/react-jsonschema-form/issues/2673, https://github.com/rjsf-team/react-jsonschema-form/issues/2347, https://github.com/rjsf-team/react-jsonschema-form/issues/2186) +- Clear errors on `formData` change when `liveOmit=true` when "additionalProperties: false" [issue 1507](https://github.com/rjsf-team/react-jsonschema-form/issues/1507) (https://github.com/rjsf-team/react-jsonschema-form/pull/2631) + +## @rjsf/validator-ajv6 +- New package created by refactoring and converting to Typescript the `validator.js` file from `core` into independent functions as well as a class that implements the new `ValidatorType` interface. + - [#2693](https://github.com/rjsf-team/react-jsonschema-form/issues/2693). +- Added support for customizing the options passed to the creation of the `ajv` instance. + +## @rjsf/validator-ajv6 +- A **BREAKING CHANGE** to `toErrorList()` was made so that it takes `fieldPath: string[]` rather than `fieldName='root'` as part of the fix to (https://github.com/rjsf-team/react-jsonschema-form/issues/1596) + - The returned `errors` also now adds `property` from the `fieldPath` along with the proper path from the `property` to the `stack` message, making it consistent with the AJV errors. + - Previously the `stack` attribute would say `root: error message`; now it says `. error message` + - In addition, the extra information provided by AJV is no longer lost from the `errors` when merged with custom validation, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596). + +## @rjsf/core +- Converted core to Typescript (https://github.com/rjsf-team/react-jsonschema-form/issues/583) +- `ui:emptyValue` now works with selects (https://github.com/rjsf-team/react-jsonschema-form/issues/1041) +- Refactoring `utils.js` into the new `@rjsf/utils` fixes (https://github.com/rjsf-team/react-jsonschema-form/issues/2719) +- **BREAKING CHANGE** Fix overriding core submit button className (https://github.com/rjsf-team/react-jsonschema-form/issues/2979) +- Fix `ui:field` with anyOf or oneOf no longer rendered twice (#2890) +- **BREAKING CHANGE** Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array (https://github.com/rjsf-team/react-jsonschema-form/issues/2197) +- `formContext` is now passed properly to `SchemaField`, fixes (https://github.com/rjsf-team/react-jsonschema-form/issues/2394, https://github.com/rjsf-team/react-jsonschema-form/issues/2274) +- Added `ui:duplicateKeySuffixSeparator` to customize how duplicate object keys are renamed when using `additionalProperties`. +- The `extraErrors` are now consistently appended onto the end of the schema validation-based `errors` information that is returned via the `onErrors()` callback when submit fails. + - In addition, the extra information provided by AJV is no longer stripped from the `errors` during the merge process, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596). +- Fixed id generation for `RadioWidget` to no longer use random numbers fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2461) +- Correctly call the `onChange` handler in the new set of props if it changed, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1708). +- Fixed race condition for `onChange` when `formData` is controlled prop, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/513), + +## @rjsf/antd +- Fix esm build to use `@rollup/plugin-replace` to replace `antd/lib` and `rc-picker/lib` with `antd/es` and `rc-picker/es` respectively, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2962) + +## @rjsf/bootstrap-4 +- Bootstrap-4 `withTheme` customizations should work properly now (https://github.com/rjsf-team/react-jsonschema-form/issues/2058) +- `ArrayFieldTemplate` refactor seems to have fixed https://github.com/rjsf-team/react-jsonschema-form/issues/2775 +- Fix issues with `SelectField` (https://github.com/rjsf-team/react-jsonschema-form/issues/2616, https://github.com/rjsf-team/react-jsonschema-form/issues/2875) + +## @rjsf/chakra-ui +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) + +## @rjsf/material-ui +- The theme for Material UI version 5 (i.e. `@rjsf/mui`) was split out of the theme for version 4 (i.e. `@rjsf/material-ui`) to resolve the following issues: + - [#2762](https://github.com/rjsf-team/react-jsonschema-form/issues/2762) + - [#2858](https://github.com/rjsf-team/react-jsonschema-form/issues/2858) + - [#2905](https://github.com/rjsf-team/react-jsonschema-form/issues/2905) + - [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) + - [#2774](https://github.com/rjsf-team/react-jsonschema-form/issues/2774) +- Material-UI TextWidget now respects `inputType` in uiSchema (https://github.com/rjsf-team/react-jsonschema-form/issues/2057) + - Also respects `step` for `number` type (https://github.com/rjsf-team/react-jsonschema-form/issues/2488) +- Material-UI UpDownWidget now support min/max/step (https://github.com/rjsf-team/react-jsonschema-form/issues/2022) +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) +- Select properly accepts true or false (https://github.com/rjsf-team/react-jsonschema-form/issues/2326) + +## @rjsf/mui +- The theme for Material UI version 5 (i.e. `@rjsf/mui`) was split out of the theme for version 4 (i.e. `@rjsf/material-ui`) to resolve the following issues: + - [#2762](https://github.com/rjsf-team/react-jsonschema-form/issues/2762) + - [#2858](https://github.com/rjsf-team/react-jsonschema-form/issues/2858) + - [#2905](https://github.com/rjsf-team/react-jsonschema-form/issues/2905) + - [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) + - [#2774](https://github.com/rjsf-team/react-jsonschema-form/issues/2774) +- Material-UI TextWidget now respects `inputType` in uiSchema (https://github.com/rjsf-team/react-jsonschema-form/issues/2057) + - Also respects `step` for `number` type (https://github.com/rjsf-team/react-jsonschema-form/issues/2488) +- Material-UI UpDownWidget now support min/max/step (https://github.com/rjsf-team/react-jsonschema-form/issues/2022) +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) + +## @rjsf/semantic-ui +- Fix missing error class on fields (https://github.com/rjsf-team/react-jsonschema-form/issues/2666) +- Fixed the `main` definition in `semantic-ui` to fix (https://github.com/withastro/astro/issues/4357) +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) + +## Dev / docs / playground +- Demonstrate use of `ui:field` with `anyOf` (#2890) +- Playground now uses webpack 5 +- Corrected number field default (https://github.com/rjsf-team/react-jsonschema-form/issues/2358) # 4.2.1 * fix typo by @epicfaace in https://github.com/rjsf-team/react-jsonschema-form/pull/2854 @@ -47,7 +138,7 @@ should change the heading of the (upcoming) version to include a major version b - NOTE: `@rjsf/material-ui` was retained to avoid a breaking change, but using it will continue to cause bundler warnings - See the `README.md` for the `@rjsf/material-ui` package for updated usage information - Fixed (#2831) for `material-ui` by removing the `DefaultChildren` passed into the themes - + ## @rjsf/bootstrap-4 - SubmitButton widget to use new ui:submitButtonOptions on the submit button for forms (https://github.com/rjsf-team/react-jsonschema-form/pull/2640) diff --git a/docs/3.x upgrade guide.md b/docs/3.x upgrade guide.md index 4ff446ef80..bad2dd34c3 100644 --- a/docs/3.x upgrade guide.md +++ b/docs/3.x upgrade guide.md @@ -12,7 +12,7 @@ Dropped support for Node 8, 9, 10. Minimum supported version of Node.js is now 1 ### Help field IDs -IDs for [Help fields](https://react-jsonschema-form.readthedocs.io/en/latest/api-reference/uiSchema/#help) are now suffixed by `__help` so that the IDs are unique. Previously, their IDs would be nonexistent or the same as the fields that they were describing. +IDs for [Help fields](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/uiSchema/#help) are now suffixed by `__help` so that the IDs are unique. Previously, their IDs would be nonexistent or the same as the fields that they were describing. ### Bring your own polyfills diff --git a/docs/4.x upgrade guide.md b/docs/4.x upgrade guide.md index f6fd2c61a3..3ebc1fa99a 100644 --- a/docs/4.x upgrade guide.md +++ b/docs/4.x upgrade guide.md @@ -8,4 +8,4 @@ No longer actively supporting React version < 16.3. The minimum supported versio ### @rjsf/material-ui package - Minimum version of material-ui 4 -If you are using the material-ui 4 theme, @material-ui/core and @material-ui/icons packages should be updated to the latest versions. The minimum versions supported for @material-ui/core and @material-ui/icons are 4.12.0 and 4.11.1 respectively. This change is required for [support for the material-ui version 5 theme](https://github.com/rjsf-team/react-jsonschema-form/tree/master/packages/material-ui) \ No newline at end of file +If you are using the material-ui 4 theme, @material-ui/core and @material-ui/icons packages should be updated to the latest versions. The minimum versions supported for @material-ui/core and @material-ui/icons are 4.12.0 and 4.11.1 respectively. This change is required for [support for the material-ui version 5 theme](https://github.com/rjsf-team/react-jsonschema-form/tree/master/packages/material-ui) diff --git a/docs/5.x upgrade guide.md b/docs/5.x upgrade guide.md new file mode 100644 index 0000000000..eccd4101ad --- /dev/null +++ b/docs/5.x upgrade guide.md @@ -0,0 +1,493 @@ +# 5.x Upgrade Guide + +## Breaking changes + +There were several significant **breaking changes** in RJSF version 5 that were necessary in order to support the following new features: + +- Schema validation was decoupled from `@rjsf/core` to resolve issue [#2693](https://github.com/rjsf-team/react-jsonschema-form/issues/2693). + - Additionally, in order to break a circular dependency in the validation refactor, the `@rjsf/core/utils.js` file was split out into its own `@rjsf/utils` package as was suggested in [#1655](https://github.com/rjsf-team/react-jsonschema-form/issues/1655). +- The theme for Material UI version 5 (i.e. `@rjsf/mui`) was split out of the theme for version 4 (i.e. `@rjsf/material-ui`) to resolve the following issues: + - [#2762](https://github.com/rjsf-team/react-jsonschema-form/issues/2762) + - [#2858](https://github.com/rjsf-team/react-jsonschema-form/issues/2858) + - [#2905](https://github.com/rjsf-team/react-jsonschema-form/issues/2905) + - [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) +- As part of the fix for [#2526](https://github.com/rjsf-team/react-jsonschema-form/issues/2526) all the existing templates in the previous version were moved into a new `templates` dictionary, similar to how `widgets` and `fields` work + - This `templates` dictionary was added to the `Registry` and also the `Form` props, replacing the `ArrayFieldTemplate`, `FieldTemplate`, `ObjectFieldTemplate` and `ErrorList` props. + - In addition, several of the `fields` and `widgets` based components were moved into the `templates` dictionary as they were more like templates than true `Field`s or `Widget`s. + - [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) +- Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array (https://github.com/rjsf-team/react-jsonschema-form/issues/2197) + +### Node support + +Version 5 is dropping official support for Node 12 as it is no longer a [maintained version](https://nodejs.org/en/about/releases/). +Please use Node 16 when making any changes to `package.json` and `package-lock.json` files. +All PR and branch builds are running against Node 14, 16 and 18. + +### React version + +RJSF is no longer actively supporting React version < 16.14.x. +React 17 is officially supported on all the themes where the underlying theme library also supports React 17 (only `semantic-ui` is current restricted to React 16). + +Unfortunately, there is required work pending to properly support React 18, so use it at your own risk. + +### New packages + +There are three new packages added in RJSF version 5: +- `@rjsf/utils`: All of the [utility functions](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions) previously imported from `@rjsf/core/utils` as well as the Typescript types for RJSF version 5. + - The following new utility functions were added: `createSchemaUtils()`, `getInputProps()`, `mergeValidationData()` and `processSelectValue()` +- `@rjsf/validator-ajv6`: The [ajv](https://github.com/ajv-validator/ajv)-v6-based validator refactored out of `@rjsf/core@4.x`, that implements the `ValidatorType` interface defined in `@rjsf/utils`. +- `@rjsf/mui`: Previously `@rjsf/material-ui/v5`, now provided as its own theme. + +### `@rjsf/core` BREAKING CHANGES + +#### Types +In version 4, RJSF exported all its types directly from `@rjsf/core`. +In version 5, only the types for the `Form` component and the `withTheme()` HOC are exported directly from `@rjsf/core`. +All the rest of the types for RJSF are now exported from the new `@rjsf/utils` package. + +NOTE: The types in `@rjsf/utils` have been improved significantly from those in version 4. +Some of the most notable changes are: +- `RJSFSchema` has replaced the use of `JSON7Schema` for future compatibility reasons. + - Currently `RJSFSchema` is simply an alias to `JSON7Schema` so this change is purely a naming one. + - It is highly recommended to update your use of `JSON7Schema` with `RJSFSchema` so that when the RJSF begins supporting a newer JSON Schema version out-of-the-box, your code won't be affected. +- `RJSFSchemaDefinition` has replaced the use of `JSONSchema7Definition` for the same reasons. +- The use of the generic `T` (defaulting to `any`) for the `formData` type has been expanded to cover all type hierarchies that use `formData`. +- A new generic `F` (defaulting to `any`) was added for the `formContext` type, and all types in the hierarchy that use `formContext` have had that generic added to them. +- The new `CustomValidator`, `ErrorTransformer`, `ValidationData`, `ValidatorType` and `SchemaUtilsType` types were added to support the decoupling of the validation implementation. +- The new `TemplatesType`, `ArrayFieldDescriptionProps`, `ArrayFieldTitleProps`, `UnsupportedFieldProps`, `IconButtonProps`, `SubmitButtonProps` and `UIOptionsBaseType` were added to support the consolidation (and expansion) of `templates` in the `Registry` and `Form`. +- **BREAKING CHANGE** The `DescriptionField` and `TitleField` props were removed from the `ArrayFieldTemplateProps` and `ObjectFieldTemplateProps` as they can now be derived from the `templates` or `uiSchema` via the new `getTemplate()` utility function. +- **BREAKING CHANGE** The `fields` prop was removed from the `FieldTemplateProps` as you can simply use `registry.fields` instead. + +You can view all these [types](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/utils/src/types.ts) on Github. + + +#### Form props +In version 5, the `Form` component's two optional props `additionalMetaSchemas` and `customFormats` were replaced with the new, required `validator` prop, in order to support the decoupling of the validation implementation. +This new `validator` prop is expected to be an implementation of the `ValidatorType` interface. +The new `@rjsf/validator-ajv6` package contains the refactored implementation of the version 4 validator. + +There are two ways to use this new package to provide a `validator` for a `Form`. +First, you can simply import the default validator from the package and pass it to a `Form`. + +```tsx +import { RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv6"; + +// Your schema +const schema: RJSFSchema = { ... }; + +render(( + +), document.getElementById("app")); +``` + +Second, if you were actually providing one (or both) of the removed optional props to your `Form`, you can continue using them by creating a customized validator. + +```tsx +import { RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import { customizeValidator, CustomValidatorOptionsType } from "@rjsf/validator-ajv6"; + +// Your schema, additionalMetaSchemas and/or customFormats +const schema: RJSFSchema = { ... }; +const additionalMetaSchemas: CustomValidatorOptionsType['additionalMetaSchemas'] = [{ ... }]; +const customFormats: CustomValidatorOptionsType['customFormats'] = { ... }; + +const validator = customizeValidator({ additionalMetaSchemas, customFormats }); + +render(( + +), document.getElementById("app")); +``` + +##### `validate` prop renamed +Additionally, in version 5, the `validate` prop on `Form` was renamed to `customValidate` to avoid confusion with the new `validator` prop. + +##### `fields` prop changes +In previous versions, it was possible to provide an override to the `DescriptionField`, `TitleField` and/or `UnsupportedField` components by providing a custom implementation in the `fields` prop on the `Form`. +Since these components do not actually support the `FieldProps` interface, they were moved into the `templates` dictionary instead. +If you were previously overriding any (or all) of these components, you can override them now via the `templates` prop on `Form` instead: + +```tsx +import { DescriptionFieldProps, RJSFSchema, TitleFieldProps } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv6"; + +// Your schema +const schema: RJSFSchema = { ... }; + +// Your custom fields +const CustomDescriptionField = (props: DescriptionFieldProps) => { ... }; +const CustomTitleField = (props: TitleFieldProps) => { ... }; +const CustomUnsupportedField = (props: ObjectFieldTemplateProps) => { ... +}; + +const templates: Partial = { + DescriptionFieldTemplate: CustomDescriptionField, + TitleFieldTemplate: CustomTitleField, + UnsupportedFieldTemplate: CustomUnsupportedField, +}; + +render(( + +), document.getElementById("app")); +``` + +##### new `templates` prop +Additionally, in version 5, the `ArrayFieldTemplate`, `FieldTemplate`, `ObjectFieldTemplate` and `ErrorList` props were replaced with the `templates` prop as part of the `TemplatesType` consolidation. +If you were previously overriding any (or all) of these templates, you can simply consolidate them into the new `templates` prop on `Form` instead: + +```tsx +import { ArrayFieldTemplateProps, ErrorListProps, FieldTemplateProps, ObjectFieldTemplateProps, RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv6"; + +// Your schema +const schema: RJSFSchema = { ... }; + +// Your custom templates +const CustomArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { ... }; +const CustomFieldTemplate = (props: FieldTemplateProps) => { ... }; +const CustomObjectFieldTemplate = (props: ObjectFieldTemplateProps) => { ... }; +const CustomErrorField = (props: ErrorListProps) => { ... }; + +const templates: Partial = { + ArrayFieldTemplate: CustomArrayFieldTemplate, + FieldTemplate: CustomFieldTemplate, + ObjectFieldTemplate: CustomObjectFieldTemplate, + ErrorFieldTemplate: CustomErrorField, +}; + +render(( + +), document.getElementById("app")); +``` + +NOTE: In version 5, the `ArrayField` implementation was refactored to add 3 additional templates for presenting arrays along with the `ArrayFieldTemplate`. +If you were updating the `ArrayFieldTemplate` to modify just a subset of the UI, it may be easier for you to implement one of the other new templates instead. +See the [Custom Templates](https://react-jsonschema-form.readthedocs.io/en/stable/advanced-customization/custom-templates) documentation for more details. + +##### `widgets` prop change +In the previous version, it was possible to provide an override to the `SubmitButton` component by providing a custom implementation in the `widgets` prop on the `Form`. +Since this component only requires a tiny fraction of the `WidgetProps` interface, it was moved into the `templates.ButtonTemplates` dictionary instead with its own, reduced set of props. +If you were previously overriding this component, you can override it now via the `templates` prop on `Form` instead: + +```tsx +import { RJSFSchema, SubmitButtonProps } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv6"; + +// Your schema +const schema: RJSFSchema = { ... }; + +// Your custom button +const CustomSubmitButton = (props: SubmitButtonProps) => { ... +}; + +const templates: Partial = { + ButtonTemplates: { + SubmitButton: CustomSubmitButton, + } +}; + +render(( + +), document.getElementById("app")); +``` + +#### utils.js +In version 5, all the utility functions that were previously accessed via `import { utils } from '@rjsf/core';` are now available via `import utils from '@rjsf/utils';`. +Because of the decoupling of validation from `@rjsf/core` there is a breaking change for all the [validator-based utility functions](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions#validator-based-utility-functions), since they now require an additional `ValidatorType` parameter. +More over, one previously exported function `resolveSchema()` is no longer exposed in the `@rjsf/utils`, so use `retrieveSchema()` instead. + +If you have built custom fields or widgets that utilized any of these breaking-change functions, don't worry, there is a quick and easy solution for you. +The `registry` has a breaking-change which removes the previously deprecated `definitions` property while adding the new `schemaUtils` property. +This new `registry.schemaUtils` property implements the `SchemaUtilsType` interface, which allows you to call a version of each of these breaking-change functions without the need for passing either a `validator` or `rootSchema`. +Because all fields and widgets are guaranteed to be passed the `registry` as a prop, if your custom field/widget happens to use either the `registry.definitions` object or a breaking-change validator-based utility function you make the following changes: + +```tsx +import { RJSFSchema, FieldProps } from '@rjsf/utils'; + +function YourField(props: FieldProps) { + const { registry } = props; +// Change `registry.definitions` to `registry.rootSchema.definitions` +// const { definitions } = registry; <- version 4 + const { rootSchema } = registry; + const { definitions } = rootSchema; + ... +} +``` + +```tsx +// Change breaking-change function to schemaUtils instead, otherwise import from @rjsf/utils +// import { utils } from '@rjsf/core'; <- version 4 +// const { isMultiSelect, resolveSchema, getUiOptions } = utils; <- version 4 +import { RJSFSchema, WidgetProps, getUiOptions } from '@rjsf/utils'; + +function YourWidget(props: WidgetProps) { + const { registry, uiSchema } = props; + const { schemaUtils } = registry; +// const isMultiSelect = isMultiSelect(schema, rootSchema); <- version 4 +// const newSchema = resolveSchema(schema, formData, rootSchema); <- version 4 + const isMultiSelect = schemaUtils.isMultiSelect(schema); + const newSchema: RJSFSchema = schemaUtils.retrieveSchema(schema, formData); + const options = getUiOptions(uiSchema); + +... +} +``` + +#### validator.js +Because of the decoupling of validation from `@rjsf/core` this file was refactored into its own `@rjsf/validator-ajv6` package. +During that refactor a few **breaking changes** were made to how it works related to custom validation and `ErrorSchema` conversion. + +##### toErrorList param changed +In previous versions, the `toErrorList()` function used to take a `fieldName` string defaulted to `root`, and used it to format the `stack` message. +In version 5, `fieldName` was changed to `fieldPath` string array defaulted to an empty array, and is used to recursively add the field name to the errors as the `property` object along with the raw `message`. +The result is that if you had an `ErrorSchema` that looks like: + +```tsx +const errorSchema: ErrorSchema = { + __error: [ "error message 1"], + password: { __error: "passwords do not match" } +} +``` + +The returned result from calling `toErrorList(errorSchema)` has changed as follows: + +```tsx +// version 4 result +[ + { stack: "root: error message 1" }, + { stack: "password: passwords do not match" } +] + +// version 5 result +[ + { property: ".", message: "error message 1", stack: ". error message 1" }, + { property: ".password", message: "passwords do not match", stack: ".password passwords do not match" } +] +``` + +##### Custom validation and extraErrors +In previous versions, when using a custom validator on the `Form`, any errors that were generated were inconsistently inserted into the validations `errors` list. +In addition, there was an [issue](https://github.com/rjsf-team/react-jsonschema-form/issues/1596) where the non-`stack` AJV error information was lost when custom validation generated errors. +This issue has been fixed. +Also, when `extraErrors` were provided, they were being inconsistently inserted into the `errors` list and the non-`stack` AJV error information was lost. +In version 5, all of these errors will be consistently appended onto the end of the validation `errors` list, and the additional AJV error information is maintained. + +In other words, if custom validation or `extraErrors` produced the following `ErrorSchema`: + +```tsx +{ + __error: [ "Please correct your password"], + password2: { __error: "passwords do not match" } +} +``` + +And the AJV validation produced the following `ErrorSchema`: + +```tsx +{ + __error: [{ + message: "should NOT be shorter than 3 characters", + name: "minLength", + params: { limit: 3 }, + property: ".password2", + schemaPath: "#/properties/password2/minLength", + stack: ".password2 should NOT be shorter than 3 characters", + }] +} +``` + +The resulting `errors` list has changed as follows: + +```tsx +// version 4 +[ + { stack: "root: Please correct your password" }, + { stack: "password2: passwords do not match" }, + { stack: "password2: should NOT be shorter than 3 characters" } +] + +// version 5 +[ + { + message: "should NOT be shorter than 3 characters", + name: "minLength", + params: { limit: 3 }, + property: ".password2", + schemaPath: "#/properties/password2/minLength", + stack: ".password2 should NOT be shorter than 3 characters", + }, + { property: ".", message: "Please correct your password", stack: ". Please correct your password" }, + { property: ".", message: "passwords do not match", stack: ".password2 passwords do not match" } +] +``` + +#### Generate correct ids when arrays are combined with `anyOf`/`oneOf` + +In v4, with arrays inside `anyOf` or `oneOf`, the parent name was not used to generate ids. +For example, given a schema such as: + +```json +{ + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "anyOf": [ + { + "properties": { + "foo": { + "type": "string", + }, + }, + }, + { + "properties": { + "bar": { + "type": "string", + }, + }, + }, + ], + }, + }, + }, +} +``` + +We would get fields with id `root_foo` and `root_bar`. +As you can imagine, we could end up with duplicated ids if there's actually a `foo` or a `bar` in the root of the schema. + +From v5, the child fields will correctly use the parent id when generating its own id, generating ids such as `root_items_0_foo`. + +#### Deprecations added in v5 + +##### Non-standard `enumNames` property + +`enumNames` is a non-standard JSON Schema field that was deprecated in version 5. +`enumNames` could be included in the schema to apply labels that differed from an enumeration value. +This behavior can still be accomplished with `oneOf` or `anyOf` containing `const` values, so `enumNames` support may be removed from a future major version of RJSF. +For more information, see [#532](https://github.com/rjsf-team/react-jsonschema-form/issues/532). + +##### uiSchema.classNames + +In versions previous to 5, `uiSchema.classNames` was the only property that did not require the `ui:` prefix. +Additionally, it did not support being added into the `ui:options` object. +This was fixed in version 5 to be consistent with all the other properties in the `uiSchema`, so the `uiSchema.classNames` support may be removed from a future major version of RJSF. + +If you are using `classNames` as follows, simply add the `ui:` prefix to it to remove the deprecation warning that will be displayed for each `uiSchema.classNames` you have: + +```jsx +// This uiSchema will log a deprecation warning to the console +const uiSchema = { + title: { + "classNames": "myClass" + } +}; +// This uiSchema will not +const uiSchema = { + title: { + "ui:classNames": "myClass" + } +}; +``` + +### `@rjsf/material-ui` BREAKING CHANGES + +This theme was simplified back to working only with Material UI version 4 after an unsuccessful attempt to have it fully support both versions 4 and 5 simultaneously. +As a result, the `MuiComponentContext`, `MuiForm5`, `Theme5` components and the `useMuiComponent` hook were removed from the export. +In addition, the `/v4` and `/v5` sub-packages were also removed. + +#### Migrating for Material UI version 4 +If you were using this theme for Material UI version 4 AND you were using the sub-package, simply remove the `/v4` from your imports. + +If you modified your Typescript configuration for the `/v4` sub-package, remove the following from your `tsconfig.json`: + +``` +{ + ... + "compilerOptions": { + ... + "baseUrl": ".", + "paths": { + "@rjsf/material-ui/*": ["node_modules/@rjsf/material-ui/dist/*"] + } + } +} +``` + +If you modified your Jest configuration for the `/v4` sub-package, remove the following from your `jest.config.json`: + +``` + "moduleNameMapper": { + "@rjsf/material-ui/v4": "/node_modules/@rjsf/material-ui/dist/v4.js" + }, +``` + +#### Migrating for Material UI version 5 +If you were using this theme for Material UI version 5, you will want to use `@rjsf/mui` instead. +See below for some before and after examples. + +If you modified your Typescript configuration for the `/v5` sub-package, remove the following from your `tsconfig.json`: + +``` +{ + ... + "compilerOptions": { + ... + "baseUrl": ".", + "paths": { + "@rjsf/material-ui/*": ["node_modules/@rjsf/material-ui/dist/*"] + } + } +} +``` + +If you modified your Jest configuration for the `/v5` sub-package, remove the following from your `jest.config.json`: + +``` + "moduleNameMapper": { + "@rjsf/material-ui/v5": "/node_modules/@rjsf/material-ui/dist/v5.js" + }, +``` + +##### Before +```jsx +import Form5 from '@rjsf/material-ui'; +``` + or +```jsx +import Form from '@rjsf/material-ui/v5'; +``` + or +```jsx +import { withTheme } from '@rjsf/core'; +import Theme from '@rjsf/material-ui/v5'; +// Make modifications to the theme with your own fields and widgets +const Form = withTheme(Theme); +``` + or +```jsx +import { withTheme } from '@rjsf/core'; +import Theme5 from '@rjsf/material-ui'; +// Make modifications to the theme with your own fields and widgets +const Form = withTheme(Theme5); +``` + +##### After +```jsx +import Form from '@rjsf/mui'; +``` +or +```jsx +import { withTheme } from '@rjsf/core'; +import Theme from '@rjsf/mui'; +// Make modifications to the theme with your own fields and widgets +const Form = withTheme(Theme); +``` diff --git a/docs/advanced-customization/custom-templates.md b/docs/advanced-customization/custom-templates.md index af29a624ba..dc445fee55 100644 --- a/docs/advanced-customization/custom-templates.md +++ b/docs/advanced-customization/custom-templates.md @@ -2,21 +2,55 @@ This is an advanced feature that lets you customize even more aspects of the form: -_ | Custom Field | Custom Template | Custom Widget ---|---------- | ------------- | ---- -**What it does** | Overrides all behaviour | Overrides just the layout (not behaviour) | Overrides just the input box (not layout, labels, or help, or validation) -**Usage** | Global or per-field | Global or per-field | Global or per-field -**Global Example** | `` | `` | `` -**Per-Field Example** | `"ui:field": MyCustomField` | `"ui:ArrayFieldTemplate": MyArrayTemplate` | `"ui:widget":MyCustomWidget` -**Documentation** | [Custom Fields](custom-widgets-fields.md) | [FieldTemplate](#FieldTemplate) / [ArrayFieldTemplate](#ArrayFieldTemplate) / [ObjectFieldTemplate](#ObjectFieldTemplate) | [Custom Widgets](custom-widgets-fields.md) +| | Custom Field | Custom Template | Custom Widget | +|-----------------------|-------------------------------------------|----------------------------------------------------------------|---------------------------------------------------------------------------| +| **What it does** | Overrides all behaviour | Overrides just the layout (not behaviour) | Overrides just the input box (not layout, labels, or help, or validation) | +| **Usage** | Global or per-field | Global or per-field | Global or per-field | +| **Global Example** | `` | `` | `` | +| **Per-Field Example** | `"ui:field": MyCustomField` | `"ui:ArrayFieldTemplate": MyArrayTemplate` | `"ui:widget":MyCustomWidget` | +| **Documentation** | [Custom Fields](custom-widgets-fields.md) | See documentation below | [Custom Widgets](custom-widgets-fields.md) | + +In version 5, all existing `templates` were consolidated into a new `TemplatesType` interface that is provided as part of the `Registry`. +They can also be overloaded globally on the `Form` via the `templates` prop as well as globally or per-field through the `uiSchema`. +Further, many new templates were added or repurposed from existing `widgets` and `fields` in an effort to simplify the effort needed by theme authors to build new and/or maintain current themes. +These new templates can also be overridden by individual users to customize the specific needs of their application. +A special category of templates, `ButtonTemplates`, were also added to support the easy replacement of the `Submit` button on the form, the `Add` and `Remove` buttons associated with `additionalProperties` on objects and elements of arrays, as well as the `Move up` and `Move down` buttons used for reordering arrays. +This category, unlike the others, can only be overridden globally via the `templates` prop on `Form`. + +Below is the table that lists all the `templates`, their props interface, their `uiSchema` name and from where they originated in the previous version of RJSF: + +| Template* | Props Type | UiSchema name | Origin | +|------------------------------------------------------------------|----------------------------|----------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [ArrayFieldTemplate](#ArrayFieldTemplate) | ArrayFieldTemplateProps | ui:ArrayFieldTemplate | Formerly `Form.ArrayFieldTemplate` or `Registry.ArrayFieldTemplate` | +| [ArrayFieldDescriptionTemplate*](#ArrayFieldDescriptionTemplate) | ArrayFieldDescriptionProps | ui:ArrayFieldDescriptionTemplate | Formerly part of `@rjsf/core` ArrayField, refactored as a template, used in all `ArrayFieldTemplate` implementations | +| [ArrayFieldItemTemplate*](#ArrayFieldItemTemplate) | ArrayFieldTemplateItemType | ui:ArrayFieldItemTemplate | Formerly an internal class for `ArrayFieldTemplate`s in all themes, refactored as a template in each theme, used in all `ArrayFieldTemplate` implementations | +| [ArrayFieldTitleTemplate*](#ArrayFieldTitleTemplate) | ArrayFieldTitleProps | ui:ArrayFieldTitleTemplate | Formerly part of `@rjsf/core` ArrayField, refactored as a template, used in all `ArrayFieldTemplate` implementations. | +| [BaseInputTemplate*](#BaseInputTemplate) | WidgetProps | ui:BaseInputTemplate | Formerly a `widget` in `@rjsf.core` moved to `templates` and newly implemented in each theme to maximize code reuse. | +| [DescriptionFieldTemplate*](#DescriptionFieldTemplate) | DescriptionFieldProps | ui:DescriptionFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. Previously implemented in each theme. | +| [ErrorListTemplate*](#ErrorListTemplate) | ErrorListProps | ui:ErrorListTemplate | Formerly `Form.ErrorList` moved to `templates` with the `Templates` suffix. Previously implemented in each theme. | +| [FieldTemplate](#FieldTemplate) | FieldTemplateProps | ui:FieldTemplate | Formerly `Form.FieldTemplate` or `Registry.FieldTemplate` | +| [ObjectFieldTemplate](#ObjectFieldTemplate) | ObjectFieldTemplateProps | ui:ObjectFieldTemplate | Formerly `Form.ObjectFieldTemplate` or `Registry.ObjectFieldTemplate` | +| [TitleFieldTemplate*](#TitleFieldTemplate) | TitleFieldProps | ui:TitleFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. Previously implemented in each theme. | +| [UnsupportedFieldTemplate*](#UnsupportedFieldTemplate) | UnsupportedFieldProps | ui:UnsupportedFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. | +| [ButtonTemplates.AddButton*](#AddButton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.MoveDownButton*](#MoveDownButton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.MoveUpButton*](#MoveUpButton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.RemoveButton*](#RemoveButton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.SubmitButton*](#SubmitButton) | SubmitButtonProps | n/a | Formerly a `field` in each theme move to `templates.ButtonTemplates` | + +\* indicates a new template in version 5 ## ArrayFieldTemplate You can use an `ArrayFieldTemplate` to customize how your arrays are rendered. -This allows you to customize your array, and each element in the array. You can also customize arrays by specifying a widget in the relevant `ui:widget` schema, more details over on [Custom Widgets](../usage/arrays.md#custom-widgets). +This allows you to customize your array, and each element in the array. +If you only want to customize how the array's title, description or how the array items are presented, you may want to consider providing your own [ArrayFieldDescriptionTemplate](#ArrayFieldDescriptionTemplate), [ArrayFieldItemTemplate](#ArrayFieldItemTemplate) and/or [ArrayFieldTitleTemplate](#ArrayFieldTitleTemplate) instead. +You can also customize arrays by specifying a widget in the relevant `ui:widget` schema, more details over on [Custom Widgets](../usage/arrays.md#custom-widgets). +```tsx +import { ArrayFieldTemplateProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; -```jsx const schema = { type: "array", items: { @@ -24,7 +58,7 @@ const schema = { } }; -function ArrayFieldTemplate(props) { +function ArrayFieldTemplate(props: ArrayFieldTemplateProps) { return (
{props.items.map(element => element.children)} @@ -34,8 +68,7 @@ function ArrayFieldTemplate(props) { } render(( - + ), document.getElementById("app")); ``` @@ -47,25 +80,25 @@ const uiSchema = { } ``` -Please see [customArray.js](https://github.com/rjsf-team/react-jsonschema-form/blob/4542cd254ffdc6dfaf55e8c9f6f17dc900d0d041/packages/playground/src/samples/customArray.js) for another example. +Please see [customArray.js](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/playground/src/samples/customArray.js) for another example. The following props are passed to each `ArrayFieldTemplate`: -- `DescriptionField`: The `DescriptionField` from the registry (in case you wanted to utilize it) -- `TitleField`: The `TitleField` from the registry (in case you wanted to utilize it). - `canAdd`: A boolean value stating whether new elements can be added to the array. - `className`: The className string. - `disabled`: A boolean value stating if the array is disabled. -- `idSchema`: Object +- `idSchema`: An object containing the id for this object & ids for its properties - `items`: An array of objects representing the items in the array. Each of the items represent a child with properties described below. - `onAddClick: (event?) => void`: A function that adds a new item to the array. - `readonly`: A boolean value stating if the array is read-only. - `required`: A boolean value stating if the array is required. +- `hideError`: A boolean value stating if the field is hiding its errors. - `schema`: The schema object for this array. - `uiSchema`: The uiSchema object for this array field. - `title`: A string value containing the title for the array. - `formContext`: The `formContext` object that you passed to Form. - `formData`: The formData for this array. +- `rawErrors`: An array of strings listing all generated error messages from encountered errors for this widget - `registry`: The `registry` object. The following props are part of each element in `items`: @@ -83,8 +116,338 @@ The following props are part of each element in `items`: - `onDropIndexClick: (index) => (event?) => void`: Returns a function that removes the item at `index`. - `onReorderClick: (index, newIndex) => (event?) => void`: Returns a function that swaps the items at `index` with `newIndex`. - `readonly`: A boolean value stating if the array item is read-only. +- `registry`: The `registry` object. + +> Note: Array and object field templates are always rendered inside the FieldTemplate. To fully customize an array field template, you may need to specify both `ui:FieldTemplate` and `ui:ArrayFieldTemplate`. + +## ArrayFieldDescriptionTemplate + +The out-of-the-box version of this template will render the `DescriptionFieldTemplate` with a generated id, if there is a `description` otherwise nothing is rendered. +If you want different behavior for the rendering of the description of an array field, you can customize this template. +If you want a different behavior for the rendering of ALL descriptions in the `Form`, see [DescriptionFieldTemplate](#descriptionfieldtemplate) + +```tsx +import { ArrayFieldDescriptionProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "array", + items: { + type: "string" + } +}; + +function ArrayFieldDescriptionTemplate(props: ArrayFieldDescriptionProps) { + const { description, idSchema } = props; + const id = `${idSchema.$id}__description`; + return ( +
+ Description + {description} +
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. + +```js +const uiSchema = { + "ui:ArrayFieldDescriptionTemplate": ArrayFieldDescriptionTemplate +} +``` + +The following props are passed to each `ArrayFieldDescriptionTemplate`: + +- `description`: The description of the array field being rendered. +- `idSchema`: The idSchema of the array field in the hierarchy. +- `uiSchema`: The uiSchema object for this array field. +- `registry`: The `registry` object. + +## ArrayFieldItemTemplate + +The `ArrayFieldItemTemplate` is used to render the representation of a single item in an array. +All of the `ArrayFieldTemplate` implementations in all themes get this template from the `registry` in order to render array fields items. +Each theme has an implementation of the `ArrayFieldItemTemplate` to render an array field item in a manner best suited to the theme. +If you want to change how an array field item is rendered you can customize this template (for instance to remove the move up/down and remove buttons). + +```tsx +import { ArrayFieldTemplateItemType } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "array", + items: { + type: "string" + } +}; + +function ArrayFieldItemTemplate(props: ArrayFieldTemplateItemType) { + const { children, className } = props; + return ( +
{children}
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +The following props are passed to each `ArrayFieldItemTemplate`: + +- `children`: The html for the item's content. +- `className`: The className string. +- `disabled`: A boolean value stating if the array item is disabled. +- `hasMoveDown`: A boolean value stating whether the array item can be moved down. +- `hasMoveUp`: A boolean value stating whether the array item can be moved up. +- `hasRemove`: A boolean value stating whether the array item can be removed. +- `hasToolbar`: A boolean value stating whether the array item has a toolbar. +- `index`: A number stating the index the array item occurs in `items`. +- `key`: A stable, unique key for the array item. +- `onAddIndexClick: (index) => (event?) => void`: Returns a function that adds a new item at `index`. +- `onDropIndexClick: (index) => (event?) => void`: Returns a function that removes the item at `index`. +- `onReorderClick: (index, newIndex) => (event?) => void`: Returns a function that swaps the items at `index` with `newIndex`. +- `readonly`: A boolean value stating if the array item is read-only. +- `registry`: The `registry` object. + +## ArrayFieldTitleTemplate -> Note: Array and object field templates are always rendered inside of the FieldTemplate. To fully customize an array field template, you may need to specify both `ui:FieldTemplate` and `ui:ArrayFieldTemplate`. +The out-of-the-box version of this template will render the `TitleFieldTemplate` with a generated id, if there is a `title` otherwise nothing is rendered. +If you want a different behavior for the rendering of the title of an array field, you can customize this template. +If you want a different behavior for the rendering of ALL titles in the `Form`, see [TitleFieldTemplate](#titlefieldtemplate) + +```tsx +import { ArrayFieldTitleTemplateProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "array", + items: { + type: "string" + } +}; + +function ArrayFieldTitleTemplate(props: ArrayFieldTitleProps) { + const { description, idSchema } = props; + const id = `${idSchema.$id}__title`; + return ( +

+ {title} +

+ ); +} + +render(( + +), document.getElementById("app")); +``` + +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. + +```js +const uiSchema = { + "ui:ArrayFieldTitleTemplate": ArrayFieldTitleTemplate +} +``` + +The following props are passed to each `ArrayFieldTitleTemplate`: + +- `title`: The title of the array field being rendered. +- `idSchema`: The idSchema of the array field in the hierarchy. +- `uiSchema`: The uiSchema object for this array field. +- `required`: A boolean value stating if the field is required +- `registry`: The `registry` object. + +## BaseInputTemplate + +The `BaseInputTemplate` is the template to use to render the basic `` component for a theme. +It is used as the template for rendering many of the `` based widgets that differ by `type` and callbacks only. +For example, the `TextWidget` implementation in `core` is simply a wrapper around `BaseInputTemplate` that it gets from the `registry`. +Additionally, each theme implements its own version of `BaseInputTemplate` without needing to provide a different implementation of `TextWidget`. + +If you desire a different implementation for the `` based widgets, you can customize this template. +For instance, say you have a `CustomTextInput` component that you want to integrate: + +```tsx +import { getInputProps, WidgetProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +import CustomTextInput from '../CustomTextInput'; + +const schema = { + type: "string", + title: "My input", + description: "input description" +}; + +function BaseInputTemplate(props: WidgetProps) { + const { + schema, + id, + options, + label, + value, + type, + placeholder, + required, + disabled, + readonly, + autofocus, + onChange, + onBlur, + onFocus, + rawErrors, + hideError, + uiSchema, + registry, + formContext, + ...rest + } = props; + const onTextChange = ({ target: { value: val } }: React.ChangeEvent) => { + // Use the options.emptyValue if it is specified and newVal is also an empty string + onChange(val === '' ? options.emptyValue || '' : val); + }; + const onTextBlur = ({ target: { value: val } }: React.FocusEvent) => onBlur(id, val); + const onTextFocus = ({ target: { value: val } }: React.FocusEvent) => onFocus(id, val); + + const inputProps = { ...rest, ...getInputProps(schema, type, options) }; + const hasError = rawErrors.length > 0 && !hideError; + + return ( + + ); +} + +render(( + +), document.getElementById("app")); +``` + +The following props are passed to the `BaseInputTemplate`: + +- `id`: The generated id for this widget; +- `schema`: The JSONSchema subschema object for this widget; +- `uiSchema`: The uiSchema for this widget; +- `value`: The current value for this widget; +- `placeholder`: The placeholder for the widget, if any; +- `required`: The required status of this widget; +- `disabled`: A boolean value stating if the widget is disabled; +- `hideError`: A boolean value stating if the widget is hiding its errors. +- `readonly`: A boolean value stating if the widget is read-only; +- `autofocus`: A boolean value stating if the widget should autofocus; +- `label`: The computed label for this widget, as a string +- `multiple`: A boolean value stating if the widget can accept multiple values; +- `onChange`: The value change event handler; call it with the new value every time it changes; +- `onKeyChange`: The key change event handler (only called for fields with `additionalProperties`); pass the new value every time it changes; +- `onBlur`: The input blur event handler; call it with the widget id and value; +- `onFocus`: The input focus event handler; call it with the widget id and value; +- `options`: A map of options passed as a prop to the component (see [Custom widget options](#custom-widget-options)). +- `options.enumOptions`: For enum fields, this property contains the list of options for the enum as an array of { label, value } objects. If the enum is defined using the oneOf/anyOf syntax, the entire schema object for each option is appended onto the { schema, label, value } object. +- `formContext`: The `formContext` object that you passed to `Form`. +- `rawErrors`: An array of strings listing all generated error messages from encountered errors for this widget. +- `registry`: The `registry` object + +## DescriptionFieldTemplate + +Each theme implements a `DescriptionFieldTemplate` used to render the description of a field. +If you want to customize how descriptions are rendered you can. + +```tsx +import { DescriptionFieldProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string", + title: "My input", + description: "input description" +}; + +function DescriptionFieldTemplate(props: DescriptionFieldProps) { + const { description, id } = props; + return ( +
+ Description + {description} +
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +The following props are passed to the `DescriptionFieldTemplate`: + +- `description`: The description of the field being rendered. +- `id`: The id of the field in the hierarchy. +- `registry`: The `registry` object. + +## ErrorListTemplate + +The `ErrorListTemplate` is the template that renders the all the errors associated with the fields in the `Form`, at the top. +Each theme implements a `ErrorListTemplate` used to render its errors using components for the theme's toolkit. +If you want to customize how all the errors are rendered you can. + +```tsx +import { ErrorListProps, RJSFValidationError } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string", + title: "My input", + description: "input description" +}; + +function ErrorListTemplate(props: ErrorListProps) { + const { errors } = props; + return ( +
+ Errors +
    + {errors.map((error: RJSFValidationError, i: number) => { + return ( +
  • + {error.stack} +
  • + ); + })} +
+
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +The following props are passed to the `ErrorListTemplate`: + +- `schema`: The schema that was passed to `Form` +- `uiSchema`: The uiSchema that was passed to `Form` +- `formContext`: The `formContext` object that you passed to `Form`. +- `errors`: An array of all errors in this `Form`. +- `errorSchema`: The `ErrorSchema` constructed by `Form` ## FieldTemplate @@ -92,12 +455,15 @@ To take control over the inner organization of each field (each form row), you c A field template is basically a React stateless component being passed field-related props, allowing you to structure your form row as you like. -```jsx +```tsx +import { FieldTemplateProps } from "@rjsf/utils"; +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; -function CustomFieldTemplate(props) { +function CustomFieldTemplate(props: FieldTemplateProps) { const {id, classNames, label, help, required, description, errors, children} = props; return (
@@ -111,8 +477,7 @@ function CustomFieldTemplate(props) { } render(( - + ), document.getElementById("app")); ``` @@ -134,6 +499,7 @@ The following props are passed to a custom field template component: - `description`: A component instance rendering the field description, if one is defined (this will use any [custom `DescriptionField`](#custom-descriptions) defined). - `rawDescription`: A string containing any `ui:description` uiSchema directive defined. - `children`: The field or widget component instance for this field row. +- `hideError`: A boolean value stating if the field is hiding its errors. - `errors`: A component instance listing any encountered errors for this field. - `rawErrors`: An array of strings listing all generated error messages from encountered errors for this field. - `help`: A component instance rendering any `ui:help` uiSchema directive defined. @@ -144,11 +510,10 @@ The following props are passed to a custom field template component: - `hideError`: A boolean value stating if the field is hiding its errors - `disabled`: A boolean value stating if the field is disabled. - `displayLabel`: A boolean value stating if the label should be rendered or not. This is useful for nested fields in arrays where you don't want to clutter the UI. -- `fields`: An array containing all Form's fields including your [custom fields](#custom-field-components) and the built-in fields. - `schema`: The schema object for this field. - `uiSchema`: The uiSchema object for this field. - `onChange`: The value change event handler; Can be called with a new value to change the value for this field. -- `formContext`: The `formContext` object that you passed to Form. +- `formContext`: The `formContext` object that you passed to `Form`. - `formData`: The formData for this field. - `registry`: The `registry` object. @@ -156,7 +521,10 @@ The following props are passed to a custom field template component: ## ObjectFieldTemplate -```jsx +```tsx +import { ObjectFieldTemplateProps } from "@rjsf/utils"; +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "object", title: "Object title", @@ -171,7 +539,7 @@ const schema = { } }; -function ObjectFieldTemplate(props) { +function ObjectFieldTemplate(props: ObjectFieldTemplateProps) { return (
{props.title} @@ -182,8 +550,7 @@ function ObjectFieldTemplate(props) { } render(( - + ), document.getElementById("app")); ``` @@ -195,22 +562,21 @@ const uiSchema = { }; ``` -Please see [customObject.js](https://github.com/rjsf-team/react-jsonschema-form/blob/4542cd254ffdc6dfaf55e8c9f6f17dc900d0d041/packages/playground/src/samples/customObject.js) for a better example. +Please see [customObject.js](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/playground/src/samples/customObject.js) for a better example. -The following props are passed to each `ObjectFieldTemplate`: +The following props are passed to each `ObjectFieldTemplate` as defined by the `ObjectFieldTemplateProps` in `@rjsf/utils`: -- `DescriptionField`: The `DescriptionField` from the registry (in case you wanted to utilize it) -- `TitleField`: The `TitleField` from the registry (in case you wanted to utilize it). - `title`: A string value containing the title for the object. - `description`: A string value containing the description for the object. - `disabled`: A boolean value stating if the object is disabled. -- `properties`: An array of object representing the properties in the array. Each of the properties represent a child with properties described below. -- `onAddClick: (schema: JSONSchema7) => () => void`: Returns a function that adds a new property to the object (to be used with additionalProperties) +- `properties`: An array of object representing the properties in the object. Each of the properties represent a child with properties described below. +- `onAddClick: (schema: RJSFSchema) => () => void`: Returns a function that adds a new property to the object (to be used with additionalProperties) - `readonly`: A boolean value stating if the object is read-only. - `required`: A boolean value stating if the object is required. +- `hideError`: A boolean value stating if the field is hiding its errors. - `schema`: The schema object for this object. - `uiSchema`: The uiSchema object for this object field. -- `idSchema`: An object containing the id for this object & ids for it's properties. +- `idSchema`: An object containing the id for this object & ids for its properties. - `formData`: The form data for the object. - `formContext`: The `formContext` object that you passed to Form. - `registry`: The `registry` object. @@ -223,4 +589,243 @@ The following props are part of each element in `properties`: - `readonly`: A boolean value stating if the property is read-only. - `hidden`: A boolean value stating if the property should be hidden. -> Note: Array and object field templates are always rendered inside of the FieldTemplate. To fully customize an object field template, you may need to specify both `ui:FieldTemplate` and `ui:ObjectFieldTemplate`. +> 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`. + +## TitleFieldTemplate + +Each theme implements a `TitleFieldTemplate` used to render the title of a field. +If you want to customize how titles are rendered you can. + +```tsx +import { TitleFieldProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string", + title: "My input", + description: "input description" +}; + +function TitleFieldTemplate(props: TitleFieldProps) { + const { id, required, title } = props; + return ( +
+ {title} + {required && *} +
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +The following props are passed to each `TitleFieldTemplate`: + +- `id`: The id of the field in the hierarchy. +- `title`: The title of the field being rendered. +- `uiSchema`: The uiSchema object for this field. +- `required`: A boolean value stating if the field is required +- `registry`: The `registry` object. + +## UnsupportedFieldTemplate + +The `UnsupportedField` component is used to render a field in the schema is one that is not supported by react-jsonschema-form. +If you want to customize how an unsupported field is rendered (perhaps for localization purposes) you can. + +```tsx +import { UnsupportedFieldProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "invalid" +}; + +function UnsupportedFieldTemplate(props: UnsupportedFieldProps) { + const { schema, reason } = props; + return ( +
+ +
{JSON.stringify(schema, null, 2)}
+
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +The following props are passed to each `UnsupportedFieldTemplate`: + +- `schema`: The schema object for this unsupported field. +- `idSchema`: An object containing the id for this unsupported field. +- `reason`: The reason why the schema field has an unsupported type. +- `registry`: The `registry` object. + +## ButtonTemplates + +There are several buttons that are potentially rendered in the `Form`. +Each of these buttons have been customized in the themes, and can be customized by you as well. +All but one of these buttons (i.e. the `SubmitButton`) are rendered currently as icons with title text for a description. + +Each button template (except for the `SubmitButton`) accepts, as props, the standard [HTML button attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) along with the following: + +- `iconType`: An alternative specification for the type of the icon button. +- `icon`: The name representation or actual react element implementation for the icon. + +### AddButton + +The `AddButton` is used to render an add action on a `Form` for both a new `additionalProperties` element for an object or a new element in an array. +You can customize the `AddButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string" +}; + +function AddButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +}; + +render(( + +), document.getElementById("app")); +``` + +### MoveDownButton + +The `MoveDownButton` is used to render a move down action on a `Form` for elements in an array. +You can customize the `MoveDownButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string" +}; + +function MoveDownButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +}; + +render(( + +), document.getElementById("app")); +``` + +### MoveUpButton + +The `MoveUpButton` is used to render a move up action on a `Form` for elements in an array. +You can customize the `MoveUpButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string" +}; + +function MoveUpButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +}; + +render(( + +), document.getElementById("app")); +``` + +### RemoveButton + +The `RemoveButton` is used to render a remove action on a `Form` for both a existing `additionalProperties` element for an object or an existing element in an array. +You can customize the `RemoveButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string" +}; + +function RemoveButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +}; + +render(( + +), document.getElementById("app")); +``` + +### SubmitButton + +The `SubmitButton` is already very customizable via the `UISchemaSubmitButtonOptions` capabilities in the `uiSchema` but it can also be fully customized as you see fit. +> NOTE: However you choose to implement this, making it something other than a `submit` type `button` may result in the `Form` not submitting when pressed. +> You could also choose to provide your own submit button as the [children prop](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/form-props#children) of the `Form` should you so choose. + +```tsx +import React from "react"; +import { getSubmitButtonOptions, SubmitButtonProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "string" +}; + +function SubmitButton(props: SubmitButtonProps) { + const { uiSchema } = props; + const { norender } = getSubmitButtonOptions(uiSchema); + if (norender) { + return null; + } + return ( + + ); +}; + +render(( + +), document.getElementById("app")); +``` + +The following prop is passed to a `SubmitButton`: + +- `uiSchema`: The uiSchema object for this field, used to extract the `UISchemaSubmitButtonOptions`. diff --git a/docs/advanced-customization/custom-themes.md b/docs/advanced-customization/custom-themes.md index a90db5a0e9..ac2e493196 100644 --- a/docs/advanced-customization/custom-themes.md +++ b/docs/advanced-customization/custom-themes.md @@ -1,11 +1,13 @@ # Custom Themes -The `withTheme` component provides an easy way to extend the functionality of react-jsonschema-form by passing in a theme object that defines custom/overridden widgets and fields, as well as any of the other possible properties of the standard rjsf `Form` component. This theme-defining object is passed as the only parameter to the HOC (`withTheme(ThemeObj)`), and the HOC will return a themed-component which you use instead of the standard `Form` component. +The `withTheme` component provides an easy way to extend the functionality of react-jsonschema-form by passing in a theme object that defines custom/overridden widgets and fields, as well as any of the other possible properties of the standard rjsf `Form` component. +This theme-defining object is passed as the only parameter to the HOC (`withTheme(ThemeObj)`), and the HOC will return a themed-component which you use instead of the standard `Form` component. ## Usage ```jsx import React, { Component } from 'react'; +import validator from '@rjsf/validator-ajv6'; import { withTheme } from '@rjsf/core'; const theme = { widgets: {test: () => (
test
) } }; @@ -13,12 +15,17 @@ const theme = { widgets: {test: () => (
test
) } }; const ThemedForm = withTheme(theme); const Demo = () => ( - + ); ``` ## Theme object properties -The Theme object consists of the same properties as the rjsf `Form` component (such as **widgets** and **fields**). The themed-Form component merges together any theme-specific **widgets** and **fields** with the default **widgets** and **fields**. For instance, providing a single widget in **widgets** will merge this widget with all the default widgets of the rjsf `Form` component, but overrides the default if the theme's widget's name matches the default widget's name. Thus, for each default widget or field not specified/overridden, the themed-form will rely on the defaults from the rjsf `Form`. Note that you are not required to pass in either custom **widgets** or **fields** when using the custom-themed HOC component; you can make the essentially redefine the default Form by simply doing `const Form = withTheme({});`. +The Theme object consists of the same properties as the rjsf `Form` component (such as **widgets**, **fields** and **templates**). +The themed-Form component merges together any theme-specific **widgets**, **fields** and **templates** with the default **widgets**, **fields** and **templates**. +For instance, providing a single widget in **widgets** will merge this widget with all the default widgets of the rjsf `Form` component, but overrides the default if the theme's widget's name matches the default widget's name. +Thus, for each default widget or field not specified/overridden, the themed-form will rely on the defaults from the rjsf `Form`. +Note that you are not required to pass in either custom **widgets**, **fields** or **templates** when using the custom-themed HOC component; +you can essentially redefine the default Form by simply doing `const Form = withTheme({});`. ### Widgets and fields **widgets** and **fields** should be in the same format as shown [here](/advanced-customization/#custom-widgets-and-fields). @@ -39,14 +46,14 @@ const myWidgets = { myCustomWidget: MyCustomWidget }; -const ThemeObject = {widgets: myWidgets}; +const ThemeObject = { widgets: myWidgets }; export default ThemeObject; ``` -The above can be similarly done for **fields**. +The above can be similarly done for **fields** and **templates**. ### Templates -Each template should be passed directly into the theme object just as you would into the rjsf Form component. Here is an example of how to use a custom [ArrayFieldTemplate](/advanced-customization/#array-field-template) and [ErrorListTemplate](/advanced-customization/#error-list-template) in the theme object: +Each template should be passed into the theme object via the **templates** object just as you would into the rjsf Form component. Here is an example of how to use a custom [ArrayFieldTemplate](/advanced-customization/#array-field-template) and [ErrorListTemplate](/advanced-customization/#error-list-template) in the theme object: ```jsx function MyArrayFieldTemplate(props) { return ( @@ -71,8 +78,10 @@ function MyErrorListTemplate(props) { } const ThemeObject = { - ArrayFieldTemplate: MyArrayFieldTemplate, - ErrorList: MyErrorListTemplate, + templates: { + ArrayFieldTemplate: MyArrayFieldTemplate, + ErrorListTemplate: MyErrorListTemplate, + }, widgets: myWidgets }; @@ -80,10 +89,12 @@ export default ThemeObject; ``` ## Overriding other Form props -Just as the theme can override **widgets**, **fields**, any of the field templates, and set default values to properties like **showErrorList**, you can do the same with the instance of the withTheme() Form component. +Just as the theme can override **widgets**, **fields**, any of the **templates**, and set default values to properties like **showErrorList**, you can do the same with the instance of the withTheme() Form component. ```jsx const ThemeObject = { - ArrayFieldTemplate: MyArrayFieldTemplate, + templates: { + ArrayFieldTemplate: MyArrayFieldTemplate, + }, fields: myFields, showErrorList: false, widgets: myWidgets diff --git a/docs/advanced-customization/custom-widgets-fields.md b/docs/advanced-customization/custom-widgets-fields.md index 895766557e..df82520a2e 100644 --- a/docs/advanced-customization/custom-widgets-fields.md +++ b/docs/advanced-customization/custom-widgets-fields.md @@ -10,6 +10,8 @@ The API allows to specify your own custom *widget* and *field* components: You can override any default field and widget, including the internal widgets like the `CheckboxWidget` that `ObjectField` renders for boolean values. You can override any field and widget just by providing the customized fields/widgets in the `fields` and `widgets` props: ```jsx +import validator from '@rjsf/validator-ajv6'; + const schema = { type: "boolean", default: true @@ -32,9 +34,7 @@ const widgets = { }; render(( - + ), document.getElementById("app")); ``` @@ -97,6 +97,8 @@ You can provide your own custom widgets to a uiSchema for the following json dat - `array` ```jsx +import validator from '@rjsf/validator-ajv6'; + const schema = { type: "string" }; @@ -114,8 +116,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -125,18 +126,20 @@ The following props are passed to custom widget components: - `schema`: The JSONSchema subschema object for this widget; - `uiSchema`: The uiSchema for this widget; - `value`: The current value for this widget; -- `placeholder`: the placeholder for the field, if any; +- `placeholder`: The placeholder for the widget, if any; - `required`: The required status of this widget; -- `disabled`: `true` if the widget is disabled; -- `readonly`: `true` if the widget is read-only; -- `autofocus`: `true` if the widget should autofocus; +- `disabled`: A boolean value stating if the widget is disabled; +- `readonly`: A boolean value stating if the widget is read-only; +- `autofocus`: A boolean value stating if the widget should autofocus; +- `label`: The computed label for this widget, as a string +- `multiple`: A boolean value stating if the widget can accept multiple values; - `onChange`: The value change event handler; call it with the new value every time it changes; - `onKeyChange`: The key change event handler (only called for fields with `additionalProperties`); pass the new value every time it changes; -- `onBlur`: The input blur event handler; call it with the the widget id and value; -- `onFocus`: The input focus event handler; call it with the the widget id and value; +- `onBlur`: The input blur event handler; call it with the widget id and value; +- `onFocus`: The input focus event handler; call it with the widget id and value; - `options`: A map of options passed as a prop to the component (see [Custom widget options](#custom-widget-options)). - `options.enumOptions`: For enum fields, this property contains the list of options for the enum as an array of { label, value } objects. If the enum is defined using the oneOf/anyOf syntax, the entire schema object for each option is appended onto the { schema, label, value } object. -- `formContext`: The `formContext` object that you passed to Form. +- `formContext`: The `formContext` object that you passed to `Form`. - `rawErrors`: An array of strings listing all generated error messages from encountered errors for this widget. - `registry`: A [registry](#the-registry-object) object (read next). @@ -145,6 +148,8 @@ The following props are passed to custom widget components: Alternatively, you can register them all at once by passing the `widgets` prop to the `Form` component, and reference their identifier from the `uiSchema`: ```jsx +import validator from '@rjsf/validator-ajv6'; + const MyCustomWidget = (props) => { return ( + ), document.getElementById("app")); ``` @@ -182,6 +184,8 @@ This is useful if you expose the `uiSchema` as pure JSON, which can't carry func If you need to pass options to your custom widget, you can add a `ui:options` object containing those properties. If the widget has `defaultProps`, the options will be merged with the (optional) options object from `defaultProps`: ```jsx +import validator from '@rjsf/validator-ajv6'; + const schema = { type: "string" }; @@ -207,8 +211,7 @@ const uiSchema = { // renders red on yellow input render(( - + ), document.getElementById("app")); ``` @@ -227,6 +230,8 @@ You can provide your own field components to a uiSchema for basically any json s For example, let's create and register a dumb `geo` component handling a *latitude* and a *longitude*: ```jsx +import validator from '@rjsf/validator-ajv6'; + const schema = { type: "object", required: ["lat", "lon"], @@ -272,10 +277,7 @@ const fields = {geo: GeoPosition}; // Render the form with all the properties we just defined passed // as props render(( - + ), document.getElementById("app")); ``` @@ -285,25 +287,33 @@ render(( A field component will always be passed the following props: - - `schema`: The JSON schema for this field; + - `schema`: The JSON subschema object for this field; - `uiSchema`: The [uiSchema](#the-uischema-object) for this field; - `idSchema`: The tree of unique ids for every child field; - `formData`: The data for this field; - `errorSchema`: The tree of errors for this field and its children; - `registry`: A [registry](#the-registry-object) object (read next). - `formContext`: A [formContext](#the-formcontext-object) object (read next). + - `required`: The required status of this field; + - `disabled`: A boolean value stating if the field is disabled; + - `readonly`: A boolean value stating if the field is read-only; + - `autofocus`: A boolean value stating if the field should autofocus; + - `name`: The unique name of the field, usually derived from the name of the property in the JSONSchema + - `onChange`: The field change event handler; called with the updated form data and an optional `ErrorSchema` + - `onBlur`: The input blur event handler; call it with the field id and value; + - `onFocus`: The input focus event handler; call it with the field id and value; ## The `registry` object -The `registry` is an object containing the registered custom fields and widgets as well as the root schema definitions. +The `registry` is an object containing the registered core, theme and custom fields and widgets as well as the root schema, form context, schema utils. - - `fields`: All fields, including [custom registered fields](#custom-field-components), if any; - - `widgets`: All widgets, including, [custom registered widgets](#custom-widget-components), if any; - - `rootSchema`: The root schema, which can contain referenced [definitions](#schema-definitions-and-references); - - `formContext`: The [formContext](#the-formcontext-object) object; - - `definitions` (deprecated since v2): Equal to `rootSchema.definitions`. + - `fields`: The set of all fields used by the `Form`. Includes fields from `core`, theme-specific fields and any [custom registered fields](#custom-field-components); + - `widgets`: The set of all widgets used by the `Form`. Includes widgets from `core`, theme-specific widgets and any [custom registered widgets](#custom-widget-components), if any; + - `rootSchema`: The root schema, as passed to the `Form`, which can contain referenced [definitions](#schema-definitions-and-references); + - `formContext`: The [formContext](#the-formcontext-object) that was passed to `Form`; + - `schemaUtils`: The current implementation of the `SchemaUtilsType` (from `@rjsf/utils`) in use by the `Form`. Used to call any of the validation-schema-based utility functions. -The registry is passed down the component tree, so you can access it from your custom field, custom widget, and `SchemaField` components. +The registry is passed down the component tree, so you can access it from your custom field, custom widget, custom template and `SchemaField` components. ### Custom SchemaField @@ -314,6 +324,7 @@ You can provide your own implementation of the `SchemaField` base React componen To proceed so, pass a `fields` object having a `SchemaField` property to your `Form` component; here's an example: ```jsx +import validator from '@rjsf/validator-ajv6'; const CustomSchemaField = function(props) { return ( @@ -333,13 +344,10 @@ const schema = { }; render(( - + ), document.getElementById("app")); ``` If you're curious how this could ever be useful, have a look at the [Kinto formbuilder](https://github.com/Kinto/formbuilder) repository to see how it's used to provide editing capabilities to any form field. Props passed to a custom SchemaField are the same as [the ones passed to a custom field](#field-props). - -NOTE: If you are using the `material-ui` theme and are considering customizing a widget or a field, checkout this [guide](material-ui/customizing-material-ui.md). diff --git a/docs/advanced-customization/internals.md b/docs/advanced-customization/internals.md index c0db02427b..ff8b84f448 100644 --- a/docs/advanced-customization/internals.md +++ b/docs/advanced-customization/internals.md @@ -4,7 +4,7 @@ Miscellaneous internals of react-jsonschema-form are listed here. ## JSON Schema supporting status -This component follows [JSON Schema](http://json-schema.org/documentation.html) specs. We currently support JSON Schema-07 by default, but we also support other JSON schema versions through the [custom schema validation](https://react-jsonschema-form.readthedocs.io/en/latest/validation/#custom-schema-validation) feature. Due to the limitation of form widgets, there are some exceptions as follows: +This component follows [JSON Schema](http://json-schema.org/documentation.html) specs. We currently support JSON Schema-07 by default, but we also support other JSON schema versions through the [custom schema validation](https://react-jsonschema-form.readthedocs.io/en/stable/validation/#custom-schema-validation) feature. Due to the limitation of form widgets, there are some exceptions as follows: * `additionalItems` keyword for arrays @@ -62,6 +62,8 @@ You can use the reference to get your `Form` component and call the `submit` met This method will dispatch the `submit` event of the form, and the function, that is passed to `onSubmit` props, will be called. ```jsx +import validator from "@rjsf/validator-ajv6"; + const onSubmit = ({formData}) => console.log("Data submitted: ", formData); let yourForm; @@ -70,8 +72,7 @@ const schema = { }; render(( - {yourForm = form;}}/> + {yourForm = form;}}/> ), document.getElementById("app")); yourForm.submit(); diff --git a/docs/advanced-customization/material-ui/customizing-material-ui.md b/docs/advanced-customization/material-ui/customizing-material-ui.md deleted file mode 100644 index 331616d736..0000000000 --- a/docs/advanced-customization/material-ui/customizing-material-ui.md +++ /dev/null @@ -1,106 +0,0 @@ -# Customizing material-ui fields and widgets - -Unlike most other themes, the `material-ui` theme supports the two distinct version of Material UI (versions 4 and 5) side-by-side. -Material UI version 4 is provided by the scoped packages under `@material-ui` and version 5 is provided by the scoped packages under `@mui`. - -The components used by `@rjsf/material-ui` for Material UI version 4 and version 5 have identical names and props. -As a result, all of the `fields` and `widgets` provided by the theme are identical as well. -The trick to making the two versions function side-by-side, was done by creating a React context, `MuiComponentContext`, that provides the appropriate set of components used by theme, for the particular scoped package. - -In addition to this context, a custom hook, `useMuiComponent()`, is provided to allow quick access to that component set. - -## Example of a custom widget for `@rjsf/material-ui` - -Here is an update to the `MyCustomWidget` for the `material-ui` theme - -```jsx -const schema = { - type: "string" -}; - -import { useMuiComponent } from '@rjsf/material-ui/v4'; - -function MyCustomWidget(props) { - const { options, ...otherProps } = props; - const { color, backgroundColor } = options; - const { TextInput } = useMuiComponent(); - return ; -} - -MyCustomWidget.defaultProps = { - options: { - color: "red" - } -}; - -const uiSchema = { - "ui:widget": MyCustomWidget, - "ui:options": { - backgroundColor: "yellow" - } -}; - -// renders red on yellow input -render(( - -), document.getElementById("app")); -``` - -## Example of a custom field for `@rjsf/material-ui` - -Here is an update to the `GeoPosition` for the `material-ui` theme - -```jsx -const schema = { - type: "object", - required: ["lat", "lon"], - properties: { - lat: { type: "number"}, - lon: { type: "number" } - } -}; - -import { useMuiComponent } from '@rjsf/material-ui/v4'; - -// Define a custom component for handling the root position object -function GeoPosition(props) { - const { lat, lon } = props.formData; - const { Box, TextInput } = useMuiComponent(); - - const onChangeLat = (event) => { - const { target: { value } } = event; - const newData = { ...props.formData, lat: value }; - props.onChange(newData); - }; - - const onChangeLon = (event) => { - const { target: { value } } = event; - const newData = { ...props.formData, lon: value }; - props.onChange(newData); - }; - - return ( - - - - - ); -} - -// Define the custom field component to use for the root object -const uiSchema = { "ui:field": "geo" }; - -// Define the custom field components to register; here our "geo" -// custom field component -const fields = { geo: GeoPosition }; - -// Render the form with all the properties we just defined passed -// as props -render(( - -), document.getElementById("app")); -``` diff --git a/docs/api-reference/form-props.md b/docs/api-reference/form-props.md index 37609169c7..0fac4cc2af 100644 --- a/docs/api-reference/form-props.md +++ b/docs/api-reference/form-props.md @@ -10,14 +10,6 @@ The value of this prop will be passed to the `action` [HTML attribute on the for Note that this just renders the `action` attribute in the HTML markup. There is no real network request being sent to this `action` on submit. Instead, react-jsonschema-form catches the submit event with `event.preventDefault()` and then calls the [`onSubmit`](#onSubmit) function, where you could send a request programmatically with `fetch` or similar. -## additionalMetaSchemas - -This prop allows you to validate the form data against another JSON Schema meta schema, for example, JSON Schema draft-04. See [Validation](../usage/validation.md) for more information. - -## ArrayFieldTemplate - -React component used to customize how alls arrays are rendered on the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. - ## autoComplete The value of this prop will be passed to the `autocomplete` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-autocomplete). @@ -35,12 +27,14 @@ The value of this prop will be passed to the `class` [HTML attribute on the form You can provide custom buttons to your form via the `Form` component's `children`. Otherwise a default submit button will be rendered. ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; render(( - +
@@ -51,43 +45,47 @@ render(( > **Warning:** There needs to be a button or an input with `type="submit"` to trigger the form submission (and then the form validation). -## customFormats +## customValidate -This prop allows you to define custom formats for validation. See [Validation](../usage/validation.md) for more information. +Formerly the `validate` prop. +The `customValidate` prop requires a function that specifies custom validation rules for the form. +See [Validation](../usage/validation.md) for more information. ## disabled It's possible to disable the whole form by setting the `disabled` prop. The `disabled` prop is then forwarded down to each field of the form. ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; render(( - + ), document.getElementById("app")); ``` -If you just want to disable some of the fields, see the `ui:disabled` parameter in `uiSchema`. +If you just want to disable some fields, see the `ui:disabled` parameter in `uiSchema`. ## readonly It's possible to make the whole form read-only by setting the `readonly` prop. The `readonly` prop is then forwarded down to each field of the form. ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; render(( - + ), document.getElementById("app")); ``` -If you just want to make some of the fields read-only, see the `ui:readonly` parameter in `uiSchema`. +If you just want to make some fields read-only, see the `ui:readonly` parameter in `uiSchema`. ## enctype @@ -105,10 +103,6 @@ You can pass a React component to this prop to customize how form errors are dis Dictionary of registered fields in the form. See [Custom Widgets and Fields](../advanced-customization/custom-widgets-fields.md) for more information. -## FieldTemplate - -React component used to customize each field of the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. - ## formContext You can provide a `formContext` object to the Form, which is passed down to all fields and widgets. Useful for implementing context aware fields and widgets. @@ -127,13 +121,14 @@ The value of this prop will be passed to the `id` [HTML attribute on the form](h To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids (the default is `root`). ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; render(( - + ), document.getElementById("app")); ``` @@ -144,6 +139,8 @@ This will render `` instead of ` + ), document.getElementById("app")); ``` @@ -181,16 +177,12 @@ The value of this prop will be passed to the `name` [HTML attribute on the form] ## noHtml5Validate -If set to true, turns off HTML5 validation on the form. Set to `false` on default. +If set to true, turns off HTML5 validation on the form. Set to `false` by default. ## noValidate If set to true, turns off all validation. Set to `false` by default. -## ObjectFieldTemplate - -React component used to customize how all objects are rendered in the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. - ## omitExtraData If set to true, then extra form data values that are not in any form field will be removed whenever `onSubmit` is called. Set to `false` by default. @@ -208,14 +200,15 @@ If you plan on being notified every time the form data are updated, you can pass To react when submitted form data are invalid, pass an `onError` handler. It will be passed the list of encountered errors: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; const onError = (errors) => console.log("I have", errors.length, "errors to fix"); render(( - + ), document.getElementById("app")); ``` @@ -228,14 +221,15 @@ Sometimes you may want to trigger events or modify external state when a field h You can pass a function as the `onSubmit` prop of your `Form` component to listen to when the form is submitted and its data are valid. It will be passed a result object having a `formData` attribute, which is the valid form data you're usually after. The original event will also be passed as a second parameter: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "string" }; const onSubmit = ({formData}, e) => console.log("Data submitted: ", formData); render(( - + ), document.getElementById("app")); ``` @@ -243,7 +237,7 @@ render(( ## schema -Form schema. We support JSON schema draft-07 by default. See [Schema Reference](https://json-schema.org/draft-07/json-schema-release-notes.html) for more information. +**Required**! Form schema. We support JSON schema draft-07 by default. See [Schema Reference](https://json-schema.org/draft-07/json-schema-release-notes.html) for more information. ## showErrorList @@ -256,17 +250,18 @@ It's possible to change the default `form` tag name to a different HTML tag, whi ```jsx ``` You can also provide a class/function component. - ```jsx const CustomForm = props => // ... ``` @@ -274,6 +269,10 @@ const CustomForm = props => The value of this prop will be passed to the `target` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-target). +## templates + +Dictionary of registered templates in the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. + ## transformErrors A function can be passed to this prop in order to make modifications to the default errors resulting from JSON Schema validation. See [Validation](../usage/validation.md) for more information. @@ -282,9 +281,10 @@ A function can be passed to this prop in order to make modifications to the defa Form uiSchema. See [uiSchema Reference](uiSchema.md) for more information. -## validate +## validator -The `validate` prop requires a function that specifies custom validation rules for the form. See [Validation](../usage/validation.md) for more information. +**Required**! An implementation of the `ValidatorType` interface that is needed for form validation to work. +`@rjsf/validator-ajv6` exports the implementation of this interface from RJSF version 4. ## widgets diff --git a/docs/api-reference/themes/semantic-ui/uiSchema.md b/docs/api-reference/themes/semantic-ui/uiSchema.md index bc3f8fb257..858583d04a 100644 --- a/docs/api-reference/themes/semantic-ui/uiSchema.md +++ b/docs/api-reference/themes/semantic-ui/uiSchema.md @@ -73,6 +73,8 @@ horizontalButtons: horizontal buttons instead of the default vertical ``` ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -90,7 +92,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` diff --git a/docs/api-reference/uiSchema.md b/docs/api-reference/uiSchema.md index 98a272a310..219826ae8a 100644 --- a/docs/api-reference/uiSchema.md +++ b/docs/api-reference/uiSchema.md @@ -5,22 +5,23 @@ A UI schema is basically an object literal providing information on **how** the The uiSchema object follows the tree structure of the form field hierarchy, and defines how each property should be rendered. -Note that every property within uiSchema can be rendered in one of two ways: `{"ui:options": {[property]: [value]}}`, or `{"ui:[property]": value}`. +Note that almost every property within uiSchema can be rendered in one of two ways: `{"ui:options": {[property]: [value]}}`, or `{"ui:[property]": value}`. -In other words, the following uiSchemas are equivalent: +In other words, the following `uiSchema`s are equivalent: ```json { "ui:title": "Title", "ui:description": "Description", + "ui:classNames": "my-class", "ui:submitButtonOptions": { "props": { "disabled": false, "className": "btn btn-info", }, - "norender": false, - "submitText": "Submit" - }, + "norender": false, + "submitText": "Submit" + } } ``` @@ -29,6 +30,7 @@ In other words, the following uiSchemas are equivalent: "ui:options": { "title": "Title", "description": "Description", + "classNames": "my-class", "submitButtonOptions": { "props": { "disabled": false, @@ -36,19 +38,62 @@ In other words, the following uiSchemas are equivalent: }, "norender": false, "submitText": "Submit" - }, + } } } ``` -## classNames +For a full list of what is supported in the `uiSchema` see the `UiSchema` type in [@rjsf/utils/types.ts](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/utils/src/types.ts). +Be sure to pay attention to the hierarchical intersection to these other types: `UIOptionsBaseType` and `TemplatesType`. + +## Exceptions to the equivalence +There are 3 properties that exist in a `UiSchema` that will not be found in an inner `ui:options` object. + +### ui:rootFieldId + +By default, this library will generate ids unique to the form for all rendered widgets. +If you plan on using multiple instances of the `Form` component in a same page, it's wise to declare a root prefix for these, using the `ui:rootFieldId` uiSchema directive: + +```js +const uiSchema = { + "ui:rootFieldId": "myform" +}; +``` + +This will make all widgets have an id prefixed with `myform`. + +### ui:field + +The `ui:field` property overrides the `Field` implementation used for rendering any field in the form's hierarchy. +Specify either the name of a field that is used to look up an implementation from the `fields` list or an actual one-off `Field` component implementation itself. + +See [Custom Widgets and Fields](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/custom-widgets-fields#custom-field-components) for more information about how to use this property. + +### ui:options + +The `ui:options` property cannot be nested inside itself and thus is the last exception. + +## ui:XXX or ui:options.XXX + +All the properties that follow can be specified in the `uiSchema` in either of the two equivalent ways. + +NOTE: The properties specific to array items can be found [here](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/arrays#array-item-uiSchema-options) + +### widget + +The `ui:field` property overrides the `Widget` implementation used for rendering any field in the form's hierarchy. +Specify either the name of a widget that is used to look up an implementation from the `widgets` list or an actual one-off `Widget` component implementation itself. + +See [Custom Widgets and Fields](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/custom-widgets-fields) for more information about how to use this property. + +### classNames The uiSchema object accepts a `classNames` property for each field of the schema: ```jsx const uiSchema = { title: { - classNames: "task-title foo-bar" + "ui:classNames": "task-title foo-bar" } }; ``` @@ -64,7 +109,19 @@ Will result in:
``` -## autofocus +### autocomplete + +If you want to mark a text input, select or textarea input to use the HTML autocomplete feature, set the `ui:autocomplete` uiSchema directive to a valid [HTML autocomplete value](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values). + +```js +const schema = {type: "string"}; +const uiSchema = { + "ui:widget": "textarea", + "ui:autocomplete": "on" +} +``` + +### autofocus If you want to automatically focus on a text input or textarea input, set the `ui:autofocus` uiSchema directive to `true`. @@ -76,7 +133,7 @@ const uiSchema = { } ``` -## description +### description Sometimes it's convenient to change the description of a field. This is the purpose of the `ui:description` uiSchema directive: @@ -88,13 +145,17 @@ const uiSchema = { }; ``` -## disabled +### disabled The `ui:disabled` uiSchema directive will disable all child widgets from a given field. > Note: If you're wondering about the difference between a `disabled` field and a `readonly` one: Marking a field as read-only will render it greyed out, but its text value will be selectable. Disabling it will prevent its value to be selected at all. -## enumDisabled +### emptyValue + +The `ui:emptyValue` uiSchema directive provides the default value to use when an input for a field is empty + +### enumDisabled To disable an option, use the `enumDisabled` property in uiSchema. @@ -109,7 +170,7 @@ const uiSchema={ } ``` -## help +### help Sometimes it's convenient to add text next to a field to guide the end user filling it. This is the purpose of the `ui:help` uiSchema directive: @@ -125,7 +186,7 @@ const uiSchema = { Help texts work for any kind of field at any level, and will always be rendered immediately below the field component widget(s) (after contextualized errors, if any). -## hideError +### hideError The `ui:hideError` uiSchema directive will, if set to `true`, hide the default error display for the given field AND all of its child fields in the hierarchy. @@ -133,7 +194,7 @@ If you need to enable the default error display of a child in the hierarchy afte This is useful when you have a custom field or widget that utilizes either the `rawErrors` or the `errorSchema` to manipulate and/or show the error(s) for the field/widget itself. -## inputType +### inputType To change the input type (for example, `tel` or `email`) you can specify the `inputType` in the `ui:options` uiSchema directive. @@ -146,11 +207,13 @@ const uiSchema = { }; ``` -## label +### label Field labels are rendered by default. Labels may be omitted by setting the `label` option to `false` in the `ui:options` uiSchema directive. ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = {type: "string"}; const uiSchema = { "ui:options": { @@ -159,79 +222,73 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` -## order +### order This property allows you to reorder the properties that are shown for a particular object. See [Objects](../usage/objects.md) for more information. -## placeholder +### placeholder You can add placeholder text to an input by using the `ui:placeholder` uiSchema directive: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = {type: "string", format: "uri"}; const uiSchema = { "ui:placeholder": "http://" }; render(( - + ), document.getElementById("app")); ``` Fields using `enum` can also use `ui:placeholder`. The value will be used as the text for the empty option in the select widget. ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = {type: "string", enum: ["First", "Second"]}; const uiSchema = { "ui:placeholder": "Choose an option" }; render(( - + ), document.getElementById("app")); ``` -## readonly +### readonly The `ui:readonly` uiSchema directive will mark all child widgets from a given field as read-only. This is equivalent to setting the `readOnly` property in the schema. > Note: If you're wondering about the difference between a `disabled` field and a `readonly` one: Marking a field as read-only will render it greyed out, but its text value will be selectable. Disabling it will prevent its value to be selected at all. -## rootFieldId - -By default, this library will generate ids unique to the form for all rendered widgets. If you plan on using multiple instances of the `Form` component in a same page, it's wise to declare a root prefix for these, using the `ui:rootFieldId` uiSchema directive: - -```js -const uiSchema = { - "ui:rootFieldId": "myform" -}; -``` - -This will make all widgets have an id prefixed with `myform`. - -## rows +### rows You can set the initial height of a textarea widget by specifying `rows` option. -```js +```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = {type: "string"}; const uiSchema = { - "ui:widget": "textarea", "ui:options": { + widget: "textarea", rows: 15 } }; render(( - + ), document.getElementById("app")); ``` -## title +### title Sometimes it's convenient to change a field's title. This is the purpose of the `ui:title` uiSchema directive: @@ -243,30 +300,29 @@ const uiSchema = { }; ``` -## submitButtonOptions +### submitButtonOptions Sometimes it's convenient to change the behavior of the submit button for the form. This is the purpose of the `ui:submitButtonOptions` uiSchema directive: You can pass any other prop to the submit button if you want, by default, this library will set the following options / props mentioned below for all submit buttons: -### `norender` option +#### `norender` option You can set this property to `true` to remove the submit button completely from the form. Nice option, if the form is just for viewing purposes. -### `submitText` option +#### `submitText` option You can use this option to change the text of the submit button. Set to "Submit" by default. -### `props` section +#### `props` section You can pass any other prop to the submit button if you want, via this section. - -#### `disabled` prop +##### `disabled` prop You can use this option to disable the submit button. -#### `className` prop +##### `className` prop You can use this option to specify a class name for the submit button. @@ -282,6 +338,12 @@ const uiSchema = { } }; ``` + +## `duplicateKeySuffixSeparator` option + +When using `additionalProperties`, key collision is prevented by appending a unique integer suffix to the duplicate key. For example, when you add a key named `myKey` to a form where `myKey` is already defined, then your new key will become `myKey-1`. +You can use `ui:duplicateKeySuffixSeparator` to override the default separator, `"-"` with a string of your choice. + ## Theme Options [Semantic UI](themes/semantic-ui/uiSchema.md) [Chakra UI](themes/chakra-ui/uiSchema.md) diff --git a/docs/api-reference/utility-functions.md b/docs/api-reference/utility-functions.md new file mode 100644 index 0000000000..371b82de4c --- /dev/null +++ b/docs/api-reference/utility-functions.md @@ -0,0 +1,545 @@ +# RJSF utility functions, constants and types + +In version 5, the utility functions from `@rjsf/core/utils` were refactored into their own library called `@rjsf/utils`. +These utility functions are separated into two distinct groups. +The first, larger, group are the [functions](#non-validator-utility-functions) that do NOT require a `ValidatorType` interface be provided as one of their parameters. +The second, smaller, group are the [functions](#validator-based-utility-functions) that DO require a `ValidatorType` interface be provided as a parameter. +There is also a helper [function](#schema-utils-creation-function) used to create a `SchemaUtilsType` implementation from a `ValidatorType` implementation and `rootSchema` object. + +## Constants +The `@rjsf/utils` package exports a set of constants that represent all the keys into various elements of a RJSFSchema or UiSchema that are used by the various utility functions. +In addition to those keys, there is the special `ADDITIONAL_PROPERTY_FLAG` flag that is added to a schema under certain conditions by the `retrieveSchema()` utility. + +These constants can be found on Github [here](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/utils/src/constants.ts). + +## Types +Additionally, the Typescript types used by the utility functions represent nearly all the types used by RJSF. +Those types are exported for use by `@rjsf/core` and all the themes, as well as any customizations you may build. + +These types can be found on Github [here](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/utils/src/types.ts). + +## Non-Validator utility functions + +### allowAdditionalItems() +Checks the schema to see if it is allowing additional items, by verifying that `schema.additionalItems` is an object. +The user is warned in the console if `schema.additionalItems` has the value `true`. + +#### Parameters +- schema: RJSFSchema - The schema object to check + +#### Returns +- boolean: True if additional items is allowed, otherwise false + +### asNumber() +Attempts to convert the string into a number. If an empty string is provided, then `undefined` is returned. +If a `null` is provided, it is returned. +If the string ends in a `.` then the string is returned because the user may be in the middle of typing a float number. +If a number ends in a pattern like `.0`, `.20`, `.030`, string is returned because the user may be typing number that will end in a non-zero digit. +Otherwise, the string is wrapped by `Number()` and if that result is not `NaN`, that number will be returned, otherwise the string `value` will be. + +#### Parameters +- value: string | null - The string or null value to convert to a number + +#### Returns +- undefined | null | string | number: The `value` converted to a number when appropriate, otherwise the `value` + +### canExpand() + +Checks whether the field described by `schema`, having the `uiSchema` and `formData` supports expanding. +The UI for the field can expand if it has additional properties, is not forced as non-expandable by the `uiSchema` and the `formData` object doesn't already have `schema.maxProperties` elements. + +#### Parameters +- schema: RJSFSchema - The schema for the field that is being checked +- [uiSchema={}]: UiSchema - The uiSchema for the field +- [formData]: T - The formData for the field + +#### Returns +- boolean: True if the schema element has additionalProperties, is expandable, and not at the maxProperties limit + +### dataURItoBlob() +Given the `FileReader.readAsDataURL()` based `dataURI` extracts that data into an actual Blob along with the name +of that Blob if provided in the URL. If no name is provided, then the name falls back to `unknown`. + +#### Parameters +- dataURI: string - The `DataUrl` potentially containing name and raw data to be converted to a Blob + +#### Returns +- { blob: Blob, name: string }: An object containing a Blob and its name, extracted from the URI + +### deepEquals() +Implements a deep equals using the `lodash.isEqualWith` function, that provides a customized comparator that assumes all functions are equivalent. + +#### Parameters +- a: any - The first element to compare +- b: any - The second element to compare + +#### Returns +- boolean: True if the `a` and `b` are deeply equal, false otherwise + +### findSchemaDefinition() +Given the name of a `$ref` from within a schema, using the `rootSchema`, look up and return the sub-schema using the path provided by that reference. +If `#` is not the first character of the reference, or the path does not exist in the schema, then throw an Error. +Otherwise return the sub-schema. Also deals with nested `$ref`s in the sub-schema. + +#### Parameters +- $ref: string - The ref string for which the schema definition is desired +- [rootSchema={}]: RJSFSchema - The root schema in which to search for the definition + +#### Returns +- RJSFSchema: The sub-schema within the `rootSchema` which matches the `$ref` if it exists + +#### Throws +- Error indicating that no schema for that reference exists + +### getInputProps() +Using the `schema`, `defaultType` and `options`, extract out the props for the element that make sense. + +#### Parameters +- schema: RJSFSchema - The schema for the field provided by the widget +- [defaultType]: string - The default type, if any, for the field provided by the widget +- [options={}]: UIOptionsType - The UI Options for the field provided by the widget +- [autoDefaultStepAny=true]: boolean - Determines whether to auto-default step=any when the type is number and no step +#### Returns +- InputPropsType: The extracted `InputPropsType` object + +### getSchemaType() +Gets the type of a given `schema`. +If the type is not explicitly defined, then an attempt is made to infer it from other elements of the schema as follows: +- schema.const: Returns the `guessType()` of that value +- schema.enum: Returns `string` +- schema.properties: Returns `object` +- schema.additionalProperties: Returns `object` +- type is an array with a length of 2 and one type is 'null': Returns the other type + +#### Parameters +- schema: RJSFSchema - The schema for which to get the type + +#### Returns +- string | string[] | undefined: The type of the schema + +### getSubmitButtonOptions() +Extracts any `ui:submitButtonOptions` from the `uiSchema` and merges them onto the `DEFAULT_OPTIONS` + +#### Parameters +- [uiSchema={}]: UiSchema - the UI Schema from which to extract submit button props + +#### Returns +- UISchemaSubmitButtonOptions: The merging of the `DEFAULT_OPTIONS` with any custom ones + +### getUiOptions() +Get all passed options from ui:options, and ui:, returning them in an object with the `ui:` stripped off. + +#### Parameters +- [uiSchema={}]: UiSchema - The UI Schema from which to get any `ui:xxx` options + +#### Returns +- UIOptionsType: An object containing all of the `ui:xxx` options with the stripped off + +### getTemplate, T = any, F = any>() +Returns the template with the given `name` from either the `uiSchema` if it is defined or from the `registry` +otherwise. NOTE, since `ButtonTemplates` are not overridden in `uiSchema` only those in the `registry` are returned. + +#### Parameters +- name: Name - The name of the template to fetch, restricted to the keys of `TemplatesType` +- registry: Registry - The `Registry` from which to read the template +- [uiOptions={}]: UIOptionsType - The `UIOptionsType` from which to read an alternate template + +#### Returns +- TemplatesType[Name] - The template from either the `uiSchema` or `registry` for the `name` + +### getWidget() +Given a schema representing a field to render and either the name or actual `Widget` implementation, returns the +React component that is used to render the widget. If the `widget` is already a React component, then it is wrapped +with a `MergedWidget`. Otherwise an attempt is made to look up the widget inside of the `registeredWidgets` map based +on the schema type and `widget` name. If no widget component can be found an `Error` is thrown. + +#### Parameters +- schema: RJSFSchema - The schema for the field +- widget: Widget | string - Either the name of the widget OR a `Widget` implementation to use +- [registeredWidgets={}]: RegistryWidgetsType - A registry of widget name to `Widget` implementation + +#### Returns +- Widget: The `Widget` component to use + +#### Throws +- An error if there is no `Widget` component that can be returned + +### guessType() +Given a specific `value` attempts to guess the type of a schema element. In the case where we have to implicitly +create a schema, it is useful to know what type to use based on the data we are defining. + +#### Parameters +- value: any - The value from which to guess the type + +#### Returns +- string: The best guess for the object type + +### hasWidget() +Detects whether the `widget` exists for the `schema` with the associated `registryWidgets` and returns true if it does, or false if it doesn't. + +#### Parameters +- schema: RJSFSchema - The schema for the field +- widget: Widget | string - Either the name of the widget OR a `Widget` implementation to use +- [registeredWidgets={}]: RegistryWidgetsType - A registry of widget name to `Widget` implementation + +#### Returns +- boolean: True if the widget exists, false otherwise + +### isConstant() +This function checks if the given `schema` matches a single constant value. +This happens when either the schema has an `enum` array with a single value or there is a `const` defined. + +#### Parameters +- schema: RJSFSchema - The schema for a field + +#### Returns +- boolean: True if the `schema` has a single constant value, false otherwise + +### isCustomWidget() +Checks to see if the `uiSchema` contains the `widget` field and that the widget is not `hidden` + +#### Parameters +- uiSchema: UiSchema - The UI Schema from which to detect if it is customized + +#### Returns +- boolean: True if the `uiSchema` describes a custom widget, false otherwise + +### isFixedItems() +Detects whether the given `schema` contains fixed items. +This is the case when `schema.items` is a non-empty array that only contains objects. + +#### Parameters +- schema: RJSFSchema - The schema in which to check for fixed items + +#### Returns +- boolean: True if there are fixed items in the schema, false otherwise + +### isObject() +Determines whether a `thing` is an object for the purposes of RSJF. +In this case, `thing` is an object if it has the type `object` but is NOT null, an array or a File. + +#### Parameters +- thing: any - The thing to check to see whether it is an object + +#### Returns +- boolean: True if it is a non-null, non-array, non-File object + +### localToUTC() +Converts a local Date string into a UTC date string + +#### Parameters +- dateString: string - The string representation of a date as accepted by the `Date()` constructor + +#### Returns +- string | undefined: A UTC date string if `dateString` is truthy, otherwise undefined + +### mergeDefaultsWithFormData() +Merges the `defaults` object of type `T` into the `formData` of type `T` + +When merging defaults and form data, we want to merge in this specific way: +- objects are deeply merged +- arrays are merged in such a way that: + - when the array is set in form data, only array entries set in form data are deeply merged; additional entries from the defaults are ignored + - when the array is not set in form data, the default is copied over +- scalars are overwritten/set by form data + +#### Parameters +- defaults: T - The defaults to merge +- formData: T - The form data into which the defaults will be merged + +#### Returns +- T: The resulting merged form data with defaults + +### mergeObjects() +Recursively merge deeply nested objects. + +#### Parameters +- obj1: GenericObjectType - The first object to merge +- obj2: GenericObjectType - The second object to merge +- [concatArrays=false]: boolean - Optional flag that, when true, will cause arrays to be concatenated + +#### Returns +@returns - A new object that is the merge of the two given objects + +### mergeSchemas() +Recursively merge deeply nested schemas. +The difference between mergeSchemas and mergeObjects is that mergeSchemas only concats arrays for values under the 'required' keyword, and when it does, it doesn't include duplicate values. + +#### Parameters +- obj1: GenericObjectType - The first object to merge +- obj2: GenericObjectType - The second object to merge + +#### Returns +- GenericObjectType: The merged schema object + +### optionsList() +Gets the list of options from the schema. If the schema has an enum list, then those enum values are returned. +The labels for the options will be extracted from the non-standard `enumNames` if it exists otherwise will be the same as the `value`. +If the schema has a `oneOf` or `anyOf`, then the value is the list of `const` values from the schema and the label is either the `schema.title` or the value. + +NOTE: `enumNames` is deprecated and may be removed in a future major version of RJSF. + +#### Parameters +- schema: RJSFSchema - The schema from which to extract the options list + +#### Returns +- { schema?: RJSFSchema, label: string, value: any }: The list of options from the schema + +### orderProperties() +Given a list of `properties` and an `order` list, returns a list that contains the `properties` ordered correctly. +If `order` is not an array, then the untouched `properties` list is returned. +Otherwise `properties` is ordered per the `order` list. +If `order` contains a '*' then any `properties` that are not mentioned explicity in `order` will be places in the location of the `*`. + +#### Parameters +- properties: string[] - The list of property keys to be ordered +- order: string[] - An array of property keys to be ordered first, with an optional '*' property + +#### Returns +- string[]: A list with the `properties` ordered + +#### Throws +- Error when the properties cannot be ordered correctly + +### pad() +Returns a string representation of the `num` that is padded with leading "0"s if necessary + +#### Parameters +- num: number - The number to pad +- width: number - The width of the string at which no lead padding is necessary + +#### Returns +- string: The number converted to a string with leading zero padding if the number of digits is less than `width` + +### parseDateString() +Parses the `dateString` into a `DateObject`, including the time information when `includeTime` is true + +#### Parameters +- dateString: string - The date string to parse into a DateObject +- [includeTime=true]: boolean - Optional flag, if false, will not include the time data into the object + +#### Returns +- DateObject: The date string converted to a `DateObject` + +#### Throws +- Error when the date cannot be parsed from the string + +### processSelectValue() +Returns the real value for a select widget due to a silly limitation in the DOM which causes option change event values to always be retrieved as strings. +Uses the `schema` to help determine the value's true type. +If the value is an empty string, then the `emptyValue` from the `options` is returned, falling back to undefined. + +#### Parameters +- schema: RJSFSchema - The schema to used to determine the value's true type +- [value]: any - The value to convert +- [options]: UIOptionsType - The UIOptionsType from which to potentially extract the `emptyValue` + +#### Returns +- string | boolean | number | string[] | boolean[] | number[] | undefined: The `value` converted to the proper type + +### rangeSpec() +Extracts the range spec information `{ step?: number, min?: number, max?: number }` that can be spread onto an HTML input from the range analog in the schema `{ multipleOf?: number, minimum?: number, maximum?: number }`. + +#### Parameters +- schema: RJSFSchema - The schema from which to extract the range spec + +#### Returns +- RangeSpecType: A range specification from the schema + +### schemaRequiresTrueValue() +Check to see if a `schema` specifies that a value must be true. This happens when: +- `schema.const` is truthy +- `schema.enum` == `[true]` +- `schema.anyOf` or `schema.oneOf` has a single value which recursively returns true +- `schema.allOf` has at least one value which recursively returns true + +#### Parameters +- schema: RJSFSchema - The schema to check + +#### Returns +- boolean: True if the schema specifies a value that must be true, false otherwise + +### shouldRender() +Determines whether the given `component` should be rerendered by comparing its current set of props and state against the next set. +If either of those two sets are not the same, then the component should be rerendered. + +#### Parameters +- component: React.Component - A React component being checked +- nextProps: any - The next set of props against which to check +- nextState: any - The next set of state against which to check + +#### Returns +- True if boolean: the component should be re-rendered, false otherwise + +### toConstant() +Returns the constant value from the schema when it is either a single value enum or has a const key. +Otherwise throws an error. + +#### Parameters +- schema: RJSFSchema - The schema from which to obtain the constant value + +#### Returns +- string | number | boolean: The constant value for the schema + +#### Throws +- Error when the schema does not have a constant value + +### toDateString() +Returns a UTC date string for the given `dateObject`. +If `time` is false, then the time portion of the string is removed. + +#### Parameters +- dateObject: DateObject - The `DateObject` to convert to a date string +- [time=true]: boolean - Optional flag used to remove the time portion of the date string if false + +#### Returns +- string: The UTC date string + +### utcToLocal() +Converts a UTC date string into a local Date format + +#### Parameters +- jsonDate: string - A UTC date string + +#### Returns +- string: An empty string when `jsonDate` is falsey, otherwise a date string in local format + +## Validator-based utility functions + +### getDefaultFormState() +Returns the superset of `formData` that includes the given set updated to include any missing fields that have computed to have defaults provided in the `schema`. + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- theSchema: RJSFSchema - The schema for which the default state is desired +- [formData]: T - The current formData, if any, onto which to provide any missing defaults +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s +- [includeUndefinedValues=false]: boolean - Optional flag, if true, cause undefined values to be added as defaults + +#### Returns +- T: The resulting `formData` with all the defaults provided + +### getDisplayLabel() +Determines whether the combination of `schema` and `uiSchema` properties indicates that the label for the `schema` should be displayed in a UI. + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: RJSFSchema - The schema for which the display label flag is desired +- [uiSchema={}]: UiSchema - The UI schema from which to derive potentially displayable information +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s + +#### Returns +- boolean: True if the label should be displayed or false if it should not + +### getMatchingOption() +Given the `formData` and list of `options`, attempts to find the index of the option that best matches the data. + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- formData: T | undefined - The current formData, if any, used to figure out a match +- options: RJSFSchema[] - The list of options to find a matching options from +- rootSchema: RJSFSchema - The root schema, used to primarily to look up `$ref`s + +#### Returns +- number: The index of the matched option or 0 if none is available + +### isFilesArray() +Checks to see if the `schema` and `uiSchema` combination represents an array of files + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: RJSFSchema - The schema for which check for array of files flag is desired +- [uiSchema={}]: UiSchema - The UI schema from which to check the widget +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s + +#### Returns +- boolean: True if schema/uiSchema contains an array of files, otherwise false + +### isMultiSelect() +Checks to see if the `schema` combination represents a multi-select + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: RJSFSchema - The schema for which check for a multi-select flag is desired +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s + +#### Returns +- boolean: True if schema contains a multi-select, otherwise false + +### isSelect() +Checks to see if the `schema` combination represents a select + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- theSchema: RJSFSchema - The schema for which check for a select flag is desired +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s + +#### Returns +- boolean: True if schema contains a select, otherwise false + +### mergeValidationData() +Merges the errors in `additionalErrorSchema` into the existing `validationData` by combining the hierarchies in the two `ErrorSchema`s and then appending the error list from the `additionalErrorSchema` obtained by calling `validator.toErrorList()` onto the `errors` in the `validationData`. +If no `additionalErrorSchema` is passed, then `validationData` is returned. + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used to convert an ErrorSchema to a list of errors +- validationData: ValidationData - The current `ValidationData` into which to merge the additional errors +- [additionalErrorSchema]: ErrorSchema - The additional set of errors in an `ErrorSchema` + +#### Returns +- ValidationData: The `validationData` with the additional errors from `additionalErrorSchema` merged into it, if provided. + +### retrieveSchema() +Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies +resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the +potentially recursive resolution. + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs +- schema: RJSFSchema - The schema for which retrieving a schema is desired +- [rootSchema={}]: RJSFSchema - The root schema that will be forwarded to all the APIs +- [rawFormData]: T - The current formData, if any, to assist retrieving a schema + +#### Returns +- RJSFSchema: The schema having its conditions, additional properties, references and dependencies resolved + +### toIdSchema() +Generates an `IdSchema` object for the `schema`, recursively + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: RJSFSchema - The schema for which the `IdSchema` is desired +- [id]: string | null - The base id for the schema +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s +- [formData]: T - The current formData, if any, to assist retrieving a schema +- [idPrefix='root']: string - The prefix to use for the id +- [idSeparator='_']: string - The separator to use for the path segments in the id + +#### Returns +- IDSchema: The `IdSchema` object for the `schema` + +### toPathSchema() +Generates an `PathSchema` object for the `schema`, recursively + +#### Parameters +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: RJSFSchema - The schema for which the `PathSchema` is desired +- [name='']: string - The base name for the schema +- [rootSchema]: RJSFSchema - The root schema, used to primarily to look up `$ref`s +- [formData]: T - The current formData, if any, to assist retrieving a schema + +#### Returns +- PathSchema - The `PathSchema` object for the `schema` + +## Schema utils creation function + +### createSchemaUtils() +Creates a `SchemaUtilsType` interface that is based around the given `validator` and `rootSchema` parameters. +The resulting interface implementation will forward the `validator` and `rootSchema` to all the wrapped APIs. + +#### Parameters +- validator: ValidatorType - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs +- rootSchema: RJSFSchema - The root schema that will be forwarded to all the APIs + +#### Returns +- SchemaUtilsType - An implementation of a `SchemaUtilsType` interface diff --git a/docs/index.md b/docs/index.md index 0229110f35..47982c9e3f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -16,15 +16,22 @@ react-jsonschema-form also comes with tools such as `uiSchema` and other form pr ## Installation -First install the dependency from npm: +First install the dependencies from npm: ```bash -$ npm install @rjsf/core --save +$ npm install @rjsf/core @rjsf/utils --save ``` +As of version 5, you will also need to select and install a validator implementation (such as `@rjsf/validator-ajv6`): + +```bash +$ npm install @rjsf/validator-ajv6 --save +```` + Then import the dependency as follows: ```js +import validator from "@rjsf/validator-ajv6"; import Form from "@rjsf/core"; ``` @@ -51,6 +58,8 @@ const {default: Form} = JSONSchemaForm; ## Usage ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { title: "Todo", type: "object", @@ -65,6 +74,7 @@ const log = (type) => console.log.bind(console, type); render(( diff --git a/docs/quickstart.md b/docs/quickstart.md index 8e768da844..fec068831c 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -1,25 +1,30 @@ # Quickstart Let's walk through setup of a form after installing the dependency properly. +NOTE: As of version 5, the `Form` now requires you to provide a `validator` implementation. We recommend the one from `@rjsf/validator-ajv6`. ## Form schema First, specify a schema using the [JSON Schema specification](https://json-schema.org/). The below schema renders a single string field: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { title: "Test form", type: "string" }; render(( - + ), document.getElementById("app")); ``` You can also render an object with multiple fields with the below schema: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { title: "Test form", type: "object", @@ -34,7 +39,7 @@ const schema = { }; render(( - + ), document.getElementById("app")); ``` @@ -47,6 +52,8 @@ attribute of the uiSchema to add a custom CSS class name to the form: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { title: "Test form", type: "string" @@ -57,7 +64,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -66,6 +73,8 @@ uiSchema should be `{key: value}`, where `key` is the property key and `value` i object with the uiSchema configuration for that particular property. For example: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { title: "Test form", type: "object", @@ -89,7 +98,7 @@ const uiSchema = { } render(( - + ), document.getElementById("app")); ``` @@ -98,6 +107,8 @@ render(( Often you'll want to prefill a form with existing data; this is done by passing a `formData` prop object matching the schema: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "object", properties: { @@ -116,8 +127,7 @@ const formData = { }; render(( - + ), document.getElementById("app")); ``` @@ -135,12 +145,15 @@ By default, `` is an [uncontrolled component](https://reactjs.org/docs/u `onChange` and `formData` props as in the below example: ```jsx +import validator from "@rjsf/validator-ajv6"; + const App = () => { const [formData, setFormData] = React.useState(null); return ( setFormData(e.formData)} + validator={validator} />); }; diff --git a/docs/usage/arrays.md b/docs/usage/arrays.md index 964b1fb892..761f03abaf 100644 --- a/docs/usage/arrays.md +++ b/docs/usage/arrays.md @@ -7,6 +7,8 @@ Arrays are defined with a type equal to `array`, and array items' schemas are sp Arrays of a single field type can be specified as follows: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -15,7 +17,7 @@ const schema = { }; render(( - + ), document.getElementById("app")); ``` @@ -24,6 +26,8 @@ render(( Arrays of objects can be specified as follows: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -37,7 +41,7 @@ const schema = { }; render(( - + ), document.getElementById("app")); ``` @@ -46,6 +50,8 @@ render(( To specify a uiSchema that applies to array items, specify the uiSchema value within the `items` property: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -60,7 +66,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -69,6 +75,8 @@ render(( The `additionalItems` keyword allows the user to add additional items of a given schema. For example: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -80,17 +88,19 @@ const schema = { }; render(( - + ), document.getElementById("app")); ``` -## Array item options +## Array item uiSchema options ### `orderable` option Array items are orderable by default, and react-jsonschema-form renders move up/down buttons alongside them. The uiSchema `orderable` options allows you to disable ordering: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -105,7 +115,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -114,6 +124,8 @@ render(( If either `items` or `additionalItems` contains a schema object, an add button for new items is shown by default. You can turn this off with the `addable` option in `uiSchema`: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -128,7 +140,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -137,6 +149,8 @@ render(( A remove button is shown by default for an item if `items` contains a schema object, or the item is an `additionalItems` instance. You can turn this off with the `removable` option in `uiSchema`: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", items: { @@ -151,7 +165,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -163,6 +177,8 @@ The default behavior for array fields is a list of text inputs with add/remove b Example: ```jsx +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", title: "A multiple-choice list", @@ -174,13 +190,15 @@ const schema = { }; render(( - + ), document.getElementById("app")); ``` By default, this will render a multiple select box. If you prefer a list of checkboxes, just set the uiSchema `ui:widget` directive to `checkboxes` for that field: ```js +import validator from "@rjsf/validator-ajv6"; + const schema = { type: "array", title: "A multiple-choice list", @@ -196,7 +214,7 @@ const uiSchema = { }; render(( - + ), document.getElementById("app")); ``` @@ -207,6 +225,8 @@ In addition to [ArrayFieldTemplate](../advanced-customization/custom-templates.m Example: ```jsx +import validator from "@rjsf/validator-ajv6"; + const CustomSelectComponent = props => { return ( - ); -}; - -export default ColorWidget; diff --git a/packages/antd/src/widgets/DateTimeWidget/index.js b/packages/antd/src/widgets/DateTimeWidget/index.js index 78f32a2845..6a3db69c39 100644 --- a/packages/antd/src/widgets/DateTimeWidget/index.js +++ b/packages/antd/src/widgets/DateTimeWidget/index.js @@ -1,10 +1,10 @@ -import React from 'react'; -import dayjs from 'dayjs'; +import React from "react"; +import dayjs from "dayjs"; -import DatePicker from '../../components/DatePicker'; +import DatePicker from "../../components/DatePicker"; const DATE_PICKER_STYLE = { - width: '100%', + width: "100%", }; const DateTimeWidget = ({ diff --git a/packages/antd/src/widgets/DateWidget/index.js b/packages/antd/src/widgets/DateWidget/index.js index 7a87a2a3a3..4252d698be 100644 --- a/packages/antd/src/widgets/DateWidget/index.js +++ b/packages/antd/src/widgets/DateWidget/index.js @@ -1,10 +1,10 @@ -import React from 'react'; -import dayjs from 'dayjs'; +import React from "react"; +import dayjs from "dayjs"; -import DatePicker from '../../components/DatePicker'; +import DatePicker from "../../components/DatePicker"; const DATE_PICKER_STYLE = { - width: '100%', + width: "100%", }; const DateWidget = ({ @@ -26,7 +26,7 @@ const DateWidget = ({ const { readonlyAsDisabled = true } = formContext; const handleChange = (nextValue) => - onChange(nextValue && nextValue.format('YYYY-MM-DD')); + onChange(nextValue && nextValue.format("YYYY-MM-DD")); const handleBlur = () => onBlur(id, value); diff --git a/packages/antd/src/widgets/EmailWidget/index.js b/packages/antd/src/widgets/EmailWidget/index.js deleted file mode 100644 index 0f277b32d3..0000000000 --- a/packages/antd/src/widgets/EmailWidget/index.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; - -import Input from 'antd/lib/input'; - -const INPUT_STYLE = { - width: '100%', -}; - -const EmailWidget = ({ - // autofocus, - disabled, - formContext, - id, - // label, - onBlur, - onChange, - onFocus, - options, - placeholder, - readonly, - // required, - // schema, - value, -}) => { - const { readonlyAsDisabled = true } = formContext; - - const handleChange = ({ target }) => - onChange(target.value === '' ? options.emptyValue : target.value); - - const handleBlur = ({ target }) => onBlur(id, target.value); - - const handleFocus = ({ target }) => onFocus(id, target.value); - - return ( - - ); -}; - -export default EmailWidget; diff --git a/packages/antd/src/widgets/PasswordWidget/index.js b/packages/antd/src/widgets/PasswordWidget/index.js index 6171832a1c..a207b5d2e6 100644 --- a/packages/antd/src/widgets/PasswordWidget/index.js +++ b/packages/antd/src/widgets/PasswordWidget/index.js @@ -1,6 +1,6 @@ -import React from 'react'; +import React from "react"; -import Input from 'antd/lib/input'; +import Input from "antd/lib/input"; const PasswordWidget = ({ // autofocus, @@ -20,10 +20,10 @@ const PasswordWidget = ({ }) => { const { readonlyAsDisabled = true } = formContext; - const emptyValue = options.emptyValue || ''; + const emptyValue = options.emptyValue || ""; const handleChange = ({ target }) => - onChange(target.value === '' ? emptyValue : target.value); + onChange(target.value === "" ? emptyValue : target.value); const handleBlur = ({ target }) => onBlur(id, target.value); @@ -38,7 +38,7 @@ const PasswordWidget = ({ onChange={!readonly ? handleChange : undefined} onFocus={!readonly ? handleFocus : undefined} placeholder={placeholder} - value={value || ''} + value={value || ""} /> ); }; diff --git a/packages/antd/src/widgets/RadioWidget/index.js b/packages/antd/src/widgets/RadioWidget/index.js index b2b3e135db..44f757fe57 100644 --- a/packages/antd/src/widgets/RadioWidget/index.js +++ b/packages/antd/src/widgets/RadioWidget/index.js @@ -1,7 +1,7 @@ /* eslint-disable no-else-return */ -import React from 'react'; +import React from "react"; -import Radio from 'antd/lib/radio'; +import Radio from "antd/lib/radio"; const RadioWidget = ({ autofocus, @@ -24,7 +24,7 @@ const RadioWidget = ({ const { enumOptions, enumDisabled } = options; const handleChange = ({ target: { value: nextValue } }) => - onChange(schema.type === 'boolean' ? nextValue !== 'false' : nextValue); + onChange(schema.type === "boolean" ? nextValue !== "false" : nextValue); const handleBlur = ({ target }) => onBlur(id, target.value); diff --git a/packages/antd/src/widgets/RangeWidget/index.js b/packages/antd/src/widgets/RangeWidget/index.js index 4b58f7b28c..a6c67e073f 100644 --- a/packages/antd/src/widgets/RangeWidget/index.js +++ b/packages/antd/src/widgets/RangeWidget/index.js @@ -1,10 +1,8 @@ /* eslint-disable no-else-return */ -import React from 'react'; +import React from "react"; -import { utils } from '@rjsf/core'; -import Slider from 'antd/lib/slider'; - -const { rangeSpec } = utils; +import { rangeSpec } from "@rjsf/utils"; +import Slider from "antd/lib/slider"; const RangeWidget = ({ autofocus, @@ -26,10 +24,10 @@ const RangeWidget = ({ const { min, max, step } = rangeSpec(schema); - const emptyValue = options.emptyValue || ''; + const emptyValue = options.emptyValue || ""; const handleChange = (nextValue) => - onChange(nextValue === '' ? emptyValue : nextValue); + onChange(nextValue === "" ? emptyValue : nextValue); const handleBlur = () => onBlur(id, value); diff --git a/packages/antd/src/widgets/SelectWidget/index.js b/packages/antd/src/widgets/SelectWidget/index.js index 40822add04..9b37190710 100644 --- a/packages/antd/src/widgets/SelectWidget/index.js +++ b/packages/antd/src/widgets/SelectWidget/index.js @@ -1,46 +1,11 @@ /* eslint-disable no-else-return */ -import React from 'react'; +import React from "react"; -import { utils } from '@rjsf/core'; -import Select from 'antd/lib/select'; - -const { asNumber, guessType } = utils; +import { processSelectValue } from "@rjsf/utils"; +import Select from "antd/lib/select"; const SELECT_STYLE = { - width: '100%', -}; - -const nums = new Set(['number', 'integer']); - -/** - * This is a silly limitation in the DOM where option change event values are - * always retrieved as strings. - */ -const processValue = (schema, value) => { - // "enum" is a reserved word, so only "type" and "items" can be destructured - const { type, items } = schema; - - if (value === '') { - return undefined; - } else if (type === 'array' && items && nums.has(items.type)) { - return value.map(asNumber); - } else if (type === 'boolean') { - return value === 'true'; - } else if (type === 'number') { - return asNumber(value); - } - - // If type is undefined, but an enum is present, try and infer the type from - // the enum values - if (schema.enum) { - if (schema.enum.every((x) => guessType(x) === 'number')) { - return asNumber(value); - } else if (schema.enum.every((x) => guessType(x) === 'boolean')) { - return value === 'true'; - } - } - - return value; + width: "100%", }; const SelectWidget = ({ @@ -64,11 +29,14 @@ const SelectWidget = ({ const { enumOptions, enumDisabled } = options; - const handleChange = (nextValue) => onChange(processValue(schema, nextValue)); + const handleChange = (nextValue) => + onChange(processSelectValue(schema, nextValue, options)); - const handleBlur = () => onBlur(id, processValue(schema, value)); + const handleBlur = () => + onBlur(id, processSelectValue(schema, value, options)); - const handleFocus = () => onFocus(id, processValue(schema, value)); + const handleFocus = () => + onFocus(id, processSelectValue(schema, value, options)); const getPopupContainer = (node) => node.parentNode; @@ -81,14 +49,14 @@ const SelectWidget = ({ disabled={disabled || (readonlyAsDisabled && readonly)} getPopupContainer={getPopupContainer} id={id} - mode={typeof multiple !== 'undefined' ? 'multiple' : undefined} + mode={typeof multiple !== "undefined" ? "multiple" : undefined} name={id} onBlur={!readonly ? handleBlur : undefined} onChange={!readonly ? handleChange : undefined} onFocus={!readonly ? handleFocus : undefined} placeholder={placeholder} style={SELECT_STYLE} - value={typeof value !== 'undefined' ? stringify(value) : undefined} + value={typeof value !== "undefined" ? stringify(value) : undefined} > {enumOptions.map(({ value: optionValue, label: optionLabel }) => ( { - const { submitText, norender, props: submitButtonProps }= getSubmitButtonOptions(uiSchema); - if (norender) {return null;} - return (); -}; - diff --git a/packages/antd/src/widgets/SubmitButton/index.js b/packages/antd/src/widgets/SubmitButton/index.js deleted file mode 100644 index f676497ba2..0000000000 --- a/packages/antd/src/widgets/SubmitButton/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './SubmitButton'; -export * from './SubmitButton'; diff --git a/packages/antd/src/widgets/TextareaWidget/index.js b/packages/antd/src/widgets/TextareaWidget/index.js index fa0f3c9bcc..8ca98fb7be 100644 --- a/packages/antd/src/widgets/TextareaWidget/index.js +++ b/packages/antd/src/widgets/TextareaWidget/index.js @@ -1,9 +1,9 @@ -import React from 'react'; +import React from "react"; -import Input from 'antd/lib/input'; +import Input from "antd/lib/input"; const INPUT_STYLE = { - width: '100%', + width: "100%", }; const TextareaWidget = ({ @@ -25,7 +25,7 @@ const TextareaWidget = ({ const { readonlyAsDisabled = true } = formContext; const handleChange = ({ target }) => - onChange(target.value === '' ? options.emptyValue : target.value); + onChange(target.value === "" ? options.emptyValue : target.value); const handleBlur = ({ target }) => onBlur(id, target.value); diff --git a/packages/antd/src/widgets/URLWidget/index.js b/packages/antd/src/widgets/URLWidget/index.js deleted file mode 100644 index 3dab394f1f..0000000000 --- a/packages/antd/src/widgets/URLWidget/index.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; - -import Input from 'antd/lib/input'; - -const INPUT_STYLE = { - width: '100%', -}; - -const URLWidget = ({ - // autofocus, - disabled, - formContext, - id, - // label, - onBlur, - onChange, - onFocus, - options, - placeholder, - readonly, - // required, - // schema, - value, -}) => { - const { readonlyAsDisabled = true } = formContext; - - const handleChange = ({ target }) => - onChange(target.value === '' ? options.emptyValue : target.value); - - const handleBlur = ({ target }) => onBlur(id, target.value); - - const handleFocus = ({ target }) => onFocus(id, target.value); - - return ( - - ); -}; - -export default URLWidget; diff --git a/packages/antd/src/widgets/UpDownWidget/index.js b/packages/antd/src/widgets/UpDownWidget/index.js deleted file mode 100644 index d5ef314d3e..0000000000 --- a/packages/antd/src/widgets/UpDownWidget/index.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; - -import InputNumber from 'antd/lib/input-number'; - -const INPUT_STYLE = { - width: '100%', -}; - -const UpDownWidget = ({ - // autofocus, - disabled, - formContext, - id, - onBlur, - onChange, - onFocus, - // options, - placeholder, - readonly, - // required, - // schema, - value, -}) => { - const { readonlyAsDisabled = true } = formContext; - - const handleChange = (nextValue) => onChange(nextValue); - - const handleBlur = ({ target }) => onBlur(id, target.value); - - const handleFocus = ({ target }) => onFocus(id, target.value); - - return ( - - ); -}; - -export default UpDownWidget; diff --git a/packages/antd/test/Array.test.js b/packages/antd/test/Array.test.js index e85519045e..d55abdbe5f 100644 --- a/packages/antd/test/Array.test.js +++ b/packages/antd/test/Array.test.js @@ -1,8 +1,9 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; +import React from "react"; +import renderer from "react-test-renderer"; +import validator from "@rjsf/validator-ajv6"; -import '../__mocks__/matchMedia.mock'; -import Form from '../src'; +import "../__mocks__/matchMedia.mock"; +import Form from "../src"; const { describe, expect, test } = global; @@ -11,11 +12,11 @@ describe("array fields", () => { const schema = { type: "array", items: { - type: "string" - } + type: "string", + }, }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); @@ -24,15 +25,15 @@ describe("array fields", () => { type: "array", items: [ { - type: "string" + type: "string", }, { - type: "number" - } - ] + type: "number", + }, + ], }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); @@ -41,12 +42,36 @@ describe("array fields", () => { type: "array", items: { type: "string", - enum: ["a", "b", "c"] + enum: ["a", "b", "c"], + }, + uniqueItems: true, + }; + const tree = renderer + .create(, { + createNodeMock: (element) => { + if (element.type === "span" && element.props["aria-hidden"]) { + // the `rc-select` MultipleSelector code expects a ref for this span to exist, so use the feature of + // react-test-renderer to create one + // See: https://reactjs.org/docs/test-renderer.html#ideas + return { scrollWidth: 100 }; + } + return null; + }, + }) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("array icons", () => { + const schema = { + type: "array", + items: { + type: "string", }, - uniqueItems: true }; const tree = renderer - .create() + .create( + + ) .toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/packages/antd/test/Form.test.js b/packages/antd/test/Form.test.js index 1eec6ba51d..3929cc15e7 100644 --- a/packages/antd/test/Form.test.js +++ b/packages/antd/test/Form.test.js @@ -1,8 +1,9 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; +import React from "react"; +import renderer from "react-test-renderer"; +import validator from "@rjsf/validator-ajv6"; -import '../__mocks__/matchMedia.mock'; -import Form from '../src'; +import "../__mocks__/matchMedia.mock"; +import Form from "../src"; const { describe, expect, test } = global; @@ -10,30 +11,30 @@ describe("single fields", () => { describe("string field", () => { test("regular", () => { const schema = { - type: "string" + type: "string", }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); test("format email", () => { const schema = { type: "string", - format: "email" + format: "email", }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); test("format uri", () => { const schema = { type: "string", - format: "uri" + format: "uri", }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); @@ -43,35 +44,215 @@ describe("single fields", () => { format: "data-url", }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); }); + test("string field with placeholder", () => { + const schema = { + type: "string", + }; + const uiSchema = { + "ui:placeholder": "placeholder", + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); test("number field", () => { const schema = { - type: "number" + type: "number", + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("number field 0", () => { + const schema = { + type: "number", }; + const formData = 0; const tree = renderer - .create() + .create( + + ) .toJSON(); expect(tree).toMatchSnapshot(); }); test("null field", () => { const schema = { - type: "null" + type: "null", }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); test("unsupported field", () => { const schema = { - type: undefined + type: undefined, + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("format color", () => { + const schema = { + type: "string", + format: "color", + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("format date", () => { + const schema = { + type: "string", + format: "date", + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("format datetime", () => { + const schema = { + type: "string", + format: "datetime", + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("password field", () => { + const schema = { + type: "string", + }; + const uiSchema = { + "ui:widget": "password", + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("up/down field", () => { + const schema = { + type: "number", + }; + const uiSchema = { + "ui:widget": "updown", + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("textarea field", () => { + const schema = { + type: "string", + }; + const uiSchema = { + "ui:widget": "textarea", + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("select field", () => { + const schema = { + type: "string", + enum: ["foo", "bar"], + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("checkbox field", () => { + const schema = { + type: "boolean", + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("checkbox field", () => { + const schema = { + type: "boolean", + }; + const tree = renderer + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("checkboxes field", () => { + const schema = { + type: "array", + items: { + type: "string", + enum: ["foo", "bar", "fuzz", "qux"], + }, + uniqueItems: true, + }; + const uiSchema = { + "ui:widget": "checkboxes", + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("radio field", () => { + const schema = { + type: "boolean", + }; + const uiSchema = { + "ui:widget": "radio", + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("slider field", () => { + const schema = { + type: "integer", + minimum: 42, + maximum: 100, + }; + const uiSchema = { + "ui:widget": "range", }; const tree = renderer - .create() + .create( + + ) .toJSON(); expect(tree).toMatchSnapshot(); }); @@ -90,7 +271,9 @@ describe("single fields", () => { }, }; const tree = renderer - .create() + .create( + + ) .toJSON(); expect(tree).toMatchSnapshot(); }); @@ -101,11 +284,11 @@ describe("single fields", () => { "my-field": { type: "string", description: "some description", - } - } + }, + }, }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); @@ -116,8 +299,8 @@ describe("single fields", () => { "my-field": { type: "string", description: "some description", - } - } + }, + }, }; const uiSchema = { "my-field": { @@ -125,16 +308,56 @@ describe("single fields", () => { }, }; const tree = renderer - .create() + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("title field", () => { + const schema = { + type: "object", + properties: { + title: { + type: "string", + }, + }, + }; + const uiSchema = { + "ui:title": "Titre 1", + title: { + "ui:title": "Titre 2", + }, + }; + const tree = renderer + .create( + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("hidden label", () => { + const schema = { + type: "string", + }; + const uiSchema = { + "ui:options": { + label: false, + }, + }; + const tree = renderer + .create( + + ) .toJSON(); expect(tree).toMatchSnapshot(); }); test("using custom tagName", () => { const schema = { - type: "string" + type: "string", }; const tree = renderer - .create() + .create() .toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/packages/antd/test/Object.test.js b/packages/antd/test/Object.test.js index 160b96a953..93321dea93 100644 --- a/packages/antd/test/Object.test.js +++ b/packages/antd/test/Object.test.js @@ -1,8 +1,9 @@ -import React from 'react'; +import React from "react"; import renderer from "react-test-renderer"; +import validator from "@rjsf/validator-ajv6"; -import '../__mocks__/matchMedia.mock'; -import Form from '../src'; +import "../__mocks__/matchMedia.mock"; +import Form from "../src"; const { describe, expect, test } = global; @@ -11,12 +12,24 @@ describe("object fields", () => { const schema = { type: "object", properties: { - a: { type: "string" }, - b: { type: "number" } - } + a: { type: "string", title: "A" }, + b: { type: "number", title: "B" }, + }, }; const tree = renderer - .create() + .create() + .toJSON(); + expect(tree).toMatchSnapshot(); + }); + test("additionalProperties", () => { + const schema = { + type: "object", + additionalProperties: true, + }; + const tree = renderer + .create( + + ) .toJSON(); expect(tree).toMatchSnapshot(); }); diff --git a/packages/antd/test/__snapshots__/Array.test.js.snap b/packages/antd/test/__snapshots__/Array.test.js.snap index ba143a1303..a8a895016f 100644 --- a/packages/antd/test/__snapshots__/Array.test.js.snap +++ b/packages/antd/test/__snapshots__/Array.test.js.snap @@ -22,6 +22,7 @@ exports[`array fields array 1`] = ` } } > +
+
+
+
+
+ + + + +`; + +exports[`array fields array icons 1`] = ` +
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+ + + + +
+
+
+ + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
@@ -99,7 +605,7 @@ exports[`array fields array 1`] = `
+
+`; + +exports[`single fields checkbox field 2`] = ` +
+
+ +
+ +
+`; + +exports[`single fields checkboxes field 1`] = ` +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+`; + exports[`single fields field with description 1`] = `
+
- -
-
+ +
- + + > + + + +
-
-
- - some description - + + some description + +
@@ -96,7 +379,7 @@ exports[`single fields field with description 1`] = ` +
+`; + +exports[`single fields hidden field 1`] = ` +
+
+
+
+ +
+
+
+ +
+`; + +exports[`single fields hidden label 1`] = ` +
+
+ +
+ +
+`; + +exports[`single fields null field 1`] = ` +
+
+ + +`; + +exports[`single fields number field 0 1`] = ` +
+
+
+
+ + + + + + +
+
+
+ +
+`; + +exports[`single fields number field 1`] = ` +
+
+
+
+ + + + + + + + + + +
+
+
+ +`; + +exports[`single fields password field 1`] = ` +
+
+ + + + + + + + +
+ +
+`; + +exports[`single fields radio field 1`] = ` +
+
+
+ + +
+
+ +
+`; + +exports[`single fields select field 1`] = ` +
+
+
+
+ + + + + + +
+ + + + + +
+
+ +
+`; + +exports[`single fields slider field 1`] = ` +
+
+
+
+
+
+
+
+
+ + +`; + +exports[`single fields string field format data-url 1`] = ` +
+
+
+

+ +

+
+
+ +
+`; + +exports[`single fields string field format email 1`] = ` +
+
+ +
+
+ +`; + +exports[`single fields title field 1`] = ` +
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ + + + +
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+ +`; + +exports[`single fields up/down field 1`] = ` +
+
+
+
+ + + + + + + + + + +
+
+ +
+
+
+
+ aria-label="delete" + className="anticon anticon-delete" + role="img" + > + + + + +
+
+
+ +
+
+
+ + + + +`; + +exports[`object fields object 1`] = ` +
+
+
+
+
- -
-
+ +
-
- - - - - - - - - - -
-
-
+ +
+
+ + + +
+
+
+
+
+
+
+
+
- + +
+
+
+
+
+
+
+ + + + + + + + + + +
+
+ +
+
+ +
+
+
+
+ + + +
@@ -253,7 +587,7 @@ exports[`object fields object 1`] = `
); diff --git a/packages/bootstrap-4/src/AddButton/index.ts b/packages/bootstrap-4/src/AddButton/index.ts index 752d720d32..e419627056 100644 --- a/packages/bootstrap-4/src/AddButton/index.ts +++ b/packages/bootstrap-4/src/AddButton/index.ts @@ -1,2 +1,2 @@ -export { default } from './AddButton'; -export * from './AddButton'; +export { default } from "./AddButton"; +export * from "./AddButton"; diff --git a/packages/bootstrap-4/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx b/packages/bootstrap-4/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx new file mode 100644 index 0000000000..79f55309a2 --- /dev/null +++ b/packages/bootstrap-4/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx @@ -0,0 +1,73 @@ +import React, { CSSProperties } from "react"; +import Row from "react-bootstrap/Row"; +import Col from "react-bootstrap/Col"; +import { ArrayFieldTemplateItemType } from "@rjsf/utils"; + +const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => { + const { + children, + disabled, + hasToolbar, + hasMoveDown, + hasMoveUp, + hasRemove, + index, + onDropIndexClick, + onReorderClick, + readonly, + registry, + } = props; + const { MoveDownButton, MoveUpButton, RemoveButton } = + registry.templates.ButtonTemplates; + const btnStyle: CSSProperties = { + flex: 1, + paddingLeft: 6, + paddingRight: 6, + fontWeight: "bold", + }; + return ( +
+ + + {children} + + + {hasToolbar && ( +
+ {(hasMoveUp || hasMoveDown) && ( +
+ +
+ )} + {(hasMoveUp || hasMoveDown) && ( +
+ +
+ )} + {hasRemove && ( +
+ +
+ )} +
+ )} + +
+
+ ); +}; + +export default ArrayFieldItemTemplate; diff --git a/packages/bootstrap-4/src/ArrayFieldItemTemplate/index.ts b/packages/bootstrap-4/src/ArrayFieldItemTemplate/index.ts new file mode 100644 index 0000000000..f64828bebf --- /dev/null +++ b/packages/bootstrap-4/src/ArrayFieldItemTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ArrayFieldItemTemplate"; +export * from "./ArrayFieldItemTemplate"; diff --git a/packages/bootstrap-4/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx b/packages/bootstrap-4/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx index 77a4bb705e..df8c216998 100644 --- a/packages/bootstrap-4/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx +++ b/packages/bootstrap-4/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx @@ -1,207 +1,93 @@ import React from "react"; -import { utils } from "@rjsf/core"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; import Container from "react-bootstrap/Container"; -import { ArrayFieldTemplateProps, IdSchema } from "@rjsf/core"; - -import AddButton from "../AddButton/AddButton"; -import IconButton from "../IconButton/IconButton"; - -const { isMultiSelect, getDefaultRegistry } = utils; +import { + ArrayFieldTemplateItemType, + ArrayFieldTemplateProps, + getTemplate, + getUiOptions, +} from "@rjsf/utils"; const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { - const { schema, registry = getDefaultRegistry() } = props; - - if (isMultiSelect(schema, registry.rootSchema)) { - return ; - } else { - return ; - } -}; - -type ArrayFieldTitleProps = { - TitleField: any; - idSchema: IdSchema; - title: string; - required: boolean; -}; - -const ArrayFieldTitle = ({ - TitleField, - idSchema, - title, - required, -}: ArrayFieldTitleProps) => { - if (!title) { - return null; - } - - const id = `${idSchema.$id}__title`; - return ; -}; - -type ArrayFieldDescriptionProps = { - DescriptionField: any; - idSchema: IdSchema; - description: string; -}; - -const ArrayFieldDescription = ({ - DescriptionField, - idSchema, - description, -}: ArrayFieldDescriptionProps) => { - if (!description) { - return null; - } - - const id = `${idSchema.$id}__description`; - return ; -}; - -// Used in the two templates -const DefaultArrayItem = (props: any) => { - const btnStyle = { - flex: 1, - paddingLeft: 6, - paddingRight: 6, - fontWeight: "bold", - }; - return ( -
- - {props.children} - - - {props.hasToolbar && ( -
- {(props.hasMoveUp || props.hasMoveDown) && ( -
- -
- )} - - {(props.hasMoveUp || props.hasMoveDown) && ( -
- -
- )} - - {props.hasRemove && ( -
- -
- )} -
- )} - -
-
+ const { + canAdd, + disabled, + idSchema, + uiSchema, + items, + onAddClick, + readonly, + registry, + required, + schema, + title, + } = props; + const uiOptions = getUiOptions(uiSchema); + const ArrayFieldDescriptionTemplate = + getTemplate<"ArrayFieldDescriptionTemplate">( + "ArrayFieldDescriptionTemplate", + registry, + uiOptions + ); + const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate">( + "ArrayFieldItemTemplate", + registry, + uiOptions ); -}; - -const DefaultFixedArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { - return ( -
- - - {(props.uiSchema["ui:description"] || props.schema.description) && ( -
- {props.uiSchema["ui:description"] || props.schema.description} -
- )} - -
- {props.items && props.items.map(DefaultArrayItem)} -
- - {props.canAdd && ( - - )} -
+ const ArrayFieldTitleTemplate = getTemplate<"ArrayFieldTitleTemplate">( + "ArrayFieldTitleTemplate", + registry, + uiOptions ); -}; - -const DefaultNormalArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { + // Button templates are not overridden in the uiSchema + const { + ButtonTemplates: { AddButton }, + } = registry.templates; return (
- - - {(props.uiSchema["ui:description"] || props.schema.description) && ( - - )} - - - {props.items && props.items.map(p => DefaultArrayItem(p))} - - {props.canAdd && ( - - - - - - - + {(uiOptions.description || schema.description) && ( + )} - - + + {items && + items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType) => ( + + ))} + {canAdd && ( + + + + + + + + + )} + +
); diff --git a/packages/bootstrap-4/src/ArrayFieldTemplate/index.ts b/packages/bootstrap-4/src/ArrayFieldTemplate/index.ts index ab908dec2c..29cbde48eb 100644 --- a/packages/bootstrap-4/src/ArrayFieldTemplate/index.ts +++ b/packages/bootstrap-4/src/ArrayFieldTemplate/index.ts @@ -1,2 +1,2 @@ -export { default } from './ArrayFieldTemplate'; -export * from './ArrayFieldTemplate'; +export { default } from "./ArrayFieldTemplate"; +export * from "./ArrayFieldTemplate"; diff --git a/packages/bootstrap-4/src/TextWidget/TextWidget.tsx b/packages/bootstrap-4/src/BaseInputTemplate/BaseInputTemplate.tsx similarity index 74% rename from packages/bootstrap-4/src/TextWidget/TextWidget.tsx rename to packages/bootstrap-4/src/BaseInputTemplate/BaseInputTemplate.tsx index 447de38bea..c859f6e317 100644 --- a/packages/bootstrap-4/src/TextWidget/TextWidget.tsx +++ b/packages/bootstrap-4/src/BaseInputTemplate/BaseInputTemplate.tsx @@ -1,10 +1,8 @@ import React from "react"; - import Form from "react-bootstrap/Form"; +import { getInputProps, getUiOptions, WidgetProps } from "@rjsf/utils"; -import { WidgetProps } from "@rjsf/core"; - -const TextWidget = ({ +const BaseInputTemplate = ({ id, placeholder, required, @@ -21,8 +19,11 @@ const TextWidget = ({ schema, rawErrors = [], uiSchema, - + children, + extraProps, }: WidgetProps) => { + const inputProps = { ...extraProps, ...getInputProps(schema, type, options) }; + const uiOptions = getUiOptions(uiSchema); const _onChange = ({ target: { value }, }: React.ChangeEvent) => @@ -32,14 +33,16 @@ const TextWidget = ({ const _onFocus = ({ target: { value }, }: React.FocusEvent) => onFocus(id, value); - const inputType = (type || schema.type) === 'string' ? 'text' : `${type || schema.type}` // const classNames = [rawErrors.length > 0 ? "is-invalid" : "", type === 'file' ? 'custom-file-label': ""] return ( - 0 ? "text-danger" : ""}> - {uiSchema["ui:title"] || schema.title || label} - {(label || uiSchema["ui:title"] || schema.title) && required ? "*" : null} + 0 ? "text-danger" : ""} + > + {uiOptions.title || label || schema.title} + {(label || uiOptions.title) && required ? "*" : null} 0 ? "is-invalid" : ""} list={schema.examples ? `examples_${id}` : undefined} - type={inputType} + {...inputProps} value={value || value === 0 ? value : ""} onChange={_onChange} onBlur={_onBlur} onFocus={_onFocus} - /> + {children} {schema.examples ? ( {(schema.examples as string[]) @@ -70,4 +73,4 @@ const TextWidget = ({ ); }; -export default TextWidget; +export default BaseInputTemplate; diff --git a/packages/bootstrap-4/src/BaseInputTemplate/index.ts b/packages/bootstrap-4/src/BaseInputTemplate/index.ts new file mode 100644 index 0000000000..37c3947ed0 --- /dev/null +++ b/packages/bootstrap-4/src/BaseInputTemplate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./BaseInputTemplate"; +export * from "./BaseInputTemplate"; diff --git a/packages/bootstrap-4/src/CheckboxWidget/CheckboxWidget.tsx b/packages/bootstrap-4/src/CheckboxWidget/CheckboxWidget.tsx index df4e9db95b..34172f3ae7 100644 --- a/packages/bootstrap-4/src/CheckboxWidget/CheckboxWidget.tsx +++ b/packages/bootstrap-4/src/CheckboxWidget/CheckboxWidget.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { WidgetProps } from "@rjsf/core"; +import { WidgetProps } from "@rjsf/utils"; import Form from "react-bootstrap/Form"; const CheckboxWidget = (props: WidgetProps) => { @@ -30,20 +30,22 @@ const CheckboxWidget = (props: WidgetProps) => { const desc = label || schema.description; return ( - - - + + + ); }; diff --git a/packages/bootstrap-4/src/CheckboxWidget/index.ts b/packages/bootstrap-4/src/CheckboxWidget/index.ts index b9e3c318ec..9a6515772c 100644 --- a/packages/bootstrap-4/src/CheckboxWidget/index.ts +++ b/packages/bootstrap-4/src/CheckboxWidget/index.ts @@ -1,2 +1,2 @@ -export { default } from './CheckboxWidget'; -export * from './CheckboxWidget'; +export { default } from "./CheckboxWidget"; +export * from "./CheckboxWidget"; diff --git a/packages/bootstrap-4/src/CheckboxesWidget/CheckboxesWidget.tsx b/packages/bootstrap-4/src/CheckboxesWidget/CheckboxesWidget.tsx index fa5894bcd9..fa82df7e9e 100644 --- a/packages/bootstrap-4/src/CheckboxesWidget/CheckboxesWidget.tsx +++ b/packages/bootstrap-4/src/CheckboxesWidget/CheckboxesWidget.tsx @@ -1,6 +1,6 @@ import React from "react"; import Form from "react-bootstrap/Form"; -import { WidgetProps } from "@rjsf/core"; +import { WidgetProps } from "@rjsf/utils"; const selectValue = (value: any, selected: any, all: any) => { const at = all.indexOf(value); @@ -31,17 +31,17 @@ const CheckboxesWidget = ({ }: WidgetProps) => { const { enumOptions, enumDisabled, inline } = options; - const _onChange = (option: any) => ({ - target: { checked }, - }: React.ChangeEvent) => { - const all = (enumOptions as any).map(({ value }: any) => value); + const _onChange = + (option: any) => + ({ target: { checked } }: React.ChangeEvent) => { + const all = (enumOptions as any).map(({ value }: any) => value); - if (checked) { - onChange(selectValue(option.value, value, all)); - } else { - onChange(deselectValue(option.value, value)); - } - }; + if (checked) { + onChange(selectValue(option.value, value, all)); + } else { + onChange(deselectValue(option.value, value)); + } + }; const _onBlur = ({ target: { value } }: React.FocusEvent) => onBlur(id, value); diff --git a/packages/bootstrap-4/src/CheckboxesWidget/index.ts b/packages/bootstrap-4/src/CheckboxesWidget/index.ts index 97152004fa..c5acc6aa16 100644 --- a/packages/bootstrap-4/src/CheckboxesWidget/index.ts +++ b/packages/bootstrap-4/src/CheckboxesWidget/index.ts @@ -1,2 +1,2 @@ -export { default } from './CheckboxesWidget'; -export * from './CheckboxesWidget'; +export { default } from "./CheckboxesWidget"; +export * from "./CheckboxesWidget"; diff --git a/packages/bootstrap-4/src/ColorWidget/ColorWidget.tsx b/packages/bootstrap-4/src/ColorWidget/ColorWidget.tsx deleted file mode 100644 index ead3906679..0000000000 --- a/packages/bootstrap-4/src/ColorWidget/ColorWidget.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; -import { WidgetProps } from '@rjsf/core'; - -const ColorWidget = (props: WidgetProps) => { - const { registry } = props; - const { TextWidget } = registry.widgets; - return ; -}; - -export default ColorWidget; diff --git a/packages/bootstrap-4/src/ColorWidget/index.ts b/packages/bootstrap-4/src/ColorWidget/index.ts deleted file mode 100644 index 95e1f017ed..0000000000 --- a/packages/bootstrap-4/src/ColorWidget/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from "./ColorWidget"; -export * from "./ColorWidget"; diff --git a/packages/bootstrap-4/src/DateTimeWidget/DateTimeWidget.tsx b/packages/bootstrap-4/src/DateTimeWidget/DateTimeWidget.tsx deleted file mode 100644 index 086adf23e8..0000000000 --- a/packages/bootstrap-4/src/DateTimeWidget/DateTimeWidget.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; -import { utils, WidgetProps } from "@rjsf/core"; - -const { localToUTC, utcToLocal } = utils; - -const DateTimeWidget = (props: WidgetProps) => { - const { registry } = props; - const { TextWidget } = registry.widgets; - const value = utcToLocal(props.value); - const onChange = (value: any) => { - props.onChange(localToUTC(value)); - }; - - return ( - - ); -}; - -export default DateTimeWidget; diff --git a/packages/bootstrap-4/src/DateWidget/DateWidget.tsx b/packages/bootstrap-4/src/DateWidget/DateWidget.tsx deleted file mode 100644 index 62fc811875..0000000000 --- a/packages/bootstrap-4/src/DateWidget/DateWidget.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from "react"; -import { WidgetProps } from '@rjsf/core'; - -const DateWidget = (props: WidgetProps) => { - const { registry } = props; - const { TextWidget } = registry.widgets; - return ( - - ); -}; - -export default DateWidget; diff --git a/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx b/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx index 1dc6a050ec..1e6e0eccba 100644 --- a/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx +++ b/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx @@ -1,13 +1,15 @@ import React from "react"; -import { FieldProps } from "@rjsf/core"; +import { DescriptionFieldProps } from "@rjsf/utils"; -export interface DescriptionFieldProps extends Partial { - description?: string; -} - -const DescriptionField = ({ description }: Partial) => { +const DescriptionField = ({ id, description }: DescriptionFieldProps) => { if (description) { - return
{description}
; + return ( +
+
+ {description} +
+
+ ); } return null; diff --git a/packages/bootstrap-4/src/DescriptionField/index.ts b/packages/bootstrap-4/src/DescriptionField/index.ts index 401540d99b..899add9fc9 100644 --- a/packages/bootstrap-4/src/DescriptionField/index.ts +++ b/packages/bootstrap-4/src/DescriptionField/index.ts @@ -1,2 +1,2 @@ -export { default } from './DescriptionField'; -export * from './DescriptionField'; +export { default } from "./DescriptionField"; +export * from "./DescriptionField"; diff --git a/packages/bootstrap-4/src/EmailWidget/EmailWidget.tsx b/packages/bootstrap-4/src/EmailWidget/EmailWidget.tsx deleted file mode 100644 index 372a6b3f93..0000000000 --- a/packages/bootstrap-4/src/EmailWidget/EmailWidget.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; -import { WidgetProps } from '@rjsf/core'; - -const EmailWidget = (props: WidgetProps) => { - const { registry } = props; - const { TextWidget } = registry.widgets; - return ; -}; - -export default EmailWidget; diff --git a/packages/bootstrap-4/src/EmailWidget/index.ts b/packages/bootstrap-4/src/EmailWidget/index.ts deleted file mode 100644 index c48979eea8..0000000000 --- a/packages/bootstrap-4/src/EmailWidget/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './EmailWidget'; -export * from './EmailWidget'; diff --git a/packages/bootstrap-4/src/ErrorList/ErrorList.tsx b/packages/bootstrap-4/src/ErrorList/ErrorList.tsx index f30f1320d3..61dd663125 100644 --- a/packages/bootstrap-4/src/ErrorList/ErrorList.tsx +++ b/packages/bootstrap-4/src/ErrorList/ErrorList.tsx @@ -3,13 +3,13 @@ import React from "react"; import Card from "react-bootstrap/Card"; import ListGroup from "react-bootstrap/ListGroup"; -import { ErrorListProps } from "@rjsf/core"; +import { ErrorListProps } from "@rjsf/utils"; const ErrorList = ({ errors }: ErrorListProps) => ( Errors - + {errors.map((error, i: number) => { return ( diff --git a/packages/bootstrap-4/src/ErrorList/index.ts b/packages/bootstrap-4/src/ErrorList/index.ts index 79376ace11..af63a176fd 100644 --- a/packages/bootstrap-4/src/ErrorList/index.ts +++ b/packages/bootstrap-4/src/ErrorList/index.ts @@ -1,2 +1,2 @@ -export { default } from './ErrorList'; -export * from './ErrorList'; +export { default } from "./ErrorList"; +export * from "./ErrorList"; diff --git a/packages/bootstrap-4/src/FieldTemplate/FieldTemplate.tsx b/packages/bootstrap-4/src/FieldTemplate/FieldTemplate.tsx index e0191b182b..d686a3dd46 100644 --- a/packages/bootstrap-4/src/FieldTemplate/FieldTemplate.tsx +++ b/packages/bootstrap-4/src/FieldTemplate/FieldTemplate.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { FieldTemplateProps } from "@rjsf/core"; +import { FieldTemplateProps } from "@rjsf/utils"; import Form from "react-bootstrap/Form"; import ListGroup from "react-bootstrap/ListGroup"; @@ -22,6 +22,7 @@ const FieldTemplate = ({ readonly, required, schema, + registry, }: FieldTemplateProps) => { return ( + schema={schema} + registry={registry} + > {children} {displayLabel && rawDescription && ( - 0 ? "text-danger" : "text-muted"}> + 0 ? "text-danger" : "text-muted"} + > {rawDescription} )} @@ -45,10 +50,12 @@ const FieldTemplate = ({ {rawErrors.map((error: string) => { return ( - - - {error} - + + {error} ); })} @@ -57,7 +64,8 @@ const FieldTemplate = ({ {rawHelp && ( 0 ? "text-danger" : "text-muted"} - id={id}> + id={id} + > {rawHelp} )} diff --git a/packages/bootstrap-4/src/FieldTemplate/WrapIfAdditional.tsx b/packages/bootstrap-4/src/FieldTemplate/WrapIfAdditional.tsx index 13a742e090..f585d250f7 100644 --- a/packages/bootstrap-4/src/FieldTemplate/WrapIfAdditional.tsx +++ b/packages/bootstrap-4/src/FieldTemplate/WrapIfAdditional.tsx @@ -1,31 +1,27 @@ - import React from "react"; -import { utils } from "@rjsf/core"; -import { JSONSchema7 } from "json-schema"; +import { ADDITIONAL_PROPERTY_FLAG, FieldTemplateProps } from "@rjsf/utils"; import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; import Form from "react-bootstrap/Form"; -import IconButton from "../IconButton/IconButton"; - -const { ADDITIONAL_PROPERTY_FLAG } = utils; - -type WrapIfAdditionalProps = { - children: React.ReactElement; - classNames: string; - disabled: boolean; - id: string; - label: string; - onDropPropertyClick: (index: string) => (event?: any) => void; - onKeyChange: (index: string) => (event?: any) => void; - readonly: boolean; - required: boolean; - schema: JSONSchema7; -}; +type WrapIfAdditionalProps = { children: React.ReactElement } & Pick< + FieldTemplateProps, + | "classNames" + | "disabled" + | "id" + | "label" + | "onDropPropertyClick" + | "onKeyChange" + | "readonly" + | "required" + | "schema" + | "registry" +>; const WrapIfAdditional = ({ + classNames, children, disabled, id, @@ -35,43 +31,41 @@ const WrapIfAdditional = ({ readonly, required, schema, + registry, }: WrapIfAdditionalProps) => { + const { RemoveButton } = registry.templates.ButtonTemplates; const keyLabel = `${label} Key`; // i18n ? - const additional = schema.hasOwnProperty(ADDITIONAL_PROPERTY_FLAG); + const additional = ADDITIONAL_PROPERTY_FLAG in schema; if (!additional) { - return children; + return
{children}
; } const handleBlur = ({ target }: React.FocusEvent) => onKeyChange(target.value); + const keyId = `${id}-key`; return ( - + - {keyLabel} + {keyLabel} - - {children} - + {children} - diff --git a/packages/bootstrap-4/src/FieldTemplate/index.ts b/packages/bootstrap-4/src/FieldTemplate/index.ts index 6f7dc3861c..290c188da5 100644 --- a/packages/bootstrap-4/src/FieldTemplate/index.ts +++ b/packages/bootstrap-4/src/FieldTemplate/index.ts @@ -1,2 +1,2 @@ -export { default } from './FieldTemplate'; -export * from './FieldTemplate'; +export { default } from "./FieldTemplate"; +export * from "./FieldTemplate"; diff --git a/packages/bootstrap-4/src/Fields/Fields.ts b/packages/bootstrap-4/src/Fields/Fields.ts deleted file mode 100644 index a1871ac4a8..0000000000 --- a/packages/bootstrap-4/src/Fields/Fields.ts +++ /dev/null @@ -1,7 +0,0 @@ -import DescriptionField from '../DescriptionField/DescriptionField'; -import TitleField from '../TitleField/TitleField'; - -export default { - DescriptionField, - TitleField, -}; diff --git a/packages/bootstrap-4/src/Fields/index.ts b/packages/bootstrap-4/src/Fields/index.ts deleted file mode 100644 index c65ffe072d..0000000000 --- a/packages/bootstrap-4/src/Fields/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './Fields'; -export * from './Fields'; diff --git a/packages/bootstrap-4/src/FileWidget/FileWidget.tsx b/packages/bootstrap-4/src/FileWidget/FileWidget.tsx index 8ec8ba28fd..4bd934b4bb 100644 --- a/packages/bootstrap-4/src/FileWidget/FileWidget.tsx +++ b/packages/bootstrap-4/src/FileWidget/FileWidget.tsx @@ -1,10 +1,14 @@ import React from "react"; -import { WidgetProps } from '@rjsf/core'; +import { getTemplate, WidgetProps } from "@rjsf/utils"; const FileWidget = (props: WidgetProps) => { - const { registry } = props; - const { TextWidget } = registry.widgets; - return ; + const { options, registry } = props; + const BaseInputTemplate = getTemplate<"BaseInputTemplate">( + "BaseInputTemplate", + registry, + options + ); + return ; }; export default FileWidget; diff --git a/packages/bootstrap-4/src/FileWidget/index.ts b/packages/bootstrap-4/src/FileWidget/index.ts index 6e364e5c94..e70174ced2 100644 --- a/packages/bootstrap-4/src/FileWidget/index.ts +++ b/packages/bootstrap-4/src/FileWidget/index.ts @@ -1,2 +1,2 @@ -export { default } from './FileWidget'; -export * from './FileWidget'; +export { default } from "./FileWidget"; +export * from "./FileWidget"; diff --git a/packages/bootstrap-4/src/Form/Form.tsx b/packages/bootstrap-4/src/Form/Form.tsx index c24d85da93..e193619249 100644 --- a/packages/bootstrap-4/src/Form/Form.tsx +++ b/packages/bootstrap-4/src/Form/Form.tsx @@ -1,10 +1,7 @@ import { withTheme, FormProps } from "@rjsf/core"; import Theme from "../Theme"; -import { StatelessComponent } from "react"; -const Form: - | React.ComponentClass> - | StatelessComponent> = withTheme(Theme); +const Form: React.ComponentType = withTheme(Theme); export default Form; diff --git a/packages/bootstrap-4/src/IconButton/IconButton.tsx b/packages/bootstrap-4/src/IconButton/IconButton.tsx index 4f92fcb205..e1a842bc92 100644 --- a/packages/bootstrap-4/src/IconButton/IconButton.tsx +++ b/packages/bootstrap-4/src/IconButton/IconButton.tsx @@ -1,33 +1,42 @@ import React from "react"; +import { IconButtonProps } from "@rjsf/utils"; import Button, { ButtonProps } from "react-bootstrap/Button"; import { IoIosRemove } from "react-icons/io"; -import { GrAdd } from "react-icons/gr"; import { AiOutlineArrowUp, AiOutlineArrowDown } from "react-icons/ai"; -const mappings: any = { - remove: , - plus: , - "arrow-up": , - "arrow-down": , -}; - -type IconButtonProps = ButtonProps & { - icon: string; - variant?: ButtonProps['variant']; - className?: string; - tabIndex?: number; - style?: any; - disabled?: any; - onClick?: any; -}; - -const IconButton = (props: IconButtonProps) => { - const { icon, className, ...otherProps } = props; +const IconButton = (props: IconButtonProps & ButtonProps) => { + const { icon, iconType, className, ...otherProps } = props; return ( - ); }; export default IconButton; + +export function MoveDownButton(props: IconButtonProps) { + return ( + } /> + ); +} + +export function MoveUpButton(props: IconButtonProps) { + return } />; +} + +export function RemoveButton(props: IconButtonProps) { + return ( + } + /> + ); +} diff --git a/packages/bootstrap-4/src/IconButton/index.ts b/packages/bootstrap-4/src/IconButton/index.ts index 655ec4c488..55447475bc 100644 --- a/packages/bootstrap-4/src/IconButton/index.ts +++ b/packages/bootstrap-4/src/IconButton/index.ts @@ -1,2 +1,2 @@ -export { default } from './IconButton'; -export * from './IconButton'; +export { default } from "./IconButton"; +export * from "./IconButton"; diff --git a/packages/bootstrap-4/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx b/packages/bootstrap-4/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx index 352aff2758..6bfd786f5f 100644 --- a/packages/bootstrap-4/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx +++ b/packages/bootstrap-4/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx @@ -4,17 +4,15 @@ import Row from "react-bootstrap/Row"; import Col from "react-bootstrap/Col"; import Container from "react-bootstrap/Container"; -import { ObjectFieldTemplateProps } from "@rjsf/core"; -import { utils } from '@rjsf/core'; - -import AddButton from "../AddButton/AddButton"; - -const { canExpand } = utils; +import { + canExpand, + getTemplate, + getUiOptions, + ObjectFieldTemplateProps, +} from "@rjsf/utils"; const ObjectFieldTemplate = ({ - DescriptionField, description, - TitleField, title, properties, required, @@ -24,21 +22,40 @@ const ObjectFieldTemplate = ({ formData, onAddClick, disabled, - readonly + readonly, + registry, }: ObjectFieldTemplateProps) => { + const uiOptions = getUiOptions(uiSchema); + const TitleFieldTemplate = getTemplate<"TitleFieldTemplate">( + "TitleFieldTemplate", + registry, + uiOptions + ); + const DescriptionFieldTemplate = getTemplate<"DescriptionFieldTemplate">( + "DescriptionFieldTemplate", + registry, + uiOptions + ); + // Button templates are not overridden in the uiSchema + const { + ButtonTemplates: { AddButton }, + } = registry.templates; return ( <> - {(uiSchema["ui:title"] || title) && ( - )} - {description && ( - )} @@ -46,7 +63,8 @@ const ObjectFieldTemplate = ({ + className={element.hidden ? "d-none" : undefined} + > {element.content} ))} @@ -60,8 +78,8 @@ const ObjectFieldTemplate = ({ /> - ) : null } - + ) : null} + ); }; diff --git a/packages/bootstrap-4/src/ObjectFieldTemplate/index.ts b/packages/bootstrap-4/src/ObjectFieldTemplate/index.ts index 77c68a9a40..b7e3ae6245 100644 --- a/packages/bootstrap-4/src/ObjectFieldTemplate/index.ts +++ b/packages/bootstrap-4/src/ObjectFieldTemplate/index.ts @@ -1,2 +1,2 @@ -export { default } from './ObjectFieldTemplate'; -export * from './ObjectFieldTemplate'; +export { default } from "./ObjectFieldTemplate"; +export * from "./ObjectFieldTemplate"; diff --git a/packages/bootstrap-4/src/PasswordWidget/PasswordWidget.tsx b/packages/bootstrap-4/src/PasswordWidget/PasswordWidget.tsx deleted file mode 100644 index 2f5002421f..0000000000 --- a/packages/bootstrap-4/src/PasswordWidget/PasswordWidget.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React from "react"; - -import Form from "react-bootstrap/Form"; - -import { WidgetProps } from "@rjsf/core"; - -const PasswordWidget = ({ - id, - required, - readonly, - disabled, - value, - label, - onFocus, - onBlur, - onChange, - options, - autofocus, - schema, - rawErrors = [], -}: WidgetProps) => { - const _onChange = ({ - target: { value }, - }: React.ChangeEvent) => - onChange(value === "" ? options.emptyValue : value); - const _onBlur = ({ target: { value } }: React.FocusEvent) => - onBlur(id, value); - const _onFocus = ({ - target: { value }, - }: React.FocusEvent) => onFocus(id, value); - - return ( - - 0 ? "text-danger" : ""}> - {label || schema.title} - {(label || schema.title) && required ? "*" : null} - - 0 ? "is-invalid" : ""} - required={required} - disabled={disabled} - readOnly={readonly} - type="password" - value={value ? value : ""} - onFocus={_onFocus} - onBlur={_onBlur} - onChange={_onChange} - /> - - ); -}; - -export default PasswordWidget; diff --git a/packages/bootstrap-4/src/PasswordWidget/index.ts b/packages/bootstrap-4/src/PasswordWidget/index.ts deleted file mode 100644 index 84fd5e9026..0000000000 --- a/packages/bootstrap-4/src/PasswordWidget/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './PasswordWidget'; -export * from './PasswordWidget'; diff --git a/packages/bootstrap-4/src/RadioWidget/RadioWidget.tsx b/packages/bootstrap-4/src/RadioWidget/RadioWidget.tsx index 0518dabdeb..3940ec61ce 100644 --- a/packages/bootstrap-4/src/RadioWidget/RadioWidget.tsx +++ b/packages/bootstrap-4/src/RadioWidget/RadioWidget.tsx @@ -2,7 +2,7 @@ import React from "react"; import Form from "react-bootstrap/Form"; -import { WidgetProps } from "@rjsf/core"; +import { WidgetProps, getUiOptions } from "@rjsf/utils"; const RadioWidget = ({ id, @@ -19,6 +19,7 @@ const RadioWidget = ({ uiSchema, }: WidgetProps) => { const { enumOptions, enumDisabled } = options; + const uiOptions = getUiOptions(uiSchema); const _onChange = ({ target: { value }, @@ -35,8 +36,8 @@ const RadioWidget = ({ return ( - {uiSchema["ui:title"] || schema.title || label} - {(label || uiSchema["ui:title"] || schema.title) && required ? "*" : null} + {uiOptions.title || schema.title || label} + {(label || uiOptions.title || schema.title) && required ? "*" : null} {(enumOptions as any).map((option: any, i: number) => { const itemDisabled = diff --git a/packages/bootstrap-4/src/RadioWidget/index.ts b/packages/bootstrap-4/src/RadioWidget/index.ts index 10292dc565..f0568f0d81 100644 --- a/packages/bootstrap-4/src/RadioWidget/index.ts +++ b/packages/bootstrap-4/src/RadioWidget/index.ts @@ -1,2 +1,2 @@ -export { default } from './RadioWidget'; -export * from './RadioWidget'; +export { default } from "./RadioWidget"; +export * from "./RadioWidget"; diff --git a/packages/bootstrap-4/src/RangeWidget/RangeWidget.tsx b/packages/bootstrap-4/src/RangeWidget/RangeWidget.tsx index 206b487825..f75d3756c9 100644 --- a/packages/bootstrap-4/src/RangeWidget/RangeWidget.tsx +++ b/packages/bootstrap-4/src/RangeWidget/RangeWidget.tsx @@ -1,56 +1,17 @@ import React from "react"; +import { getTemplate, WidgetProps } from "@rjsf/utils"; -import Form from "react-bootstrap/Form"; - -import { utils } from "@rjsf/core"; -import { WidgetProps } from "@rjsf/core"; - -const { rangeSpec } = utils; - -const RangeWidget = ({ - value, - readonly, - disabled, - onBlur, - onFocus, - options, - schema, - onChange, - required, - label, - id, - uiSchema, -}: WidgetProps) => { - let sliderProps = { value, label, id, ...rangeSpec(schema) }; - - const _onChange = ({ - target: { value }, - }: React.ChangeEvent) => - onChange(value === "" ? options.emptyValue : value); - const _onBlur = ({ target: { value } }: React.FocusEvent) => - onBlur(id, value); - const _onFocus = ({ - target: { value }, - }: React.FocusEvent) => onFocus(id, value); - +const RangeWidget = (props: WidgetProps) => { + const { value, label, options, registry } = props; + const BaseInputTemplate = getTemplate<"BaseInputTemplate">( + "BaseInputTemplate", + registry, + options + ); return ( - - - {uiSchema["ui:title"] || schema.title || label} - {(label || uiSchema["ui:title"] || schema.title) && required ? "*" : null} - - + {value} - + ); }; diff --git a/packages/bootstrap-4/src/RangeWidget/index.ts b/packages/bootstrap-4/src/RangeWidget/index.ts index d8c49226c6..70a8e7601a 100644 --- a/packages/bootstrap-4/src/RangeWidget/index.ts +++ b/packages/bootstrap-4/src/RangeWidget/index.ts @@ -1,2 +1,2 @@ -export { default } from './RangeWidget'; -export * from './RangeWidget'; +export { default } from "./RangeWidget"; +export * from "./RangeWidget"; diff --git a/packages/bootstrap-4/src/SelectWidget/SelectWidget.tsx b/packages/bootstrap-4/src/SelectWidget/SelectWidget.tsx index 907dc4d39e..cd96122fda 100644 --- a/packages/bootstrap-4/src/SelectWidget/SelectWidget.tsx +++ b/packages/bootstrap-4/src/SelectWidget/SelectWidget.tsx @@ -2,42 +2,7 @@ import React from "react"; import Form from "react-bootstrap/Form"; -import { WidgetProps } from "@rjsf/core"; -import { utils } from "@rjsf/core"; - -const { asNumber, guessType } = utils; - -const nums = new Set(["number", "integer"]); - -/** - * This is a silly limitation in the DOM where option change event values are - * always retrieved as strings. - */ -const processValue = (schema: any, value: any) => { - // "enum" is a reserved word, so only "type" and "items" can be destructured - const { type, items } = schema; - if (value === "") { - return undefined; - } else if (type === "array" && items && nums.has(items.type)) { - return value.map(asNumber); - } else if (type === "boolean") { - return value === "true"; - } else if (type === "number") { - return asNumber(value); - } - - // If type is undefined, but an enum is present, try and infer the type from - // the enum values - if (schema.enum) { - if (schema.enum.every((x: any) => guessType(x) === "number")) { - return asNumber(value); - } else if (schema.enum.every((x: any) => guessType(x) === "boolean")) { - return value === "true"; - } - } - - return value; -}; +import { processSelectValue, WidgetProps } from "@rjsf/utils"; const SelectWidget = ({ schema, @@ -62,7 +27,7 @@ const SelectWidget = ({ function getValue( event: React.FocusEvent | React.ChangeEvent | any, - multiple: Boolean + multiple?: boolean ) { if (multiple) { return [].slice @@ -76,7 +41,10 @@ const SelectWidget = ({ return ( - 0 ? "text-danger" : ""}> + 0 ? "text-danger" : ""} + htmlFor={id} + > {label || schema.title} {(label || schema.title) && required ? "*" : null} @@ -87,28 +55,28 @@ const SelectWidget = ({ value={typeof value === "undefined" ? emptyValue : value} required={required} multiple={multiple} - disabled={disabled} - readOnly={readonly} + disabled={disabled || readonly} autoFocus={autofocus} className={rawErrors.length > 0 ? "is-invalid" : ""} onBlur={ onBlur && ((event: React.FocusEvent) => { const newValue = getValue(event, multiple); - onBlur(id, processValue(schema, newValue)); + onBlur(id, processSelectValue(schema, newValue, options)); }) } onFocus={ onFocus && ((event: React.FocusEvent) => { const newValue = getValue(event, multiple); - onFocus(id, processValue(schema, newValue)); + onFocus(id, processSelectValue(schema, newValue, options)); }) } onChange={(event: React.ChangeEvent) => { const newValue = getValue(event, multiple); - onChange(processValue(schema, newValue)); - }}> + onChange(processSelectValue(schema, newValue, options)); + }} + > {!multiple && schema.default === undefined && ( )} diff --git a/packages/bootstrap-4/src/SelectWidget/index.ts b/packages/bootstrap-4/src/SelectWidget/index.ts index e37ea725b8..91a604a36c 100644 --- a/packages/bootstrap-4/src/SelectWidget/index.ts +++ b/packages/bootstrap-4/src/SelectWidget/index.ts @@ -1,2 +1,2 @@ -export { default } from './SelectWidget'; -export * from './SelectWidget'; +export { default } from "./SelectWidget"; +export * from "./SelectWidget"; diff --git a/packages/bootstrap-4/src/SubmitButton/SubmitButton.tsx b/packages/bootstrap-4/src/SubmitButton/SubmitButton.tsx index 97ad68ed3a..fc88cc93f0 100644 --- a/packages/bootstrap-4/src/SubmitButton/SubmitButton.tsx +++ b/packages/bootstrap-4/src/SubmitButton/SubmitButton.tsx @@ -1,12 +1,19 @@ -import { utils, WidgetProps } from "@rjsf/core"; import React from "react"; import Button from "react-bootstrap/Button"; -const { getSubmitButtonOptions } = utils; -const SubmitButton: React.FC = props => { - const { submitText, norender, props: submitButtonProps }= getSubmitButtonOptions(props.uiSchema); - if(norender) return null; - return (
-
diff --git a/packages/bootstrap-4/src/SubmitButton/index.ts b/packages/bootstrap-4/src/SubmitButton/index.ts index f676497ba2..467dba2499 100644 --- a/packages/bootstrap-4/src/SubmitButton/index.ts +++ b/packages/bootstrap-4/src/SubmitButton/index.ts @@ -1,2 +1,2 @@ -export { default } from './SubmitButton'; -export * from './SubmitButton'; +export { default } from "./SubmitButton"; +export * from "./SubmitButton"; diff --git a/packages/bootstrap-4/src/Templates/Templates.ts b/packages/bootstrap-4/src/Templates/Templates.ts new file mode 100644 index 0000000000..42fc7cf9d5 --- /dev/null +++ b/packages/bootstrap-4/src/Templates/Templates.ts @@ -0,0 +1,29 @@ +import AddButton from "../AddButton"; +import ArrayFieldItemTemplate from "../ArrayFieldItemTemplate"; +import ArrayFieldTemplate from "../ArrayFieldTemplate"; +import BaseInputTemplate from "../BaseInputTemplate/BaseInputTemplate"; +import DescriptionField from "../DescriptionField"; +import ErrorList from "../ErrorList"; +import { MoveDownButton, MoveUpButton, RemoveButton } from "../IconButton"; +import FieldTemplate from "../FieldTemplate"; +import ObjectFieldTemplate from "../ObjectFieldTemplate"; +import SubmitButton from "../SubmitButton"; +import TitleField from "../TitleField"; + +export default { + ArrayFieldItemTemplate, + ArrayFieldTemplate, + BaseInputTemplate, + ButtonTemplates: { + AddButton, + MoveDownButton, + MoveUpButton, + RemoveButton, + SubmitButton, + }, + DescriptionFieldTemplate: DescriptionField, + ErrorListTemplate: ErrorList, + FieldTemplate, + ObjectFieldTemplate, + TitleFieldTemplate: TitleField, +}; diff --git a/packages/bootstrap-4/src/Templates/index.ts b/packages/bootstrap-4/src/Templates/index.ts new file mode 100644 index 0000000000..0c3e935ca4 --- /dev/null +++ b/packages/bootstrap-4/src/Templates/index.ts @@ -0,0 +1,2 @@ +export { default } from "./Templates"; +export * from "./Templates"; diff --git a/packages/bootstrap-4/src/TextWidget/index.ts b/packages/bootstrap-4/src/TextWidget/index.ts deleted file mode 100644 index fc1bc51a03..0000000000 --- a/packages/bootstrap-4/src/TextWidget/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './TextWidget'; -export * from './TextWidget'; diff --git a/packages/bootstrap-4/src/TextareaWidget/TextareaWidget.tsx b/packages/bootstrap-4/src/TextareaWidget/TextareaWidget.tsx index 9bea10d758..eca882cd31 100644 --- a/packages/bootstrap-4/src/TextareaWidget/TextareaWidget.tsx +++ b/packages/bootstrap-4/src/TextareaWidget/TextareaWidget.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { WidgetProps } from "@rjsf/core"; +import { getUiOptions, WidgetProps } from "@rjsf/utils"; import FormControl from "react-bootstrap/FormControl"; import InputGroup from "react-bootstrap/InputGroup"; @@ -25,6 +25,7 @@ const TextareaWidget = ({ rawErrors = [], uiSchema, }: CustomWidgetProps) => { + const uiOptions = getUiOptions(uiSchema); const _onChange = ({ target: { value }, }: React.ChangeEvent) => @@ -39,11 +40,12 @@ const TextareaWidget = ({ return ( <>