From 5667df5835383da6313bfb7b09d4663a83becba0 Mon Sep 17 00:00:00 2001 From: Volodymyr Zakhovaiko Date: Mon, 3 Jun 2024 09:00:10 +0200 Subject: [PATCH 1/5] Migrated `wrapField` tests to @testing-library/react (#1318) Co-authored-by: Adrian Mucha --- packages/uniforms-antd/__tests__/index.ts | 6 + .../uniforms-antd/__tests__/wrapField.tsx | 121 +++++++--------- .../__tests__/wrapField.tsx | 84 ----------- .../uniforms-bootstrap4/__tests__/index.ts | 1 + .../__tests__/wrapField.tsx | 90 +++--------- .../uniforms-bootstrap5/__tests__/index.ts | 1 + .../__tests__/wrapField.tsx | 90 +++--------- .../uniforms-material/__tests__/wrapField.tsx | 35 ----- packages/uniforms-mui/__tests__/index.ts | 8 ++ packages/uniforms-mui/__tests__/wrapField.tsx | 46 ++---- packages/uniforms/__suites__/index.ts | 5 +- packages/uniforms/__suites__/wrapField.tsx | 131 ++++++++++++++++++ 12 files changed, 248 insertions(+), 370 deletions(-) delete mode 100644 packages/uniforms-bootstrap3/__tests__/wrapField.tsx delete mode 100644 packages/uniforms-material/__tests__/wrapField.tsx create mode 100644 packages/uniforms/__suites__/wrapField.tsx diff --git a/packages/uniforms-antd/__tests__/index.ts b/packages/uniforms-antd/__tests__/index.ts index f65bc471c..f81a686bb 100644 --- a/packages/uniforms-antd/__tests__/index.ts +++ b/packages/uniforms-antd/__tests__/index.ts @@ -65,4 +65,10 @@ describe('@RTL', () => { suites.testTextField(theme.TextField); suites.testValidatedForm(theme.ValidatedForm); suites.testValidatedQuickForm(theme.ValidatedQuickForm); + suites.testWrapField(theme.wrapField, { + helpPropsName: 'help', + withoutWrapClassName: true, + withoutHelpClassName: true, + withoutLabelClassName: true, + }); }); diff --git a/packages/uniforms-antd/__tests__/wrapField.tsx b/packages/uniforms-antd/__tests__/wrapField.tsx index 4039b8930..a8dd46d3d 100644 --- a/packages/uniforms-antd/__tests__/wrapField.tsx +++ b/packages/uniforms-antd/__tests__/wrapField.tsx @@ -1,75 +1,52 @@ -import Form from 'antd/lib/form'; -import Tooltip from 'antd/lib/tooltip'; +import { screen } from '@testing-library/react'; import React from 'react'; import { wrapField } from 'uniforms-antd'; - -import mount from './_mount'; - -test(' - renders wrapper with label', () => { - const element = wrapField({ label: 'Label' },
); - const wrapper = mount(element); - - // @ts-expect-error Correct label type. - expect(wrapper.find(Form.Item).prop('label').props.children[0]).toBe('Label'); -}); - -test(' - renders wrapper with label and info', () => { - const element = wrapField({ label: 'Label', info: 'Info' },
); - const wrapper = mount(element); - - expect(wrapper.find(Tooltip).prop('title')).toBe('Info'); -}); - -test(' - renders wrapper with an error message', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: true, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('help')).toBe('Error'); -}); - -test(' - renders wrapper with an error status', () => { - const element = wrapField({},
); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('validateStatus')).toBe(undefined); -}); - -test(' - renders wrapper with an error status (error)', () => { - const error = new Error(); - const element = wrapField({ error },
); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('validateStatus')).toBe('error'); -}); - -test(' - renders wrapper with help text', () => { - const element = wrapField({ help: 'Help' },
); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('help')).toBe('Help'); -}); - -test(' - renders wrapper with extra text', () => { - const element = wrapField({ extra: 'Extra' },
); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('extra')).toBe('Extra'); -}); - -test(' - renders wrapper with extra style', () => { - const element = wrapField({ wrapperStyle: {} },
); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('style')).toEqual({}); -}); - -test(' - renders wrapper with a custom validateStatus', () => { - const element = wrapField({ validateStatus: 'success' },
); - const wrapper = mount(element); - - expect(wrapper.find(Form.Item).prop('validateStatus')).toBe('success'); +import { renderWithZod } from 'uniforms/__suites__'; +import { z } from 'zod'; + +describe('wrapField tests', () => { + test(' - renders wrapper with extra style', () => { + const { container } = renderWithZod({ + element: wrapField( + { wrapperStyle: { backgroundColor: 'red' } }, +
, + ), + schema: z.object({}), + }); + const element = container.getElementsByClassName('ant-form-item')[0]; + expect(element?.getAttribute('style')).toBe('background-color: red;'); + }); + + test(' - renders wrapper with label and info', () => { + renderWithZod({ + element: wrapField({ label: 'Label', info: 'Info' },
), + schema: z.object({}), + }); + expect(screen.getByRole('img').getAttribute('aria-label')).toBe( + 'question-circle', + ); + }); + + test(' - renders wrapper with extra text', () => { + renderWithZod({ + element: wrapField({ extra: 'Extra' },
), + schema: z.object({}), + }); + expect(screen.getByText('Extra')).toBeInTheDocument(); + }); + + test(' - renders wrapper with a custom validateStatus', () => { + renderWithZod({ + element: wrapField( + { validateStatus: 'success' }, +
, + ), + schema: z.object({}), + }); + expect( + screen + .getByTestId('x') + .closest('.ant-form-item-has-feedback.ant-form-item-has-success'), + ).toBeInTheDocument(); + }); }); diff --git a/packages/uniforms-bootstrap3/__tests__/wrapField.tsx b/packages/uniforms-bootstrap3/__tests__/wrapField.tsx deleted file mode 100644 index 9089eec21..000000000 --- a/packages/uniforms-bootstrap3/__tests__/wrapField.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import { wrapField } from 'uniforms-bootstrap3'; - -import mount from './_mount'; - -test(' - renders wrapper with correct class', () => { - const element = wrapField({ wrapClassName: 'container' },
); - const wrapper = mount(element); - - expect(wrapper.find('.container')).toHaveLength(1); -}); - -test(' - renders help block', () => { - const element = wrapField({ help: 'Hint' },
); - const wrapper = mount(element); - - expect(wrapper.find('.help-block').text()).toBe('Hint'); -}); - -test(' - renders help block with specified class', () => { - const element = wrapField( - { help: 'Hint', helpClassName: 'text-hint' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.help-block.text-hint')).toHaveLength(1); -}); - -test(' - renders error block', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: true, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.help-block').text()).toBe('Error'); -}); - -test(' - renders error block (feedbackable)', () => { - const error = new Error(); - const element = wrapField({ error, feedbackable: true },
); - const wrapper = mount(element); - - expect(wrapper.find('.form-control-feedback')).toHaveLength(1); -}); - -test(' - renders error block (showInlineError=false)', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: false, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.help-block')).toHaveLength(0); -}); - -test(' - label has custom class (String)', () => { - const element = wrapField( - { - label: 'A field label', - labelClassName: 'custom-label-class', - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('label.custom-label-class')).toHaveLength(1); -}); - -test(' - label has custom class (Array[String])', () => { - const element = wrapField( - { - label: 'A field label', - labelClassName: ['custom-1', 'custom-2'], - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('label.custom-1.custom-2')).toHaveLength(1); -}); diff --git a/packages/uniforms-bootstrap4/__tests__/index.ts b/packages/uniforms-bootstrap4/__tests__/index.ts index 74eb7b3de..7a40863f3 100644 --- a/packages/uniforms-bootstrap4/__tests__/index.ts +++ b/packages/uniforms-bootstrap4/__tests__/index.ts @@ -63,4 +63,5 @@ describe('@RTL', () => { suites.testTextField(theme.TextField, { testWrapClassName: true }); suites.testValidatedForm(theme.ValidatedForm); suites.testValidatedQuickForm(theme.ValidatedQuickForm); + suites.testWrapField(theme.wrapField); }); diff --git a/packages/uniforms-bootstrap4/__tests__/wrapField.tsx b/packages/uniforms-bootstrap4/__tests__/wrapField.tsx index ec97accf1..873a35d17 100644 --- a/packages/uniforms-bootstrap4/__tests__/wrapField.tsx +++ b/packages/uniforms-bootstrap4/__tests__/wrapField.tsx @@ -1,76 +1,20 @@ +import { screen } from '@testing-library/react'; import React from 'react'; import { wrapField } from 'uniforms-bootstrap4'; - -import mount from './_mount'; - -test(' - renders wrapper with correct class', () => { - const element = wrapField({ wrapClassName: 'container' },
); - const wrapper = mount(element); - - expect(wrapper.find('.container')).toHaveLength(1); -}); - -test(' - renders help block', () => { - const element = wrapField({ help: 'Hint' },
); - const wrapper = mount(element); - - expect(wrapper.find('.form-text').text()).toBe('Hint'); -}); - -test(' - renders help block with specified class', () => { - const element = wrapField( - { help: 'Hint', helpClassName: 'text-hint' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.form-text.text-hint')).toHaveLength(1); -}); - -test(' - renders error block', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: true, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.text-danger').text()).toBe('Error'); -}); - -test(' - renders error block (showInlineError=false)', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: false, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.text-danger')).toHaveLength(0); -}); - -test(' - label has custom class (String)', () => { - const element = wrapField( - { - label: 'A field label', - labelClassName: 'custom-label-class', - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('label.custom-label-class')).toHaveLength(1); -}); - -test(' - label has custom class (Array[String])', () => { - const element = wrapField( - { - label: 'A field label', - labelClassName: ['custom-1', 'custom-2'], - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('label.custom-1.custom-2')).toHaveLength(1); +import { renderWithZod } from 'uniforms/__suites__'; +import { z } from 'zod'; + +describe('wrapField tests', () => { + test(' - renders wrapper with correct class', () => { + renderWithZod({ + element: wrapField( + { wrapClassName: 'container' }, +
, + ), + schema: z.object({}), + }); + expect( + screen.getByTestId('x').parentElement?.classList.contains('container'), + ).toBe(true); + }); }); diff --git a/packages/uniforms-bootstrap5/__tests__/index.ts b/packages/uniforms-bootstrap5/__tests__/index.ts index 374958d94..656683d20 100644 --- a/packages/uniforms-bootstrap5/__tests__/index.ts +++ b/packages/uniforms-bootstrap5/__tests__/index.ts @@ -68,4 +68,5 @@ describe('@RTL', () => { }); suites.testValidatedForm(theme.ValidatedForm); suites.testValidatedQuickForm(theme.ValidatedQuickForm); + suites.testWrapField(theme.wrapField); }); diff --git a/packages/uniforms-bootstrap5/__tests__/wrapField.tsx b/packages/uniforms-bootstrap5/__tests__/wrapField.tsx index 88b7b8bbd..34872ccca 100644 --- a/packages/uniforms-bootstrap5/__tests__/wrapField.tsx +++ b/packages/uniforms-bootstrap5/__tests__/wrapField.tsx @@ -1,76 +1,20 @@ +import { screen } from '@testing-library/react'; import React from 'react'; import { wrapField } from 'uniforms-bootstrap5'; - -import mount from './_mount'; - -test(' - renders wrapper with correct class', () => { - const element = wrapField({ wrapClassName: 'container' },
); - const wrapper = mount(element); - - expect(wrapper.find('.container')).toHaveLength(1); -}); - -test(' - renders help block', () => { - const element = wrapField({ help: 'Hint' },
); - const wrapper = mount(element); - - expect(wrapper.find('.form-text').text()).toBe('Hint'); -}); - -test(' - renders help block with specified class', () => { - const element = wrapField( - { help: 'Hint', helpClassName: 'text-hint' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.form-text.text-hint')).toHaveLength(1); -}); - -test(' - renders error block', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: true, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.text-danger').text()).toBe('Error'); -}); - -test(' - renders error block (showInlineError=false)', () => { - const error = new Error(); - const element = wrapField( - { error, showInlineError: false, errorMessage: 'Error' }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('.text-danger')).toHaveLength(0); -}); - -test(' - label has custom class (String)', () => { - const element = wrapField( - { - label: 'A field label', - labelClassName: 'custom-label-class', - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('label.custom-label-class')).toHaveLength(1); -}); - -test(' - label has custom class (Array[String])', () => { - const element = wrapField( - { - label: 'A field label', - labelClassName: ['custom-1', 'custom-2'], - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find('label.custom-1.custom-2')).toHaveLength(1); +import { renderWithZod } from 'uniforms/__suites__'; +import { z } from 'zod'; + +describe('wrapField tests', () => { + test(' - renders wrapper with correct class', () => { + renderWithZod({ + element: wrapField( + { wrapClassName: 'container' }, +
, + ), + schema: z.object({}), + }); + expect( + screen.getByTestId('x').parentElement?.classList.contains('container'), + ).toBe(true); + }); }); diff --git a/packages/uniforms-material/__tests__/wrapField.tsx b/packages/uniforms-material/__tests__/wrapField.tsx deleted file mode 100644 index 27f25020f..000000000 --- a/packages/uniforms-material/__tests__/wrapField.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import FormControl from '@material-ui/core/FormControl'; -import FormHelperText from '@material-ui/core/FormHelperText'; -import React from 'react'; -import { wrapField } from 'uniforms-material'; - -import mount from './_mount'; - -test(' - renders wrapper', () => { - const element = wrapField({},
); - const wrapper = mount(element); - - expect(wrapper.find(FormControl)).toHaveLength(1); -}); - -test(' - renders wrapper with helper text', () => { - const element = wrapField({ helperText: 'Helper text' },
); - const wrapper = mount(element); - - expect(wrapper.find(FormHelperText).text()).toBe('Helper text'); -}); - -test(' - renders wrapper with error', () => { - const element = wrapField( - { - showInlineError: true, - error: new Error(), - errorMessage: 'Error message', - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find(FormControl).prop('error')).toBe(true); - expect(wrapper.find(FormHelperText).text()).toBe('Error message'); -}); diff --git a/packages/uniforms-mui/__tests__/index.ts b/packages/uniforms-mui/__tests__/index.ts index 634b6f46f..6827b839e 100644 --- a/packages/uniforms-mui/__tests__/index.ts +++ b/packages/uniforms-mui/__tests__/index.ts @@ -60,4 +60,12 @@ describe('@RTL', () => { suites.testTextField(theme.TextField); suites.testValidatedForm(theme.ValidatedForm); suites.testValidatedQuickForm(theme.ValidatedQuickForm); + suites.testWrapField(theme.wrapField, { + helpPropsName: 'helperText', + withoutLabel: true, + withoutInlineError: true, + withoutWrapClassName: true, + withoutHelpClassName: true, + withoutLabelClassName: true, + }); }); diff --git a/packages/uniforms-mui/__tests__/wrapField.tsx b/packages/uniforms-mui/__tests__/wrapField.tsx index af882cc7a..052c017ee 100644 --- a/packages/uniforms-mui/__tests__/wrapField.tsx +++ b/packages/uniforms-mui/__tests__/wrapField.tsx @@ -1,35 +1,19 @@ -import FormControl from '@mui/material/FormControl'; -import FormHelperText from '@mui/material/FormHelperText'; +import { screen } from '@testing-library/react'; import React from 'react'; import { wrapField } from 'uniforms-mui'; +import { renderWithZod } from 'uniforms/__suites__'; +import { z } from 'zod'; -import mount from './_mount'; - -test(' - renders wrapper', () => { - const element = wrapField({},
); - const wrapper = mount(element); - - expect(wrapper.find(FormControl)).toHaveLength(1); -}); - -test(' - renders wrapper with helper text', () => { - const element = wrapField({ helperText: 'Helper text' },
); - const wrapper = mount(element); - - expect(wrapper.find(FormHelperText).text()).toBe('Helper text'); -}); - -test(' - renders wrapper with error', () => { - const element = wrapField( - { - showInlineError: true, - error: new Error(), - errorMessage: 'Error message', - }, -
, - ); - const wrapper = mount(element); - - expect(wrapper.find(FormControl).prop('error')).toBe(true); - expect(wrapper.find(FormHelperText).text()).toBe('Error message'); +describe('wrapField tests', () => { + test(' - renders wrapper', () => { + renderWithZod({ + element: wrapField({},
), + schema: z.object({}), + }); + expect( + screen + .getByTestId('x') + .parentElement?.classList.contains('MuiFormControl-root'), + ).toBe(true); + }); }); diff --git a/packages/uniforms/__suites__/index.ts b/packages/uniforms/__suites__/index.ts index e63c78281..5b5921d47 100644 --- a/packages/uniforms/__suites__/index.ts +++ b/packages/uniforms/__suites__/index.ts @@ -16,10 +16,11 @@ export * from './NestField'; export * from './NumField'; export * from './QuickForm'; export * from './RadioField'; +export * from './render-zod'; +export * from './render'; export * from './SelectField'; export * from './SubmitField'; export * from './TextField'; export * from './ValidatedForm'; export * from './ValidatedQuickForm'; -export * from './render'; -export * from './render-zod'; +export * from './wrapField'; diff --git a/packages/uniforms/__suites__/wrapField.tsx b/packages/uniforms/__suites__/wrapField.tsx new file mode 100644 index 000000000..4c919f433 --- /dev/null +++ b/packages/uniforms/__suites__/wrapField.tsx @@ -0,0 +1,131 @@ +import { screen } from '@testing-library/react'; +import React, { ReactElement, ReactNode } from 'react'; +import z from 'zod'; + +import { renderWithZod } from './render-zod'; +import { skipTestIf } from './skipTestIf'; + +export function testWrapField( + wrapField: (wrapperProps: any, children: ReactNode) => ReactElement, + options: { + withoutLabel?: boolean; + withoutWrapClassName?: boolean; + withoutHelpClassName?: boolean; + withoutLabelClassName?: boolean; + withoutInlineError?: boolean; + helpPropsName: 'help' | 'helperText'; + } = { + helpPropsName: 'help', + }, +) { + skipTestIf(options?.withoutWrapClassName)( + ' - renders wrapper with correct class', + () => { + renderWithZod({ + element: wrapField( + { wrapClassName: 'container' }, +
, + ), + schema: z.object({}), + }); + expect( + screen.getByTestId('x').parentElement?.classList.contains('container'), + ).toBe(true); + }, + ); + + test(' - renders help block', () => { + renderWithZod({ + element: wrapField({ [options.helpPropsName]: 'Hint' },
), + schema: z.object({}), + }); + expect(screen.getByText('Hint')).toBeInTheDocument(); + }); + + skipTestIf(options?.withoutHelpClassName)( + ' - renders help block with specified class', + () => { + renderWithZod({ + element: wrapField( + { help: 'Hint', helpClassName: 'text-hint' }, +
, + ), + schema: z.object({}), + }); + const span = screen.getByText('Hint'); + expect(span.classList.contains('text-hint')).toBe(true); + }, + ); + + test(' - renders error block (showInlineError=true)', () => { + const error = new Error(); + renderWithZod({ + element: wrapField( + { error, showInlineError: true, errorMessage: 'Error' }, +
, + ), + schema: z.object({}), + }); + expect(screen.getByText('Error')).toBeInTheDocument(); + }); + + skipTestIf(options?.withoutLabel)( + ' - renders wrapper with label', + () => { + renderWithZod({ + element: wrapField({ label: 'Label' },
), + schema: z.object({}), + }); + expect(screen.getByText('Label')).toBeInTheDocument(); + }, + ); + + skipTestIf(options?.withoutLabelClassName)( + ' - label has custom class (String)', + () => { + renderWithZod({ + element: wrapField( + { label: 'A field label', labelClassName: 'custom-label-class' }, +
, + ), + schema: z.object({}), + }); + const label = screen.getByText('A field label'); + expect(label.classList.contains('custom-label-class')).toBe(true); + }, + ); + + skipTestIf(options.withoutLabelClassName)( + ' - label has custom class (Array[String])', + () => { + renderWithZod({ + element: wrapField( + { label: 'A field label', labelClassName: ['custom-1', 'custom-2'] }, +
, + ), + schema: z.object({}), + }); + const label = screen.getByText('A field label'); + expect(label.classList.contains('custom-1')).toBe(true); + expect(label.classList.contains('custom-2')).toBe(true); + }, + ); + + skipTestIf(options?.withoutInlineError)( + ' - renders error block (showInlineError=false)', + () => { + const error = new Error(); + renderWithZod({ + element: wrapField( + { error, showInlineError: false, errorMessage: 'Error' }, +
, + ), + schema: z.object({}), + }); + const x = screen.getByTestId('x'); + expect( + x.closest('.ant-form-item-has-error, .is-invalid'), + ).toBeInTheDocument(); + }, + ); +} From d2b924a5777448088a779a64da58f82474e21be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= <37746259+piotrpospiech@users.noreply.github.com> Date: Mon, 3 Jun 2024 09:27:28 +0200 Subject: [PATCH 2/5] Deprecate `uniforms-bridge-simple-schema` package (#1323) --- .eslintrc.json | 3 +- .github/labeler.yml | 5 - README.md | 1 - docs/api-bridges.md | 21 +- jest.config.js | 3 - .../uniforms-bridge-simple-schema/README.md | 11 - .../__tests__/SimpleSchemaBridge.ts | 360 ------------------ .../__tests__/index.ts | 8 - .../package.json | 41 -- .../src/SimpleSchemaBridge.ts | 184 --------- .../src/index.ts | 2 - .../src/register.ts | 56 --- .../tsconfig.cjs.json | 12 - .../tsconfig.esm.json | 12 - .../__mocks__/meteor/aldeed_simple-schema.ts | 6 - packages/uniforms/__mocks__/meteor/check.ts | 5 - reproductions/package.json | 1 - tsconfig.build.json | 2 - tsconfig.global.json | 3 - website/package.json | 1 - .../types/meteor_aldeed_simple-schema.d.ts | 9 - 21 files changed, 20 insertions(+), 726 deletions(-) delete mode 100644 packages/uniforms-bridge-simple-schema/README.md delete mode 100644 packages/uniforms-bridge-simple-schema/__tests__/SimpleSchemaBridge.ts delete mode 100644 packages/uniforms-bridge-simple-schema/__tests__/index.ts delete mode 100644 packages/uniforms-bridge-simple-schema/package.json delete mode 100644 packages/uniforms-bridge-simple-schema/src/SimpleSchemaBridge.ts delete mode 100644 packages/uniforms-bridge-simple-schema/src/index.ts delete mode 100644 packages/uniforms-bridge-simple-schema/src/register.ts delete mode 100644 packages/uniforms-bridge-simple-schema/tsconfig.cjs.json delete mode 100644 packages/uniforms-bridge-simple-schema/tsconfig.esm.json delete mode 100644 packages/uniforms/__mocks__/meteor/aldeed_simple-schema.ts delete mode 100644 packages/uniforms/__mocks__/meteor/check.ts delete mode 100644 website/types/meteor_aldeed_simple-schema.d.ts diff --git a/.eslintrc.json b/.eslintrc.json index 07af91d88..4ccc8504e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -6,7 +6,7 @@ ], "overrides": [ { - "files": ["**/__mocks__/**/*", "**/__tests__/**/*"], + "files": ["**/__tests__/**/*"], "env": { "jest": true } @@ -72,7 +72,6 @@ "valid-jsdoc": "off" }, "settings": { - "import/core-modules": ["meteor/aldeed:simple-schema", "meteor/check"], "import/resolver": { "typescript": {} }, diff --git a/.github/labeler.yml b/.github/labeler.yml index a643b0c42..875cd6fa2 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -3,7 +3,6 @@ - any-glob-to-any-file: - packages/uniforms-bridge-json-schema/**/* - packages/uniforms-bridge-simple-schema-2/**/* - - packages/uniforms-bridge-simple-schema/**/* - packages/uniforms-bridge-zod/**/* 'Area: Core': - changed-files: @@ -53,10 +52,6 @@ - changed-files: - any-glob-to-any-file: - packages/uniforms-bridge-json-schema/**/* -'Bridge: SimpleSchema': - - changed-files: - - any-glob-to-any-file: - - packages/uniforms-bridge-simple-schema/**/* 'Bridge: SimpleSchema (v2)': - changed-files: - any-glob-to-any-file: diff --git a/README.md b/README.md index a49b7ccb1..a00cb2ffd 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,6 @@ - **Inline and asynchronous form validation** - **Integrations with various schemas:** - **[JSON Schema](http://json-schema.org/)** - - **[SimpleSchema](https://github.com/aldeed/meteor-simple-schema)** - **[SimpleSchema@2](https://github.com/aldeed/node-simple-schema)** - **[Zod](https://github.com/colinhacks/zod)** - **And any other - only [a small wrapper](https://vazco.github.io/uniforms/#/introduction) is needed!** diff --git a/docs/api-bridges.md b/docs/api-bridges.md index e4044e7eb..e3f584e04 100644 --- a/docs/api-bridges.md +++ b/docs/api-bridges.md @@ -13,11 +13,11 @@ Currently available bridges: - `JSONSchemaBridge` in `uniforms-bridge-json-schema` ([schema documentation](https://json-schema.org/)) - `SimpleSchema2Bridge` in `uniforms-bridge-simple-schema-2` ([schema documentation](https://github.com/longshotlabs/simpl-schema#readme)) -- `SimpleSchemaBridge` in `uniforms-bridge-simple-schema` ([schema documentation](https://github.com/Meteor-Community-Packages/meteor-simple-schema/blob/master/DOCS.md)) - `ZodBridge` in `uniforms-bridge-zod` ([schema documentation](https://zod.dev/)) -Deprecated packages: +Deprecated bridges: +- `SimpleSchemaBridge` in `uniforms-bridge-simple-schema` ([schema documentation](https://github.com/Meteor-Community-Packages/meteor-simple-schema/blob/master/DOCS.md)) - `GraphQLBridge` in `uniforms-bridge-graphql` ([schema documentation](https://graphql.org/)) If you see a lot of [`Warning: Unknown props...`](https://fb.me/react-unknown-prop) logs, check if your schema or theme doesn't provide extra props. If so, consider [registering it with `filterDOMProps`](/docs/api-helpers#filterdomprops). @@ -141,8 +141,25 @@ const schema = new SimpleSchema({ const bridge = new SimpleSchema2Bridge({ schema }); ``` +## `ZodBridge` + +```tsx +import ZodBridge from 'uniforms-bridge-zod'; +import z from 'zod'; + +const schema = z.object({ aboutMe: z.string() }); + +const bridge = new ZodBridge({ schema }); +``` + ## `SimpleSchemaBridge` +:::caution + +SimpleSchemaBridge is deprecated since uniforms v4. + +::: + ```tsx import SimpleSchemaBridge from 'uniforms-bridge-simple-schema'; import { SimpleSchema } from 'aldeed:simple-schema'; diff --git a/jest.config.js b/jest.config.js index 5db2e632d..612d9cdcc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,9 +2,6 @@ module.exports = { collectCoverageFrom: ['packages/*/src/*.{ts,tsx}'], coverageReporters: ['html', 'lcovonly', 'text-summary'], moduleNameMapper: { - '^meteor/([^:]*):(.*)$': - '/packages/uniforms/__mocks__/meteor/$1_$2.ts', - '^meteor/([^:]*)$': '/packages/uniforms/__mocks__/meteor/$1.ts', '^simpl-schema$': '/node_modules/simpl-schema', '^uniforms/__suites__$': '/packages/uniforms/__suites__', '^uniforms([^/]*)(.*)$': '/packages/uniforms$1/src$2', diff --git a/packages/uniforms-bridge-simple-schema/README.md b/packages/uniforms-bridge-simple-schema/README.md deleted file mode 100644 index c008712cd..000000000 --- a/packages/uniforms-bridge-simple-schema/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# uniforms-bridge-simple-schema - -> Simple Schema (from Atmosphere) bridge for `uniforms`. - -## Install - -```sh -$ npm install uniforms-bridge-simple-schema -``` - -For more in depth documentation see [uniforms.tools](https://uniforms.tools). diff --git a/packages/uniforms-bridge-simple-schema/__tests__/SimpleSchemaBridge.ts b/packages/uniforms-bridge-simple-schema/__tests__/SimpleSchemaBridge.ts deleted file mode 100644 index 5895527dc..000000000 --- a/packages/uniforms-bridge-simple-schema/__tests__/SimpleSchemaBridge.ts +++ /dev/null @@ -1,360 +0,0 @@ -import { SimpleSchema } from 'meteor/aldeed:simple-schema'; -import { UnknownObject } from 'uniforms'; -import { SimpleSchemaBridge } from 'uniforms-bridge-simple-schema'; - -jest.mock('meteor/aldeed:simple-schema'); -jest.mock('meteor/check'); - -describe('SimpleSchemaBridge', () => { - const noopComponent = () => null; - const schema = { - getDefinition(name: string) { - // Simulate SimpleSchema. - name = name.replace(/\d+/g, '$'); - - const field: UnknownObject | undefined = { - a: { type: Object, label: name }, - 'a.b': { type: Object, label: name }, - 'a.b.c': { type: String, label: name }, - aa: { type: String, uniforms: { type: 'password' } }, - d: { type: String, defaultValue: 'D' }, - e: { type: String, allowedValues: ['E'] }, - f: { type: Number, min: 42 }, - g: { type: Number, max: 42 }, - h: { type: Number }, - i: { type: Date }, - j: { type: Array, minCount: 3 }, - 'j.$': { type: Object }, - 'j.$.a': { type: String, defaultValue: 'x' }, - k: { type: Array }, - 'k.$': { type: Object }, - 'k.$.a': { type: String, defaultValue: 'y' }, - l: { type: String, uniforms: 'div' }, - m: { type: String, uniforms: noopComponent }, - n: { type: String, uniforms: { component: 'div' } }, - o: { type: Array }, - 'o.$': { type: String, allowedValues: ['O'] }, - r: { - type: String, - uniforms: { - options: [ - { key: 'k1', label: 'A', value: 1 }, - { key: 'k2', label: 'B', value: 2 }, - ], - }, - }, - rr: { - type: String, - uniforms: { - options: () => [ - { key: 'k1', label: 'A', value: 1 }, - { key: 'k2', label: 'B', value: 2 }, - ], - }, - }, - s: { type: String, allowedValues: ['a', 'b'] }, - t: { type: String, allowedValues: () => ['a', 'b'] }, - u: { type: Array, defaultValue: ['u'] }, - 'u.$': { type: String }, - v: { type: Object, defaultValue: { a: 'a' } }, - 'v.a': { type: String }, - w: { type: Array, defaultValue: [{ a: 'a' }] }, - 'w.$': { type: Object }, - 'w.$.a': { type: String }, - x: { type: Array }, - 'x.$': { type: String }, - }[name]; - - if (field) { - return { - label: name.split('.').join(' ').toUpperCase(), - ...field, - }; - } - - return undefined; - }, - - messageForError(type: string, name: string) { - return `(${name})`; - }, - - objectKeys(name: 'a' | 'a.b' | 'j' | 'j.$' | 'k' | 'k.$') { - return ( - { - a: ['b'], - 'a.b': ['c'], - j: ['$'], - 'j.$': ['a'], - k: ['$'], - 'k.$': ['a'], - }[name] || [] - ); - }, - - validator() { - return () => { - throw 'ValidationError'; - }; - }, - } as unknown as SimpleSchema; - - const bridge = new SimpleSchemaBridge({ schema }); - - describe('#getError', () => { - it('works without error', () => { - expect(bridge.getError('a', null)).toBe(null); - }); - - it('works with invalid error', () => { - expect(bridge.getError('a', {})).toBe(null); - expect(bridge.getError('a', { invalid: true })).toBe(null); - }); - - it('works with correct error', () => { - expect(bridge.getError('a', { details: [{ name: 'a' }] })).toEqual({ - name: 'a', - }); - expect(bridge.getError('a', { details: [{ name: 'b' }] })).toBe(null); - }); - }); - - describe('#getErrorMessage', () => { - it('works without error', () => { - expect(bridge.getErrorMessage('a', undefined)).toBe(''); - }); - - it('works with invalid error', () => { - expect(bridge.getErrorMessage('a', {})).toBe(''); - expect(bridge.getErrorMessage('a', { invalid: true })).toBe(''); - }); - - it('works with correct error', () => { - expect( - bridge.getErrorMessage('a', { - details: [{ name: 'a', details: { value: 1 } }], - }), - ).toBe('(a)'); - expect( - bridge.getErrorMessage('a', { - details: [{ name: 'b', details: { value: 1 } }], - }), - ).toBe(''); - }); - }); - - describe('#getErrorMessages', () => { - it('works without error', () => { - expect(bridge.getErrorMessages(null)).toEqual([]); - expect(bridge.getErrorMessages(undefined)).toEqual([]); - }); - - it('works with other errors', () => { - expect(bridge.getErrorMessages('correct')).toEqual(['correct']); - expect(bridge.getErrorMessages(999999999)).toEqual([999999999]); - }); - - it('works with Error', () => { - expect(bridge.getErrorMessages(new Error('correct'))).toEqual([ - 'correct', - ]); - }); - - it('works with ValidationError', () => { - expect( - bridge.getErrorMessages({ - details: [{ name: 'a', details: { value: 1 } }], - }), - ).toEqual(['(a)']); - expect( - bridge.getErrorMessages({ - details: [{ name: 'b', details: { value: 1 } }], - }), - ).toEqual(['(b)']); - }); - }); - - describe('#getField', () => { - it('return correct definition', () => { - expect(bridge.getField('a')).toEqual(schema.getDefinition('a')); - }); - - it('throws on not found field', () => { - expect(() => bridge.getField('xxx')).toThrow(/Field not found in schema/); - }); - }); - - describe('#getInitialValue', () => { - it('works with arrays', () => { - expect(bridge.getInitialValue('k')).toEqual([]); - expect(bridge.getInitialValue('x')).toEqual([]); - }); - - it('works with arrays (minCount)', () => { - expect(bridge.getInitialValue('j')).toEqual([ - { a: 'x' }, - { a: 'x' }, - { a: 'x' }, - ]); - }); - - it('works with arrays (defaultValue)', () => { - expect(bridge.getInitialValue('u')).toEqual(['u']); - }); - - it('works with arrays of objects (defaultValue)', () => { - expect(bridge.getInitialValue('w')).toEqual([{ a: 'a' }]); - }); - - it('works with objects', () => { - expect(bridge.getInitialValue('a')).toEqual({ b: {} }); - }); - - it('works with objects (defaultValue)', () => { - expect(bridge.getInitialValue('v')).toEqual({ a: 'a' }); - }); - }); - - describe('#getProps', () => { - it('works with label in schema', () => { - expect(bridge.getProps('a')).toEqual({ - label: 'a', - required: true, - }); - }); - it('works with default label', () => { - expect(bridge.getProps('h')).toEqual({ - label: 'H', - required: true, - }); - }); - it('works with allowedValues (inferred from children)', () => { - expect(bridge.getProps('o')).toEqual({ - label: 'O', - required: true, - options: [{ value: 'O' }], - }); - }); - - it('works with custom component', () => { - expect(bridge.getProps('l')).toEqual({ - label: 'L', - required: true, - component: 'div', - }); - expect(bridge.getProps('m')).toEqual({ - label: 'M', - required: true, - component: noopComponent, - }); - }); - - it('works with custom component (field)', () => { - expect(bridge.getProps('n')).toEqual({ - label: 'N', - required: true, - component: 'div', - }); - }); - - it('works with allowedValues (array)', () => { - expect(bridge.getProps('s').options[0]).toStrictEqual({ value: 'a' }); - expect(bridge.getProps('s').options[1]).toStrictEqual({ value: 'b' }); - expect(bridge.getProps('s').allowedValues).toBeUndefined(); - }); - - it('works with allowedValues (function)', () => { - expect(bridge.getProps('t').options[0]).toStrictEqual({ value: 'a' }); - expect(bridge.getProps('t').options[1]).toStrictEqual({ value: 'b' }); - expect(bridge.getProps('t').allowedValues).toBeUndefined(); - }); - - it('works with options (array)', () => { - expect(bridge.getProps('r').options[0]).toStrictEqual({ - key: 'k1', - label: 'A', - value: 1, - }); - expect(bridge.getProps('r').options[1]).toStrictEqual({ - key: 'k2', - label: 'B', - value: 2, - }); - }); - - it('works with options (function)', () => { - expect(bridge.getProps('rr').options[0]).toStrictEqual({ - key: 'k1', - label: 'A', - value: 1, - }); - expect(bridge.getProps('rr').options[1]).toStrictEqual({ - key: 'k2', - label: 'B', - value: 2, - }); - }); - - it('works with type', () => { - expect(bridge.getProps('aa')).toEqual({ - label: 'AA', - type: 'password', - required: true, - }); - }); - - it('returns no field type', () => { - expect(bridge.getProps('a')).not.toHaveProperty('type'); - expect(bridge.getProps('j')).not.toHaveProperty('type'); - expect(bridge.getProps('d')).not.toHaveProperty('type'); - expect(bridge.getProps('f')).not.toHaveProperty('type'); - expect(bridge.getProps('i')).not.toHaveProperty('type'); - }); - }); - - describe('#getSubfields', () => { - it('works with objects', () => { - expect(bridge.getSubfields('a')).toEqual(['b']); - expect(bridge.getSubfields('a.b')).toEqual(['c']); - }); - - it('works with primitives', () => { - expect(bridge.getSubfields('d')).toEqual([]); - expect(bridge.getSubfields('e')).toEqual([]); - }); - }); - - describe('#getType', () => { - it('works with any type', () => { - expect(bridge.getType('a')).toBe(Object); - expect(bridge.getType('j')).toBe(Array); - expect(bridge.getType('d')).toBe(String); - expect(bridge.getType('f')).toBe(Number); - expect(bridge.getType('i')).toBe(Date); - }); - }); - - describe('#getValidator', () => { - it('calls correct validator', () => { - const bridge = new SimpleSchemaBridge({ - schema: { - ...schema, - validator() { - return (model: UnknownObject) => { - if (typeof model.x !== 'number') { - throw new Error(); - } - - return true; - }; - }, - } as SimpleSchema, - }); - - expect(bridge.getValidator()({})).not.toEqual(null); - expect(bridge.getValidator({})({})).not.toEqual(null); - expect(bridge.getValidator()({ x: 1 })).toEqual(null); - expect(bridge.getValidator({})({ x: 1 })).toEqual(null); - }); - }); -}); diff --git a/packages/uniforms-bridge-simple-schema/__tests__/index.ts b/packages/uniforms-bridge-simple-schema/__tests__/index.ts deleted file mode 100644 index 1c1b5ef31..000000000 --- a/packages/uniforms-bridge-simple-schema/__tests__/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as uniformsSimpleSchema from 'uniforms-bridge-simple-schema'; - -it('exports everything', () => { - expect(uniformsSimpleSchema).toEqual({ - default: expect.any(Function), - SimpleSchemaBridge: expect.any(Function), - }); -}); diff --git a/packages/uniforms-bridge-simple-schema/package.json b/packages/uniforms-bridge-simple-schema/package.json deleted file mode 100644 index d87b209d6..000000000 --- a/packages/uniforms-bridge-simple-schema/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "uniforms-bridge-simple-schema", - "version": "4.0.0-alpha.5", - "license": "MIT", - "main": "./cjs/index.js", - "module": "./esm/index.js", - "sideEffects": [ - "cjs/index.js", - "cjs/register.js", - "esm/index.js", - "esm/register.js", - "src/index.ts", - "src/register.ts" - ], - "description": "SimpleSchema bridge for uniforms.", - "repository": "https://github.com/vazco/uniforms/tree/master/packages/uniforms-bridge-simple-schema", - "bugs": "https://github.com/vazco/uniforms/issues", - "funding": "https://github.com/vazco/uniforms?sponsor=1", - "keywords": [ - "form", - "forms", - "react", - "schema", - "simple-schema", - "validation" - ], - "files": [ - "cjs/*.d.ts", - "cjs/*.js", - "esm/*.d.ts", - "esm/*.js", - "src/*.ts", - "src/*.tsx" - ], - "dependencies": { - "invariant": "^2.0.0", - "lodash": "^4.0.0", - "tslib": "^2.2.0", - "uniforms": "^4.0.0-alpha.5" - } -} diff --git a/packages/uniforms-bridge-simple-schema/src/SimpleSchemaBridge.ts b/packages/uniforms-bridge-simple-schema/src/SimpleSchemaBridge.ts deleted file mode 100644 index 878312a5a..000000000 --- a/packages/uniforms-bridge-simple-schema/src/SimpleSchemaBridge.ts +++ /dev/null @@ -1,184 +0,0 @@ -import invariant from 'invariant'; -import cloneDeep from 'lodash/cloneDeep'; -import memoize from 'lodash/memoize'; -// @ts-ignore -- This package _is_ typed, but not in all environments. -import { SimpleSchema } from 'meteor/aldeed:simple-schema'; -import { Bridge, UnknownObject, joinName } from 'uniforms'; - -const propsToRemove = ['optional', 'uniforms', 'allowedValues']; - -/** Option type used in SelectField or RadioField */ -type Option = { - disabled?: boolean; - label?: string; - key?: string; - value: Value; -}; - -export default class SimpleSchemaBridge extends Bridge { - schema: SimpleSchema; - - constructor({ schema }: { schema: SimpleSchema }) { - super(); - - this.schema = schema; - - // Memoize for performance and referential equality. - this.getField = memoize(this.getField.bind(this)); - this.getInitialValue = memoize(this.getInitialValue.bind(this)); - this.getProps = memoize(this.getProps.bind(this)); - this.getSubfields = memoize(this.getSubfields.bind(this)); - this.getType = memoize(this.getType.bind(this)); - } - - // TODO: Get rid of this `any`. - getError(name: string, error: any) { - const details = error?.details; - if (!Array.isArray(details)) { - return null; - } - - return details.find(error => error.name === name) || null; - } - - // TODO: Get rid of this `any`. - getErrorMessage(name: string, error: any) { - const scopedError = this.getError(name, error); - return !scopedError - ? '' - : this.schema.messageForError( - scopedError.type, - scopedError.name, - null, - scopedError.details && scopedError.details.value, - ); - } - - // TODO: Get rid of this `any`. - getErrorMessages(error: any) { - if (!error) { - return []; - } - - const { details } = error; - return Array.isArray(details) - ? details.map(error => - this.schema.messageForError( - error.type, - error.name, - null, - error.details && error.details.value, - ), - ) - : [error.message || error]; - } - - getField(name: string) { - const definition = this.schema.getDefinition(name); - - invariant(definition, 'Field not found in schema: "%s"', name); - - return definition; - } - - getInitialValue(name: string): unknown { - const field = this.getField(name); - const defaultValue = field.defaultValue; - if (defaultValue !== undefined) { - return cloneDeep(defaultValue); - } - - if (field.type === Array) { - const item = this.getInitialValue(joinName(name, '$')); - if (item === undefined) { - return []; - } - - const length = field.minCount || 0; - return Array.from({ length }, () => item); - } - - if (field.type === Object) { - const value: UnknownObject = {}; - this.getSubfields(name).forEach(key => { - const initialValue = this.getInitialValue(joinName(name, key)); - if (initialValue !== undefined) { - value[key] = initialValue; - } - }); - return value; - } - - return undefined; - } - - getProps(name: string) { - const { type: fieldType, ...props } = this.getField(name); - props.required = !props.optional; - - if ( - typeof props.uniforms === 'function' || - typeof props.uniforms === 'string' - ) { - props.component = props.uniforms; - } else { - Object.assign(props, props.uniforms); - } - - type OptionList = Option[]; - type Options = OptionList | (() => OptionList); - let options: Options | undefined = props.options; - let allowedValues: unknown[] | (() => unknown[]) | undefined = - props.allowedValues; - - if (typeof options === 'function') { - options = options(); - } - - if (!options && typeof allowedValues === 'function') { - allowedValues = allowedValues(); - } - - if (!options && Array.isArray(allowedValues)) { - options = allowedValues.map(value => ({ value })); - } else if (fieldType === Array) { - try { - const itemProps = this.getProps(`${name}.$`); - if (itemProps.options) { - options = itemProps.options as OptionList; - } - } catch (_) { - // It's fine. - } - } - - propsToRemove.forEach(key => { - if (key in props) { - delete props[key]; - } - }); - - return Object.assign(props, { options }); - } - - getSubfields(name?: string): string[] { - return this.schema.objectKeys(SimpleSchema._makeGeneric(name)); - } - - getType(name: string) { - return this.getField(name).type; - } - - getValidator(options: UnknownObject = { clean: true }) { - const validator = this.schema.validator(options); - return (model: any) => { - try { - // Clean mutate its argument. - validator(options.clean ? cloneDeep({ ...model }) : model); - return null; - } catch (error) { - return error; - } - }; - } -} diff --git a/packages/uniforms-bridge-simple-schema/src/index.ts b/packages/uniforms-bridge-simple-schema/src/index.ts deleted file mode 100644 index 5ee541797..000000000 --- a/packages/uniforms-bridge-simple-schema/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import './register'; -export { default, default as SimpleSchemaBridge } from './SimpleSchemaBridge'; diff --git a/packages/uniforms-bridge-simple-schema/src/register.ts b/packages/uniforms-bridge-simple-schema/src/register.ts deleted file mode 100644 index 3d4672fe6..000000000 --- a/packages/uniforms-bridge-simple-schema/src/register.ts +++ /dev/null @@ -1,56 +0,0 @@ -// @ts-ignore -- This package _is_ typed, but not in all environments. -import { SimpleSchema } from 'meteor/aldeed:simple-schema'; -import { Match } from 'meteor/check'; -import { filterDOMProps } from 'uniforms'; - -// Register custom property. -SimpleSchema.extendOptions({ - uniforms: Match.Optional( - Match.OneOf( - String, - Function, - Match.ObjectIncluding({ - component: Match.Optional(Match.OneOf(String, Function)), - }), - ), - ), -}); - -// There's no possibility to retrieve them at runtime. -declare module 'uniforms' { - interface FilterDOMProps { - autoValue: never; - blackbox: never; - custom: never; - decimal: never; - defaultValue: never; - exclusiveMax: never; - exclusiveMin: never; - max: never; - maxCount: never; - min: never; - minCount: never; - optional: never; - regEx: never; - trim: never; - type: never; - } -} - -filterDOMProps.register( - 'autoValue', - 'blackbox', - 'custom', - 'decimal', - 'defaultValue', - 'exclusiveMax', - 'exclusiveMin', - 'max', - 'maxCount', - 'min', - 'minCount', - 'optional', - 'regEx', - 'trim', - 'type', -); diff --git a/packages/uniforms-bridge-simple-schema/tsconfig.cjs.json b/packages/uniforms-bridge-simple-schema/tsconfig.cjs.json deleted file mode 100644 index efc5ca26e..000000000 --- a/packages/uniforms-bridge-simple-schema/tsconfig.cjs.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "baseUrl": "src", - "outDir": "cjs", - "rootDir": "src", - "module": "CommonJS", - "tsBuildInfoFile": "../../node_modules/.cache/uniforms-bridge-simple-schema.cjs.tsbuildinfo" - }, - "include": ["src"], - "references": [{ "path": "../uniforms/tsconfig.cjs.json" }] -} diff --git a/packages/uniforms-bridge-simple-schema/tsconfig.esm.json b/packages/uniforms-bridge-simple-schema/tsconfig.esm.json deleted file mode 100644 index 805301825..000000000 --- a/packages/uniforms-bridge-simple-schema/tsconfig.esm.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "baseUrl": "src", - "outDir": "esm", - "rootDir": "src", - "module": "ES6", - "tsBuildInfoFile": "../../node_modules/.cache/uniforms-bridge-simple-schema.esm.tsbuildinfo" - }, - "include": ["src"], - "references": [{ "path": "../uniforms/tsconfig.esm.json" }] -} diff --git a/packages/uniforms/__mocks__/meteor/aldeed_simple-schema.ts b/packages/uniforms/__mocks__/meteor/aldeed_simple-schema.ts deleted file mode 100644 index 183d458d8..000000000 --- a/packages/uniforms/__mocks__/meteor/aldeed_simple-schema.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const SimpleSchema = { - extendOptions: jest.fn(), - _makeGeneric: jest.fn(name => - typeof name === 'string' ? name.replace(/\.[0-9]+(?=\.|$)/g, '.$') : null, - ), -}; diff --git a/packages/uniforms/__mocks__/meteor/check.ts b/packages/uniforms/__mocks__/meteor/check.ts deleted file mode 100644 index af3fcdef1..000000000 --- a/packages/uniforms/__mocks__/meteor/check.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const Match = { - OneOf: jest.fn(), - Optional: jest.fn(), - ObjectIncluding: jest.fn(), -}; diff --git a/reproductions/package.json b/reproductions/package.json index 9f7a497e0..549e9fd56 100644 --- a/reproductions/package.json +++ b/reproductions/package.json @@ -27,7 +27,6 @@ "uniforms-bootstrap4": "^4.0.0-alpha.0", "uniforms-bootstrap5": "^4.0.0-alpha.0", "uniforms-bridge-json-schema": "^4.0.0-alpha.0", - "uniforms-bridge-simple-schema": "^4.0.0-alpha.0", "uniforms-bridge-simple-schema-2": "^4.0.0-alpha.0", "uniforms-material": "^4.0.0-alpha.0", "uniforms-mui": "^4.0.0-alpha.0", diff --git a/tsconfig.build.json b/tsconfig.build.json index aac9aa6bf..382337b4a 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -14,8 +14,6 @@ { "path": "packages/uniforms-bootstrap5/tsconfig.esm.json" }, { "path": "packages/uniforms-bridge-json-schema/tsconfig.cjs.json" }, { "path": "packages/uniforms-bridge-json-schema/tsconfig.esm.json" }, - { "path": "packages/uniforms-bridge-simple-schema/tsconfig.cjs.json" }, - { "path": "packages/uniforms-bridge-simple-schema/tsconfig.esm.json" }, { "path": "packages/uniforms-bridge-simple-schema-2/tsconfig.cjs.json" }, { "path": "packages/uniforms-bridge-simple-schema-2/tsconfig.esm.json" }, { "path": "packages/uniforms-bridge-zod/tsconfig.cjs.json" }, diff --git a/tsconfig.global.json b/tsconfig.global.json index 5e6861fee..09343ce44 100644 --- a/tsconfig.global.json +++ b/tsconfig.global.json @@ -6,7 +6,6 @@ "tsBuildInfoFile": "node_modules/.cache/global.tsbuildinfo" }, "include": [ - "packages/*/__mocks__", "packages/*/__tests__", "packages/uniforms/__suites__", "scripts", @@ -25,8 +24,6 @@ { "path": "packages/uniforms-bootstrap5/tsconfig.cjs.json" }, { "path": "packages/uniforms-bridge-json-schema/tsconfig.esm.json" }, { "path": "packages/uniforms-bridge-json-schema/tsconfig.cjs.json" }, - { "path": "packages/uniforms-bridge-simple-schema/tsconfig.esm.json" }, - { "path": "packages/uniforms-bridge-simple-schema/tsconfig.cjs.json" }, { "path": "packages/uniforms-bridge-simple-schema-2/tsconfig.esm.json" }, { "path": "packages/uniforms-bridge-simple-schema-2/tsconfig.cjs.json" }, { "path": "packages/uniforms-bridge-zod/tsconfig.esm.json" }, diff --git a/website/package.json b/website/package.json index 08696f8f2..ba75438ee 100644 --- a/website/package.json +++ b/website/package.json @@ -30,7 +30,6 @@ "uniforms-bootstrap4": "^4.0.0-alpha.0", "uniforms-bootstrap5": "^4.0.0-alpha.0", "uniforms-bridge-json-schema": "^4.0.0-alpha.0", - "uniforms-bridge-simple-schema": "^4.0.0-alpha.0", "uniforms-bridge-simple-schema-2": "^4.0.0-alpha.0", "uniforms-bridge-zod": "^4.0.0-alpha.0", "uniforms-material": "^4.0.0-alpha.0", diff --git a/website/types/meteor_aldeed_simple-schema.d.ts b/website/types/meteor_aldeed_simple-schema.d.ts deleted file mode 100644 index 7fc02368e..000000000 --- a/website/types/meteor_aldeed_simple-schema.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -declare module 'meteor/aldeed:simple-schema' { - import SimpleSchemaStatic from 'simpl-schema'; - export class SimpleSchema extends SimpleSchemaStatic { - static _makeGeneric(name?: string): string | undefined; - // This type has to use `any` to match the `simpl-schema` argument type. - static extendOptions(options: Record): void; - objectKeys(name?: string): string[]; - } -} From 1e53adc135cbcdfe16166ca6e3016490bbc0c1d2 Mon Sep 17 00:00:00 2001 From: Adrian Mucha Date: Thu, 6 Jun 2024 08:46:09 +0200 Subject: [PATCH 3/5] Add section about development best practices to CONTRIBUTING (#1337) Co-authored-by: Konrad Bosak --- .github/CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6f7dde4dc..4279d9471 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -30,6 +30,42 @@ Our kanban board is public and available [here](https://github.com/orgs/vazco/pr - Make sure you have added the necessary tests for your changes. Do not worry though, the Codecov bot will report it in the pull request. - Make sure your code passes _all_ tests: `npm test`. +### Development + +For the best local developer experience (DX) it is recommended to start `build` and `test` in `--watch` mode. + +Run the commands below in the root directory. + +#### Running the build in watch mode + +```sh +npm run build -- --watch +``` + +#### Running the tests in watch mode + +```sh +npm run test -- --watch +``` + +#### Fixing lint issues automatically + +```sh +npm run lint:code -- --fix +``` + +#### Making changes to the documentation website (docusaurus) + +The local version of docs will use the locally built version of uniforms, so make sure to run the build in watch mode for live changes. + +Navigate to `/website` and run + +```sh +npm start +``` + +It will start the docusaurus in development mode supporting hot reload so you should see the changes made to the website immediately. + ## _Work in progress_ PRs are also welcome If you can't or won't finish your PR, submit it anyway - maybe someone else will continue your work. If you don't know how to achieve your desired feature - file an issue for it - maybe someone else will implement it. From a8f4ced256f85a85c9352359573905f58582bcb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Po=C5=9Bpiech?= <37746259+piotrpospiech@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:16:59 +0200 Subject: [PATCH 4/5] Deprecate `uniforms-bootstrap3` package (#1341) --- .github/labeler.yml | 5 - README.md | 1 - docs/installation.mdx | 1 - package-lock.json | 14 -- packages/uniforms-bootstrap3/README.md | 11 -- .../uniforms-bootstrap3/__tests__/_mount.tsx | 14 -- .../__tests__/gridClassName.ts | 42 ------ .../uniforms-bootstrap3/__tests__/index.ts | 66 ---------- packages/uniforms-bootstrap3/package.json | 41 ------ .../uniforms-bootstrap3/src/AutoField.tsx | 43 ------ .../uniforms-bootstrap3/src/AutoFields.tsx | 37 ------ packages/uniforms-bootstrap3/src/AutoForm.tsx | 13 -- packages/uniforms-bootstrap3/src/BaseForm.tsx | 40 ------ .../uniforms-bootstrap3/src/BoolField.tsx | 59 --------- .../uniforms-bootstrap3/src/DateField.tsx | 72 ---------- .../uniforms-bootstrap3/src/ErrorField.tsx | 36 ----- .../uniforms-bootstrap3/src/ErrorsField.tsx | 26 ---- .../uniforms-bootstrap3/src/HiddenField.tsx | 35 ----- .../uniforms-bootstrap3/src/ListAddField.tsx | 70 ---------- .../uniforms-bootstrap3/src/ListDelField.tsx | 68 ---------- .../uniforms-bootstrap3/src/ListField.tsx | 75 ----------- .../uniforms-bootstrap3/src/ListItemField.tsx | 30 ----- .../uniforms-bootstrap3/src/LongTextField.tsx | 32 ----- .../uniforms-bootstrap3/src/NestField.tsx | 41 ------ packages/uniforms-bootstrap3/src/NumField.tsx | 44 ------- .../uniforms-bootstrap3/src/QuickForm.tsx | 28 ---- .../uniforms-bootstrap3/src/RadioField.tsx | 55 -------- .../uniforms-bootstrap3/src/SelectField.tsx | 124 ------------------ .../uniforms-bootstrap3/src/SubmitField.tsx | 78 ----------- .../uniforms-bootstrap3/src/TextField.tsx | 35 ----- .../uniforms-bootstrap3/src/ValidatedForm.tsx | 13 -- .../src/ValidatedQuickForm.tsx | 5 - .../uniforms-bootstrap3/src/gridClassName.ts | 38 ------ packages/uniforms-bootstrap3/src/index.ts | 25 ---- packages/uniforms-bootstrap3/src/types.ts | 7 - .../uniforms-bootstrap3/src/wrapField.tsx | 112 ---------------- .../uniforms-bootstrap3/tsconfig.cjs.json | 12 -- .../uniforms-bootstrap3/tsconfig.esm.json | 12 -- reproductions/App.tsx | 1 - reproductions/package.json | 1 - tsconfig.build.json | 2 - tsconfig.global.json | 2 - website/components/ExampleCustomizer.tsx | 1 - website/components/Playground.tsx | 2 +- website/components/TutorialForm.tsx | 1 - website/lib/styles.tsx | 4 - website/lib/universal.tsx | 2 - website/package.json | 1 - website/pages-parts/LandingPage/WhyUs.tsx | 1 - 49 files changed, 1 insertion(+), 1477 deletions(-) delete mode 100644 packages/uniforms-bootstrap3/README.md delete mode 100644 packages/uniforms-bootstrap3/__tests__/_mount.tsx delete mode 100644 packages/uniforms-bootstrap3/__tests__/gridClassName.ts delete mode 100644 packages/uniforms-bootstrap3/__tests__/index.ts delete mode 100644 packages/uniforms-bootstrap3/package.json delete mode 100644 packages/uniforms-bootstrap3/src/AutoField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/AutoFields.tsx delete mode 100644 packages/uniforms-bootstrap3/src/AutoForm.tsx delete mode 100644 packages/uniforms-bootstrap3/src/BaseForm.tsx delete mode 100644 packages/uniforms-bootstrap3/src/BoolField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/DateField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ErrorField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ErrorsField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/HiddenField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ListAddField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ListDelField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ListField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ListItemField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/LongTextField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/NestField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/NumField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/QuickForm.tsx delete mode 100644 packages/uniforms-bootstrap3/src/RadioField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/SelectField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/SubmitField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/TextField.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ValidatedForm.tsx delete mode 100644 packages/uniforms-bootstrap3/src/ValidatedQuickForm.tsx delete mode 100644 packages/uniforms-bootstrap3/src/gridClassName.ts delete mode 100644 packages/uniforms-bootstrap3/src/index.ts delete mode 100644 packages/uniforms-bootstrap3/src/types.ts delete mode 100644 packages/uniforms-bootstrap3/src/wrapField.tsx delete mode 100644 packages/uniforms-bootstrap3/tsconfig.cjs.json delete mode 100644 packages/uniforms-bootstrap3/tsconfig.esm.json diff --git a/.github/labeler.yml b/.github/labeler.yml index 875cd6fa2..0abe2cf83 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -41,7 +41,6 @@ - changed-files: - any-glob-to-any-file: - packages/uniforms-antd/**/* - - packages/uniforms-bootstrap3/**/* - packages/uniforms-bootstrap4/**/* - packages/uniforms-bootstrap5/**/* - packages/uniforms-material/**/* @@ -64,10 +63,6 @@ - changed-files: - any-glob-to-any-file: - packages/uniforms-antd/**/* -'Theme: Bootstrap 3': - - changed-files: - - any-glob-to-any-file: - - packages/uniforms-bootstrap3/**/* 'Theme: Bootstrap 4': - changed-files: - any-glob-to-any-file: diff --git a/README.md b/README.md index a00cb2ffd..d91b76155 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ - **And any other - only [a small wrapper](https://vazco.github.io/uniforms/#/introduction) is needed!** - **Wide range of themes:** - **[AntD](https://ant.design/) theme** - - **[Bootstrap3](https://getbootstrap.com/docs/3.4/) theme** - **[Bootstrap4](https://getbootstrap.com/docs/4.6) theme** - **[Bootstrap5](https://getbootstrap.com/) theme** - **[Material](https://v4.mui.com/) theme** diff --git a/docs/installation.mdx b/docs/installation.mdx index d6b973226..2ed1a9ccf 100644 --- a/docs/installation.mdx +++ b/docs/installation.mdx @@ -37,7 +37,6 @@ Now the schema package. { name: 'Semantic' }, { name: 'Material' }, { name: 'MUI' }, - { name: 'Bootstrap3' }, { name: 'Bootstrap4' }, { name: 'Bootstrap5' }, { name: 'AntD' }, diff --git a/package-lock.json b/package-lock.json index 17a3e4fac..1c76069dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,6 @@ "eslint-config-vazco": "6.2.0", "eslint-import-resolver-alias": "1.1.2", "eslint-import-resolver-typescript": "2.3.0", - "graphql": "^15.0.0", "husky": "8.0.1", "invariant": "^2.0.0", "jest": "27.0.6", @@ -15806,14 +15805,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, - "node_modules/graphql": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.3.tgz", - "integrity": "sha512-sM+jXaO5KinTui6lbK/7b7H/Knj9BpjGxZ+Ki35v7YbUJxxdBCUqNM0h3CRVU1ZF9t5lNiBzvBCSYPvIwxPOQA==", - "engines": { - "node": ">= 10.x" - } - }, "node_modules/gray-matter": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", @@ -40359,11 +40350,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" }, - "graphql": { - "version": "15.5.3", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-15.5.3.tgz", - "integrity": "sha512-sM+jXaO5KinTui6lbK/7b7H/Knj9BpjGxZ+Ki35v7YbUJxxdBCUqNM0h3CRVU1ZF9t5lNiBzvBCSYPvIwxPOQA==" - }, "gray-matter": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", diff --git a/packages/uniforms-bootstrap3/README.md b/packages/uniforms-bootstrap3/README.md deleted file mode 100644 index bf4963a4a..000000000 --- a/packages/uniforms-bootstrap3/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# uniforms-bootstrap3 - -> Bootstrap3 UI components for `uniforms`. - -## Install - -```sh -$ npm install uniforms-bootstrap3 -``` - -For more in depth documentation see [uniforms.tools](https://uniforms.tools). diff --git a/packages/uniforms-bootstrap3/__tests__/_mount.tsx b/packages/uniforms-bootstrap3/__tests__/_mount.tsx deleted file mode 100644 index d586e42dd..000000000 --- a/packages/uniforms-bootstrap3/__tests__/_mount.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { mount as enzyme } from 'enzyme'; -import { context } from 'uniforms'; - -function mount(node: any, options: any) { - if (options === undefined) { - return enzyme(node); - } - return enzyme(node, { - wrappingComponent: context.Provider, - wrappingComponentProps: { value: options.context }, - }); -} - -export default mount as typeof enzyme; diff --git a/packages/uniforms-bootstrap3/__tests__/gridClassName.ts b/packages/uniforms-bootstrap3/__tests__/gridClassName.ts deleted file mode 100644 index 1af0c5192..000000000 --- a/packages/uniforms-bootstrap3/__tests__/gridClassName.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { gridClassName } from 'uniforms-bootstrap3'; - -test('gridClassName - object', () => { - expect(gridClassName({ md: 3 }, 'input')).toBe('col-md-9'); - expect(gridClassName({ md: 5 }, 'input')).toBe('col-md-7'); - expect(gridClassName({ md: 7 }, 'input')).toBe('col-md-5'); - expect(gridClassName({ md: 9 }, 'input')).toBe('col-md-3'); - expect(gridClassName({ md: 3, xs: 2 }, 'input')).toBe('col-md-9 col-xs-10'); - expect(gridClassName({ md: 5, xs: 4 }, 'input')).toBe('col-md-7 col-xs-8'); - expect(gridClassName({ md: 7, xs: 6 }, 'input')).toBe('col-md-5 col-xs-6'); - expect(gridClassName({ md: 9, xs: 8 }, 'input')).toBe('col-md-3 col-xs-4'); - - expect(gridClassName({ md: 3 }, 'label')).toBe('col-md-3'); - expect(gridClassName({ md: 5 }, 'label')).toBe('col-md-5'); - expect(gridClassName({ md: 7 }, 'label')).toBe('col-md-7'); - expect(gridClassName({ md: 9 }, 'label')).toBe('col-md-9'); - expect(gridClassName({ md: 3, xs: 2 }, 'label')).toBe('col-md-3 col-xs-2'); - expect(gridClassName({ md: 5, xs: 4 }, 'label')).toBe('col-md-5 col-xs-4'); - expect(gridClassName({ md: 7, xs: 6 }, 'label')).toBe('col-md-7 col-xs-6'); - expect(gridClassName({ md: 9, xs: 8 }, 'label')).toBe('col-md-9 col-xs-8'); -}); - -test('gridClassName - number', () => { - expect(gridClassName(3, 'input')).toBe('col-sm-9'); - expect(gridClassName(3, 'label')).toBe('col-sm-3'); - expect(gridClassName(5, 'input')).toBe('col-sm-7'); - expect(gridClassName(5, 'label')).toBe('col-sm-5'); -}); - -test('gridClassName - number (string)', () => { - expect(gridClassName('3', 'input')).toBe('col-sm-9'); - expect(gridClassName('3', 'label')).toBe('col-sm-3'); - expect(gridClassName('5', 'input')).toBe('col-sm-7'); - expect(gridClassName('5', 'label')).toBe('col-sm-5'); -}); - -test('gridClassName - string', () => { - expect(gridClassName('col-md-9')).toBe('col-md-9'); - expect(gridClassName('col-md-3')).toBe('col-md-3'); - expect(gridClassName('col-md-7')).toBe('col-md-7'); - expect(gridClassName('col-md-5')).toBe('col-md-5'); -}); diff --git a/packages/uniforms-bootstrap3/__tests__/index.ts b/packages/uniforms-bootstrap3/__tests__/index.ts deleted file mode 100644 index 73501bc3f..000000000 --- a/packages/uniforms-bootstrap3/__tests__/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -import * as theme from 'uniforms-bootstrap3'; -import * as suites from 'uniforms/__suites__'; - -it('exports everything', () => { - expect(theme).toEqual({ - AutoFields: expect.any(Function), - AutoField: expect.any(Function), - AutoForm: expect.any(Function), - BaseForm: expect.any(Function), - BoolField: expect.any(Function), - DateField: expect.any(Function), - ErrorField: expect.any(Function), - ErrorsField: expect.any(Function), - HiddenField: expect.any(Function), - ListAddField: expect.any(Function), - ListDelField: expect.any(Function), - ListField: expect.any(Function), - ListItemField: expect.any(Function), - LongTextField: expect.any(Function), - NestField: expect.any(Function), - NumField: expect.any(Function), - QuickForm: expect.any(Function), - RadioField: expect.any(Function), - SelectField: expect.any(Function), - SubmitField: expect.any(Function), - TextField: expect.any(Function), - ValidatedForm: expect.any(Function), - ValidatedQuickForm: expect.any(Function), - gridClassName: expect.any(Function), - wrapField: expect.any(Function), - }); -}); - -describe('@RTL', () => { - suites.testAutoField(theme.AutoField, { - getDateField: screen => screen.getByLabelText('X'), - getSelectField: screen => screen.getByRole('combobox'), - }); - suites.testAutoForm(theme.AutoForm); - suites.testBaseForm(theme.BaseForm); - suites.testBoolField(theme.BoolField, { testInline: true }); - suites.testDateField(theme.DateField); - suites.testErrorField(theme.ErrorField); - suites.testErrorsField(theme.ErrorsField); - suites.testHiddenField(theme.HiddenField); - suites.testListAddField(theme.ListAddField); - suites.testListDelField(theme.ListDelField); - suites.testListField(theme.ListField, { - getListAddField: screen => screen.getByRole('button'), - disableInlineError: true, - }); - suites.testListItemField(theme.ListItemField); - suites.testLongTextField(theme.LongTextField); - suites.testNestField(theme.NestField); - suites.testNumField(theme.NumField); - suites.testQuickForm(theme.QuickForm); - suites.testRadioField(theme.RadioField); - suites.testSelectField(theme.SelectField, { - getCheckboxInlineOption: screen => - screen.getByLabelText('a').closest('.checkbox-inline'), - }); - suites.testSubmitField(theme.SubmitField); - suites.testTextField(theme.TextField, { testWrapClassName: true }); - suites.testValidatedForm(theme.ValidatedForm); - suites.testValidatedQuickForm(theme.ValidatedQuickForm); -}); diff --git a/packages/uniforms-bootstrap3/package.json b/packages/uniforms-bootstrap3/package.json deleted file mode 100644 index 99c858e4a..000000000 --- a/packages/uniforms-bootstrap3/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "uniforms-bootstrap3", - "version": "4.0.0-alpha.5", - "license": "MIT", - "main": "./cjs/index.js", - "module": "./esm/index.js", - "sideEffects": false, - "description": "Bootstrap3 UI components for uniforms.", - "repository": "https://github.com/vazco/uniforms/tree/master/packages/uniforms-bootstrap3", - "bugs": "https://github.com/vazco/uniforms/issues", - "funding": "https://github.com/vazco/uniforms?sponsor=1", - "keywords": [ - "bootstrap", - "form", - "forms", - "meteor", - "react", - "react-component", - "schema", - "validation" - ], - "files": [ - "cjs/*.d.ts", - "cjs/*.js", - "esm/*.d.ts", - "esm/*.js", - "src/*.ts", - "src/*.tsx" - ], - "peerDependencies": { - "react": "^18.0.0 || ^17.0.0 || ^16.8.0" - }, - "dependencies": { - "classnames": "^2.0.0", - "invariant": "^2.0.0", - "lodash": "^4.0.0", - "tslib": "^2.2.0", - "uniforms": "^4.0.0-alpha.5", - "warning": "^4.0.0" - } -} diff --git a/packages/uniforms-bootstrap3/src/AutoField.tsx b/packages/uniforms-bootstrap3/src/AutoField.tsx deleted file mode 100644 index fe7a4693f..000000000 --- a/packages/uniforms-bootstrap3/src/AutoField.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import invariant from 'invariant'; -export { AutoFieldProps } from 'uniforms'; -import { createAutoField } from 'uniforms'; - -import BoolField from './BoolField'; -import DateField from './DateField'; -import ListField from './ListField'; -import NestField from './NestField'; -import NumField from './NumField'; -import RadioField from './RadioField'; -import SelectField from './SelectField'; -import TextField from './TextField'; - -const AutoField = createAutoField(props => { - if (props.component) { - return props.component; - } - - if (props.options) { - return props.checkboxes && props.fieldType !== Array - ? RadioField - : SelectField; - } - - switch (props.fieldType) { - case Array: - return ListField; - case Boolean: - return BoolField; - case Date: - return DateField; - case Number: - return NumField; - case Object: - return NestField; - case String: - return TextField; - } - - return invariant(false, 'Unsupported field type: %s', props.fieldType); -}); - -export default AutoField; diff --git a/packages/uniforms-bootstrap3/src/AutoFields.tsx b/packages/uniforms-bootstrap3/src/AutoFields.tsx deleted file mode 100644 index 1f70b06e0..000000000 --- a/packages/uniforms-bootstrap3/src/AutoFields.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { ComponentType, Fragment, createElement } from 'react'; -import { useForm } from 'uniforms'; - -import AutoField from './AutoField'; - -export type AutoFieldsProps = { - element?: ComponentType | string; - fields?: string[]; - omitFields?: string[]; - showInlineError?: boolean; -}; - -export default function AutoFields({ - element = Fragment, - fields, - omitFields = [], - showInlineError, - ...props -}: AutoFieldsProps) { - const { schema } = useForm(); - - return createElement( - element, - props, - (fields ?? schema.getSubfields()) - .filter(field => !omitFields.includes(field)) - .map(field => - createElement( - AutoField, - Object.assign( - { key: field, name: field }, - showInlineError === undefined ? null : { showInlineError }, - ), - ), - ), - ); -} diff --git a/packages/uniforms-bootstrap3/src/AutoForm.tsx b/packages/uniforms-bootstrap3/src/AutoForm.tsx deleted file mode 100644 index ea8321711..000000000 --- a/packages/uniforms-bootstrap3/src/AutoForm.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { AutoForm } from 'uniforms'; - -import ValidatedQuickForm from './ValidatedQuickForm'; - -function Auto(parent: any) { - class _ extends AutoForm.Auto(parent) { - static Auto = Auto; - } - - return _ as unknown as AutoForm; -} - -export default Auto(ValidatedQuickForm); diff --git a/packages/uniforms-bootstrap3/src/BaseForm.tsx b/packages/uniforms-bootstrap3/src/BaseForm.tsx deleted file mode 100644 index fc4e96cc2..000000000 --- a/packages/uniforms-bootstrap3/src/BaseForm.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import classnames from 'classnames'; -import { BaseForm } from 'uniforms'; - -function Bootstrap3(parent: any) { - class _ extends parent { - static Bootstrap3 = Bootstrap3; - - static displayName = `Bootstrap3${parent.displayName}`; - - getContextState() { - return { - ...super.getContextState(), - grid: this.props.grid, - }; - } - - getNativeFormProps() { - const error = this.getContextError(); - const { - className, - grid, - - ...props - } = super.getNativeFormProps(); - - return { - ...props, - className: classnames( - 'form', - { error, 'form-horizontal': grid }, - className, - ), - }; - } - } - - return _ as unknown as typeof BaseForm; -} - -export default Bootstrap3(BaseForm); diff --git a/packages/uniforms-bootstrap3/src/BoolField.tsx b/packages/uniforms-bootstrap3/src/BoolField.tsx deleted file mode 100644 index 80b1447f4..000000000 --- a/packages/uniforms-bootstrap3/src/BoolField.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import classnames from 'classnames'; -import React, { Ref } from 'react'; -import { connectField, HTMLFieldProps } from 'uniforms'; - -import wrapField from './wrapField'; - -export type BoolFieldProps = HTMLFieldProps< - boolean, - HTMLDivElement, - { - inline?: boolean; - inputClassName?: string; - inputRef?: Ref; - labelBefore?: string; - } ->; - -function Bool(props: BoolFieldProps) { - const { - disabled, - inline, - inputClassName, - label, - labelBefore, - name, - onChange, - readOnly, - value, - } = props; - return wrapField( - { ...props, label: labelBefore }, -
- -
, - ); -} - -export default connectField(Bool, { kind: 'leaf' }); diff --git a/packages/uniforms-bootstrap3/src/DateField.tsx b/packages/uniforms-bootstrap3/src/DateField.tsx deleted file mode 100644 index 63f69f72b..000000000 --- a/packages/uniforms-bootstrap3/src/DateField.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import classnames from 'classnames'; -import React, { Ref } from 'react'; -import { connectField, HTMLFieldProps } from 'uniforms'; - -import wrapField from './wrapField'; - -type DateFieldType = 'date' | 'datetime-local'; - -/* istanbul ignore next */ -const DateConstructor = (typeof global === 'object' ? global : window).Date; -const dateFormat = (value?: Date, type: DateFieldType = 'datetime-local') => - value?.toISOString().slice(0, type === 'datetime-local' ? -8 : -14); - -export type DateFieldProps = HTMLFieldProps< - Date, - HTMLDivElement, - { - error: unknown; - inputClassName?: string; - inputRef?: Ref; - max?: Date; - min?: Date; - wrapClassName?: string; - type?: DateFieldType; - } ->; - -function Date({ - disabled, - error, - id, - inputClassName, - inputRef, - max, - min, - name, - onChange, - placeholder, - readOnly, - value, - type = 'datetime-local', - ...props -}: DateFieldProps) { - return wrapField( - { ...props, id }, - { - const date = new DateConstructor(event.target.valueAsNumber); - if (date.getFullYear() < 10000) { - onChange(date); - } else if (isNaN(event.target.valueAsNumber)) { - onChange(undefined); - } - }} - placeholder={placeholder} - readOnly={readOnly} - ref={inputRef} - type={type} - value={dateFormat(value, type) ?? ''} - />, - ); -} - -export default connectField(Date, { kind: 'leaf' }); diff --git a/packages/uniforms-bootstrap3/src/ErrorField.tsx b/packages/uniforms-bootstrap3/src/ErrorField.tsx deleted file mode 100644 index 3ddcb803d..000000000 --- a/packages/uniforms-bootstrap3/src/ErrorField.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import classnames from 'classnames'; -import React, { HTMLProps } from 'react'; -import { connectField, filterDOMProps, Override } from 'uniforms'; - -export type ErrorFieldProps = Override< - Omit, 'onChange'>, - { error?: any; errorMessage?: string } ->; - -function Error({ - children, - className, - error, - errorMessage, - ...props -}: ErrorFieldProps) { - return !error ? null : ( -
-
- {children || ( -
-

{errorMessage}

-
- )} -
-
- ); -} - -export default connectField(Error, { - initialValue: false, - kind: 'leaf', -}); diff --git a/packages/uniforms-bootstrap3/src/ErrorsField.tsx b/packages/uniforms-bootstrap3/src/ErrorsField.tsx deleted file mode 100644 index 64b827da0..000000000 --- a/packages/uniforms-bootstrap3/src/ErrorsField.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import classnames from 'classnames'; -import React, { HTMLProps } from 'react'; -import { filterDOMProps, useForm } from 'uniforms'; - -export type ErrorsFieldProps = HTMLProps; - -function ErrorsField({ className, children, ...props }: ErrorsFieldProps) { - const { error, schema } = useForm(); - - return !error && !children ? null : ( -
-
- {children} - - {schema.getErrorMessages(error).map((message, index) => ( -
{message}
- ))} -
-
- ); -} - -export default ErrorsField; diff --git a/packages/uniforms-bootstrap3/src/HiddenField.tsx b/packages/uniforms-bootstrap3/src/HiddenField.tsx deleted file mode 100644 index 616f87f08..000000000 --- a/packages/uniforms-bootstrap3/src/HiddenField.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { HTMLProps, Ref, useEffect } from 'react'; -import { Override, filterDOMProps, useField } from 'uniforms'; - -export type HiddenFieldProps = Override< - HTMLProps, - { - inputRef?: Ref; - name: string; - noDOM?: boolean; - value?: unknown; - } ->; - -export default function HiddenField({ value, ...rawProps }: HiddenFieldProps) { - const props = useField(rawProps.name, rawProps, { initialValue: false })[0]; - - useEffect(() => { - if (value !== undefined && value !== props.value) { - props.onChange(value); - } - }); - - return props.noDOM ? null : ( - - ); -} diff --git a/packages/uniforms-bootstrap3/src/ListAddField.tsx b/packages/uniforms-bootstrap3/src/ListAddField.tsx deleted file mode 100644 index b48dac9af..000000000 --- a/packages/uniforms-bootstrap3/src/ListAddField.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import classnames from 'classnames'; -import cloneDeep from 'lodash/cloneDeep'; -import React, { ReactNode } from 'react'; -import { - HTMLFieldProps, - connectField, - filterDOMProps, - joinName, - useField, -} from 'uniforms'; - -export type ListAddFieldProps = HTMLFieldProps< - unknown, - HTMLDivElement, - { addIcon?: ReactNode } ->; - -function ListAdd({ - addIcon, - className, - disabled, - name, - readOnly, - value, - ...props -}: ListAddFieldProps) { - const nameParts = joinName(null, name); - const parentName = joinName(nameParts.slice(0, -1)); - const parent = useField< - { - maxCount?: number; - }, - unknown[] - >(parentName, {}, { absoluteName: true })[0]; - - const limitNotReached = - !disabled && !(parent.maxCount! <= parent.value!.length); - - function onAction(event: React.KeyboardEvent | React.MouseEvent) { - if ( - limitNotReached && - !readOnly && - (!('key' in event) || event.key === 'Enter') - ) { - parent.onChange(parent.value!.concat([cloneDeep(value)])); - } - } - - return ( -
- {addIcon} -
- ); -} - -ListAdd.defaultProps = { - addIcon: , -}; - -export default connectField(ListAdd, { - initialValue: false, - kind: 'leaf', -}); diff --git a/packages/uniforms-bootstrap3/src/ListDelField.tsx b/packages/uniforms-bootstrap3/src/ListDelField.tsx deleted file mode 100644 index 8c844a41b..000000000 --- a/packages/uniforms-bootstrap3/src/ListDelField.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import classnames from 'classnames'; -import React, { ReactNode } from 'react'; -import { - HTMLFieldProps, - connectField, - filterDOMProps, - joinName, - useField, -} from 'uniforms'; - -export type ListDelFieldProps = HTMLFieldProps< - unknown, - HTMLDivElement, - { removeIcon?: ReactNode } ->; - -function ListDel({ - className, - disabled, - name, - readOnly, - removeIcon, - ...props -}: ListDelFieldProps) { - const nameParts = joinName(null, name); - const nameIndex = +nameParts[nameParts.length - 1]; - const parentName = joinName(nameParts.slice(0, -1)); - const parent = useField<{ minCount?: number }, unknown[]>( - parentName, - {}, - { absoluteName: true }, - )[0]; - - disabled ||= readOnly || parent.minCount! >= parent.value!.length; - function onAction( - event: - | React.KeyboardEvent - | React.MouseEvent, - ) { - if (!disabled && (!('key' in event) || event.key === 'Enter')) { - const value = parent.value!.slice(); - value.splice(nameIndex, 1); - parent.onChange(value); - } - } - - return ( - - {removeIcon} - - ); -} - -ListDel.defaultProps = { - removeIcon: , -}; - -export default connectField(ListDel, { - initialValue: false, - kind: 'leaf', -}); diff --git a/packages/uniforms-bootstrap3/src/ListField.tsx b/packages/uniforms-bootstrap3/src/ListField.tsx deleted file mode 100644 index c2bb9c943..000000000 --- a/packages/uniforms-bootstrap3/src/ListField.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import classnames from 'classnames'; -import React, { - Children, - ReactNode, - cloneElement, - isValidElement, -} from 'react'; -import { HTMLFieldProps, connectField, filterDOMProps } from 'uniforms'; - -import ListAddField from './ListAddField'; -import ListItemField from './ListItemField'; - -export type ListFieldProps = HTMLFieldProps< - unknown[], - HTMLDivElement, - { - addIcon?: ReactNode; - itemProps?: object; - removeIcon?: ReactNode; - } ->; - -function List({ - addIcon, - children = , - className, - error, - errorMessage, - itemProps, - label, - removeIcon, - showInlineError, - value, - ...props -}: ListFieldProps) { - return ( -
-
- {label && ( -
- - - - - {!!(error && showInlineError) && ( - {errorMessage} - )} -
- )} - - {value?.map((item, itemIndex) => - Children.map(children, (child, childIndex) => - isValidElement(child) - ? cloneElement(child, { - key: `${itemIndex}-${childIndex}`, - name: child.props.name?.replace('$', '' + itemIndex), - ...itemProps, - removeIcon, - }) - : child, - ), - )} -
-
- ); -} - -export default connectField(List); diff --git a/packages/uniforms-bootstrap3/src/ListItemField.tsx b/packages/uniforms-bootstrap3/src/ListItemField.tsx deleted file mode 100644 index 06713d84d..000000000 --- a/packages/uniforms-bootstrap3/src/ListItemField.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { ReactNode } from 'react'; -import { connectField } from 'uniforms'; - -import AutoField from './AutoField'; -import ListDelField from './ListDelField'; - -export type ListItemFieldProps = { - children?: ReactNode; - name: string; - removeIcon?: ReactNode; - value?: unknown; -}; - -function ListItem({ - children = , - removeIcon, -}: ListItemFieldProps) { - return ( -
-
- -
- {children} -
- ); -} - -export default connectField(ListItem, { - initialValue: false, -}); diff --git a/packages/uniforms-bootstrap3/src/LongTextField.tsx b/packages/uniforms-bootstrap3/src/LongTextField.tsx deleted file mode 100644 index 2a2157a29..000000000 --- a/packages/uniforms-bootstrap3/src/LongTextField.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import classnames from 'classnames'; -import React, { Ref } from 'react'; -import { connectField, HTMLFieldProps } from 'uniforms'; - -import wrapField from './wrapField'; - -export type LongTextFieldProps = HTMLFieldProps< - string, - HTMLDivElement, - { inputClassName?: string; inputRef?: Ref } ->; - -function LongText(props: LongTextFieldProps) { - return wrapField( - props, -