@strictly/react-form 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.cjs +26 -0
- package/.out/.storybook/main.d.ts +3 -0
- package/.out/.storybook/main.js +32 -0
- package/.out/.storybook/preview.d.ts +4 -0
- package/.out/.storybook/preview.js +20 -0
- package/.out/.vitest/install_deterministic_random.d.ts +2 -0
- package/.out/.vitest/install_deterministic_random.js +15 -0
- package/.out/.vitest/install_storybook_preview.d.ts +1 -0
- package/.out/.vitest/install_storybook_preview.js +7 -0
- package/.out/.vitest/match_media.d.ts +1 -0
- package/.out/.vitest/match_media.js +5 -0
- package/.out/.vitest/resize_observer.d.ts +1 -0
- package/.out/.vitest/resize_observer.js +4 -0
- package/.out/core/mobx/field_adapter.d.ts +9 -0
- package/.out/core/mobx/field_adapter.js +1 -0
- package/.out/core/mobx/field_adapter_builder.d.ts +22 -0
- package/.out/core/mobx/field_adapter_builder.js +56 -0
- package/.out/core/mobx/flattened_adapters_of_fields.d.ts +9 -0
- package/.out/core/mobx/flattened_adapters_of_fields.js +1 -0
- package/.out/core/mobx/flattened_list_type_defs_of.d.ts +8 -0
- package/.out/core/mobx/flattened_list_type_defs_of.js +1 -0
- package/.out/core/mobx/form_presenter.d.ts +61 -0
- package/.out/core/mobx/form_presenter.js +425 -0
- package/.out/core/mobx/specs/flattened_adapters_of_fields.tests.d.ts +1 -0
- package/.out/core/mobx/specs/flattened_adapters_of_fields.tests.js +13 -0
- package/.out/core/mobx/specs/flattened_list_type_defs_of.tests.d.ts +1 -0
- package/.out/core/mobx/specs/flattened_list_type_defs_of.tests.js +16 -0
- package/.out/core/mobx/specs/form_presenter.tests.d.ts +1 -0
- package/.out/core/mobx/specs/form_presenter.tests.js +697 -0
- package/.out/core/mobx/types.d.ts +19 -0
- package/.out/core/mobx/types.js +1 -0
- package/.out/core/props.d.ts +12 -0
- package/.out/core/props.js +1 -0
- package/.out/field_converters/chain_field_converter.d.ts +3 -0
- package/.out/field_converters/chain_field_converter.js +46 -0
- package/.out/field_converters/identity_converter.d.ts +3 -0
- package/.out/field_converters/identity_converter.js +14 -0
- package/.out/field_converters/integer_to_string_converter.d.ts +7 -0
- package/.out/field_converters/integer_to_string_converter.js +26 -0
- package/.out/field_converters/list_converter.d.ts +2 -0
- package/.out/field_converters/list_converter.js +8 -0
- package/.out/field_converters/maybe_identity_converter.d.ts +8 -0
- package/.out/field_converters/maybe_identity_converter.js +15 -0
- package/.out/field_converters/nullable_to_boolean_converter.d.ts +11 -0
- package/.out/field_converters/nullable_to_boolean_converter.js +31 -0
- package/.out/field_converters/select_value_type_converter.d.ts +23 -0
- package/.out/field_converters/select_value_type_converter.js +60 -0
- package/.out/field_converters/trimming_string_converter.d.ts +6 -0
- package/.out/field_converters/trimming_string_converter.js +14 -0
- package/.out/field_converters/validating_converter.d.ts +3 -0
- package/.out/field_converters/validating_converter.js +21 -0
- package/.out/field_validators/minimum_string_length_field_validator.d.ts +2 -0
- package/.out/field_validators/minimum_string_length_field_validator.js +8 -0
- package/.out/field_value_factories/prototyping_field_value_factory.d.ts +2 -0
- package/.out/field_value_factories/prototyping_field_value_factory.js +5 -0
- package/.out/index.d.ts +16 -0
- package/.out/index.js +16 -0
- package/.out/mantine/create_checkbox.d.ts +9 -0
- package/.out/mantine/create_checkbox.js +37 -0
- package/.out/mantine/create_list.d.ts +15 -0
- package/.out/mantine/create_list.js +16 -0
- package/.out/mantine/create_pill.d.ts +7 -0
- package/.out/mantine/create_pill.js +15 -0
- package/.out/mantine/create_radio.d.ts +8 -0
- package/.out/mantine/create_radio.js +10 -0
- package/.out/mantine/create_radio_group.d.ts +9 -0
- package/.out/mantine/create_radio_group.js +34 -0
- package/.out/mantine/create_text_input.d.ts +19 -0
- package/.out/mantine/create_text_input.js +38 -0
- package/.out/mantine/create_value_input.d.ts +17 -0
- package/.out/mantine/create_value_input.js +38 -0
- package/.out/mantine/hooks.d.ts +56 -0
- package/.out/mantine/hooks.js +135 -0
- package/.out/mantine/specs/checkbox_constants.d.ts +1 -0
- package/.out/mantine/specs/checkbox_constants.js +1 -0
- package/.out/mantine/specs/checkbox_hooks.stories.d.ts +13 -0
- package/.out/mantine/specs/checkbox_hooks.stories.js +63 -0
- package/.out/mantine/specs/checkbox_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/checkbox_hooks.tests.js +74 -0
- package/.out/mantine/specs/list_hooks.stories.d.ts +11 -0
- package/.out/mantine/specs/list_hooks.stories.js +48 -0
- package/.out/mantine/specs/list_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/list_hooks.tests.js +12 -0
- package/.out/mantine/specs/radio_group_constants.d.ts +4 -0
- package/.out/mantine/specs/radio_group_constants.js +11 -0
- package/.out/mantine/specs/radio_group_hooks.stories.d.ts +14 -0
- package/.out/mantine/specs/radio_group_hooks.stories.js +68 -0
- package/.out/mantine/specs/radio_group_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/radio_group_hooks.tests.js +62 -0
- package/.out/mantine/specs/select_hooks.stories.d.ts +12 -0
- package/.out/mantine/specs/select_hooks.stories.js +57 -0
- package/.out/mantine/specs/select_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/select_hooks.tests.js +12 -0
- package/.out/mantine/specs/select_hooks_constant.d.ts +1 -0
- package/.out/mantine/specs/select_hooks_constant.js +1 -0
- package/.out/mantine/specs/text_input_constants.d.ts +1 -0
- package/.out/mantine/specs/text_input_constants.js +1 -0
- package/.out/mantine/specs/text_input_hooks.stories.d.ts +21 -0
- package/.out/mantine/specs/text_input_hooks.stories.js +88 -0
- package/.out/mantine/specs/text_input_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/text_input_hooks.tests.js +79 -0
- package/.out/mantine/specs/value_input_constants.d.ts +2 -0
- package/.out/mantine/specs/value_input_constants.js +2 -0
- package/.out/mantine/specs/value_input_hooks.stories.d.ts +23 -0
- package/.out/mantine/specs/value_input_hooks.stories.js +124 -0
- package/.out/mantine/specs/value_input_hooks.tests.d.ts +1 -0
- package/.out/mantine/specs/value_input_hooks.tests.js +12 -0
- package/.out/mantine/types.d.ts +11 -0
- package/.out/mantine/types.js +1 -0
- package/.out/tsconfig.json +27 -0
- package/.out/tsconfig.tsbuildinfo +1 -0
- package/.out/tsup.config.d.ts +3 -0
- package/.out/tsup.config.js +12 -0
- package/.out/types/all_fields_of_fields.d.ts +5 -0
- package/.out/types/all_fields_of_fields.js +1 -0
- package/.out/types/boolean_fields_of_fields.d.ts +5 -0
- package/.out/types/boolean_fields_of_fields.js +1 -0
- package/.out/types/error_type_of_field.d.ts +2 -0
- package/.out/types/error_type_of_field.js +1 -0
- package/.out/types/field.d.ts +7 -0
- package/.out/types/field.js +1 -0
- package/.out/types/field_converters.d.ts +29 -0
- package/.out/types/field_converters.js +5 -0
- package/.out/types/field_validator.d.ts +3 -0
- package/.out/types/field_validator.js +1 -0
- package/.out/types/flattened_form_fields_of.d.ts +9 -0
- package/.out/types/flattened_form_fields_of.js +1 -0
- package/.out/types/list_fields_of_fields.d.ts +5 -0
- package/.out/types/list_fields_of_fields.js +1 -0
- package/.out/types/specs/boolean_fields_of_fields.tests.d.ts +1 -0
- package/.out/types/specs/boolean_fields_of_fields.tests.js +11 -0
- package/.out/types/specs/error_type_of_field.tests.d.ts +1 -0
- package/.out/types/specs/error_type_of_field.tests.js +7 -0
- package/.out/types/specs/flattened_form_fields_of.tests.d.ts +1 -0
- package/.out/types/specs/flattened_form_fields_of.tests.js +13 -0
- package/.out/types/specs/string_fields_of_fields.tests.d.ts +1 -0
- package/.out/types/specs/string_fields_of_fields.tests.js +19 -0
- package/.out/types/specs/value_type_of_field.tests.d.ts +1 -0
- package/.out/types/specs/value_type_of_field.tests.js +7 -0
- package/.out/types/string_fields_of_fields.d.ts +5 -0
- package/.out/types/string_fields_of_fields.js +1 -0
- package/.out/types/value_type_of_field.d.ts +2 -0
- package/.out/types/value_type_of_field.js +1 -0
- package/.out/util/partial.d.ts +11 -0
- package/.out/util/partial.js +74 -0
- package/.out/vitest.workspace.d.ts +2 -0
- package/.out/vitest.workspace.js +22 -0
- package/.storybook/main.ts +40 -0
- package/.storybook/preview.tsx +28 -0
- package/.storybook/vite.config.mts +38 -0
- package/.turbo/turbo-build.log +18 -0
- package/.turbo/turbo-check-types.log +3 -0
- package/.turbo/turbo-release$colon$exports.log +3 -0
- package/.vitest/install_deterministic_random.ts +17 -0
- package/.vitest/install_storybook_preview.ts +9 -0
- package/.vitest/match_media.ts +7 -0
- package/.vitest/resize_observer.ts +5 -0
- package/README.md +2 -0
- package/core/mobx/field_adapter.ts +32 -0
- package/core/mobx/field_adapter_builder.ts +313 -0
- package/core/mobx/flattened_adapters_of_fields.ts +35 -0
- package/core/mobx/flattened_list_type_defs_of.ts +17 -0
- package/core/mobx/form_presenter.ts +705 -0
- package/core/mobx/specs/flattened_adapters_of_fields.tests.ts +72 -0
- package/core/mobx/specs/flattened_list_type_defs_of.tests.ts +35 -0
- package/core/mobx/specs/form_presenter.tests.ts +989 -0
- package/core/mobx/types.ts +54 -0
- package/core/props.ts +21 -0
- package/dist/index.cjs +11479 -0
- package/dist/index.d.cts +345 -0
- package/dist/index.d.ts +345 -0
- package/dist/index.js +11486 -0
- package/field_converters/chain_field_converter.ts +74 -0
- package/field_converters/identity_converter.ts +39 -0
- package/field_converters/integer_to_string_converter.ts +32 -0
- package/field_converters/list_converter.ts +15 -0
- package/field_converters/maybe_identity_converter.ts +23 -0
- package/field_converters/nullable_to_boolean_converter.ts +56 -0
- package/field_converters/select_value_type_converter.ts +141 -0
- package/field_converters/trimming_string_converter.ts +23 -0
- package/field_converters/validating_converter.ts +35 -0
- package/field_validators/minimum_string_length_field_validator.ts +13 -0
- package/field_value_factories/prototyping_field_value_factory.ts +11 -0
- package/index.ts +16 -0
- package/mantine/create_checkbox.tsx +79 -0
- package/mantine/create_list.tsx +58 -0
- package/mantine/create_pill.tsx +43 -0
- package/mantine/create_radio.tsx +36 -0
- package/mantine/create_radio_group.tsx +71 -0
- package/mantine/create_text_input.tsx +80 -0
- package/mantine/create_value_input.tsx +81 -0
- package/mantine/hooks.tsx +394 -0
- package/mantine/specs/__snapshots__/check_box_hooks.tests.tsx.snap +227 -0
- package/mantine/specs/__snapshots__/checkbox_hooks.tests.tsx.snap +227 -0
- package/mantine/specs/__snapshots__/list_hooks.tests.tsx.snap +68 -0
- package/mantine/specs/__snapshots__/radio_group_hooks.tests.tsx.snap +695 -0
- package/mantine/specs/__snapshots__/select_hooks.tests.tsx.snap +225 -0
- package/mantine/specs/__snapshots__/text_input_hooks.tests.tsx.snap +202 -0
- package/mantine/specs/__snapshots__/value_input_hooks.tests.tsx.snap +613 -0
- package/mantine/specs/checkbox_constants.ts +1 -0
- package/mantine/specs/checkbox_hooks.stories.tsx +79 -0
- package/mantine/specs/checkbox_hooks.tests.tsx +100 -0
- package/mantine/specs/list_hooks.stories.tsx +83 -0
- package/mantine/specs/list_hooks.tests.tsx +15 -0
- package/mantine/specs/radio_group_constants.ts +12 -0
- package/mantine/specs/radio_group_hooks.stories.tsx +103 -0
- package/mantine/specs/radio_group_hooks.tests.tsx +92 -0
- package/mantine/specs/select_hooks.stories.tsx +77 -0
- package/mantine/specs/select_hooks.tests.tsx +14 -0
- package/mantine/specs/select_hooks_constant.ts +1 -0
- package/mantine/specs/text_input_constants.ts +1 -0
- package/mantine/specs/text_input_hooks.stories.tsx +124 -0
- package/mantine/specs/text_input_hooks.tests.tsx +106 -0
- package/mantine/specs/value_input_constants.ts +2 -0
- package/mantine/specs/value_input_hooks.stories.tsx +182 -0
- package/mantine/specs/value_input_hooks.tests.tsx +14 -0
- package/mantine/types.ts +13 -0
- package/package.exports.json +18 -0
- package/package.json +74 -0
- package/tsconfig.build.json +13 -0
- package/tsconfig.json +27 -0
- package/tsup.config.ts +16 -0
- package/types/all_fields_of_fields.ts +9 -0
- package/types/boolean_fields_of_fields.ts +8 -0
- package/types/error_type_of_field.ts +3 -0
- package/types/field.ts +9 -0
- package/types/field_converters.ts +64 -0
- package/types/field_validator.ts +7 -0
- package/types/flattened_form_fields_of.ts +16 -0
- package/types/list_fields_of_fields.ts +7 -0
- package/types/specs/boolean_fields_of_fields.tests.ts +23 -0
- package/types/specs/error_type_of_field.tests.ts +10 -0
- package/types/specs/flattened_form_fields_of.tests.ts +43 -0
- package/types/specs/string_fields_of_fields.tests.ts +40 -0
- package/types/specs/value_type_of_field.tests.ts +10 -0
- package/types/string_fields_of_fields.ts +6 -0
- package/types/value_type_of_field.ts +3 -0
- package/util/partial.tsx +200 -0
- package/vitest.workspace.ts +26 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { composeStories } from '@storybook/react'
|
|
2
|
+
import { toArray } from '@strictly/base'
|
|
3
|
+
import {
|
|
4
|
+
fireEvent,
|
|
5
|
+
render,
|
|
6
|
+
type RenderResult,
|
|
7
|
+
} from '@testing-library/react'
|
|
8
|
+
import {
|
|
9
|
+
type Mock,
|
|
10
|
+
vi,
|
|
11
|
+
} from 'vitest'
|
|
12
|
+
import { CHECKBOX_LABEL } from './checkbox_constants'
|
|
13
|
+
import * as stories from './checkbox_hooks.stories'
|
|
14
|
+
|
|
15
|
+
const composedStories = composeStories(stories)
|
|
16
|
+
const {
|
|
17
|
+
Off,
|
|
18
|
+
On,
|
|
19
|
+
} = composedStories
|
|
20
|
+
|
|
21
|
+
describe('mantine checkbox hooks', function () {
|
|
22
|
+
it.each(toArray(composedStories))('renders %s', function (_name, Story) {
|
|
23
|
+
const wrapper = render(<Story />)
|
|
24
|
+
expect(wrapper.container).toMatchSnapshot()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe.each([
|
|
28
|
+
[
|
|
29
|
+
'Off',
|
|
30
|
+
Off,
|
|
31
|
+
true,
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
'On',
|
|
35
|
+
On,
|
|
36
|
+
false,
|
|
37
|
+
],
|
|
38
|
+
] as const)('value change %s', function (_name, Component, expectedValue) {
|
|
39
|
+
let onFieldValueChange: Mock<(path: '$', value: boolean) => void>
|
|
40
|
+
let wrapper: RenderResult
|
|
41
|
+
let checkbox: HTMLElement
|
|
42
|
+
|
|
43
|
+
beforeEach(async function () {
|
|
44
|
+
onFieldValueChange = vi.fn()
|
|
45
|
+
wrapper = render(<Component onFieldValueChange={onFieldValueChange} />)
|
|
46
|
+
checkbox = await wrapper.findByLabelText(CHECKBOX_LABEL)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('requests toggle', function () {
|
|
50
|
+
fireEvent.click(checkbox)
|
|
51
|
+
expect(onFieldValueChange).toHaveBeenCalledOnce()
|
|
52
|
+
expect(onFieldValueChange).toHaveBeenCalledWith('$', expectedValue)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
describe('other events', function () {
|
|
57
|
+
let onFieldFocus: Mock<(path: '$') => void>
|
|
58
|
+
let onFieldBlur: Mock<(path: '$') => void>
|
|
59
|
+
let wrapper: RenderResult
|
|
60
|
+
let checkbox: HTMLElement
|
|
61
|
+
|
|
62
|
+
beforeEach(async function () {
|
|
63
|
+
onFieldFocus = vi.fn()
|
|
64
|
+
onFieldBlur = vi.fn()
|
|
65
|
+
wrapper = render((
|
|
66
|
+
<Off
|
|
67
|
+
onFieldBlur={onFieldBlur}
|
|
68
|
+
onFieldFocus={onFieldFocus}
|
|
69
|
+
/>
|
|
70
|
+
))
|
|
71
|
+
checkbox = await wrapper.findByLabelText(CHECKBOX_LABEL)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
describe('focus', function () {
|
|
75
|
+
beforeEach(function () {
|
|
76
|
+
fireEvent.focus(checkbox)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('fires focus event', function () {
|
|
80
|
+
expect(onFieldFocus).toHaveBeenCalledOnce()
|
|
81
|
+
expect(onFieldFocus).toHaveBeenCalledWith('$')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('blur', function () {
|
|
85
|
+
beforeEach(function () {
|
|
86
|
+
fireEvent.blur(checkbox)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('fires blur event', function () {
|
|
90
|
+
expect(onFieldBlur).toHaveBeenCalledOnce()
|
|
91
|
+
expect(onFieldBlur).toHaveBeenCalledWith('$')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('does not refire focus event', function () {
|
|
95
|
+
expect(onFieldFocus).toHaveBeenCalledOnce()
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
})
|
|
100
|
+
})
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Code,
|
|
3
|
+
Paper,
|
|
4
|
+
Stack,
|
|
5
|
+
} from '@mantine/core'
|
|
6
|
+
import { action } from '@storybook/addon-actions'
|
|
7
|
+
import {
|
|
8
|
+
type Meta,
|
|
9
|
+
type StoryObj,
|
|
10
|
+
} from '@storybook/react'
|
|
11
|
+
import { type FormProps } from 'core/props'
|
|
12
|
+
import { useMantineForm } from 'mantine/hooks'
|
|
13
|
+
import { type Field } from 'types/field'
|
|
14
|
+
|
|
15
|
+
type ListPath = `$.${number}`
|
|
16
|
+
|
|
17
|
+
function Component(props: FormProps<{
|
|
18
|
+
$: Field<string[], string>,
|
|
19
|
+
}>) {
|
|
20
|
+
const form = useMantineForm(props)
|
|
21
|
+
const List = form.list('$')
|
|
22
|
+
return (
|
|
23
|
+
<Paper
|
|
24
|
+
p='sm'
|
|
25
|
+
withBorder={true}
|
|
26
|
+
>
|
|
27
|
+
<Stack>
|
|
28
|
+
<List>
|
|
29
|
+
{function (valuePath: ListPath) {
|
|
30
|
+
return (
|
|
31
|
+
<Code key={valuePath}>
|
|
32
|
+
ValuePath: {valuePath}
|
|
33
|
+
</Code>
|
|
34
|
+
)
|
|
35
|
+
}}
|
|
36
|
+
</List>
|
|
37
|
+
</Stack>
|
|
38
|
+
</Paper>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const meta: Meta<typeof Component> = {
|
|
43
|
+
component: Component,
|
|
44
|
+
args: {
|
|
45
|
+
onFieldBlur: action('onFieldBlur'),
|
|
46
|
+
onFieldFocus: action('onFieldFocus'),
|
|
47
|
+
onFieldSubmit: action('onFieldSubmit'),
|
|
48
|
+
onFieldValueChange: action('onFieldValueChange'),
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default meta
|
|
53
|
+
|
|
54
|
+
type Story = StoryObj<typeof Component>
|
|
55
|
+
|
|
56
|
+
export const Empty: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
fields: {
|
|
59
|
+
$: {
|
|
60
|
+
disabled: false,
|
|
61
|
+
required: false,
|
|
62
|
+
value: [],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const Populated: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
fields: {
|
|
71
|
+
$: {
|
|
72
|
+
disabled: false,
|
|
73
|
+
required: false,
|
|
74
|
+
value: [
|
|
75
|
+
'$.4',
|
|
76
|
+
'$.6',
|
|
77
|
+
'$.19',
|
|
78
|
+
'$.0',
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { composeStories } from '@storybook/react'
|
|
2
|
+
import { toArray } from '@strictly/base'
|
|
3
|
+
import {
|
|
4
|
+
render,
|
|
5
|
+
} from '@testing-library/react'
|
|
6
|
+
import * as stories from './list_hooks.stories'
|
|
7
|
+
|
|
8
|
+
const composedStories = composeStories(stories)
|
|
9
|
+
|
|
10
|
+
describe('mantine list hooks', function () {
|
|
11
|
+
it.each(toArray(composedStories))('renders %s', function (_name, Story) {
|
|
12
|
+
const wrapper = render(<Story />)
|
|
13
|
+
expect(wrapper.container).toMatchSnapshot()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const RADIO_GROUP_LABEL = 'Radio Group'
|
|
2
|
+
export const RADIO_VALUES = [
|
|
3
|
+
'1',
|
|
4
|
+
'2',
|
|
5
|
+
'3',
|
|
6
|
+
] as const
|
|
7
|
+
export type RadioValue = typeof RADIO_VALUES[number]
|
|
8
|
+
export const RADIO_LABELS: Record<RadioValue, string> = {
|
|
9
|
+
1: 'One',
|
|
10
|
+
2: 'Two',
|
|
11
|
+
3: 'Three',
|
|
12
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Stack,
|
|
3
|
+
} from '@mantine/core'
|
|
4
|
+
import { action } from '@storybook/addon-actions'
|
|
5
|
+
import {
|
|
6
|
+
type Meta,
|
|
7
|
+
type StoryObj,
|
|
8
|
+
} from '@storybook/react'
|
|
9
|
+
import { type FormProps } from 'core/props'
|
|
10
|
+
import { useMantineForm } from 'mantine/hooks'
|
|
11
|
+
import { type Field } from 'types/field'
|
|
12
|
+
import {
|
|
13
|
+
RADIO_GROUP_LABEL,
|
|
14
|
+
RADIO_LABELS,
|
|
15
|
+
RADIO_VALUES,
|
|
16
|
+
type RadioValue,
|
|
17
|
+
} from './radio_group_constants'
|
|
18
|
+
|
|
19
|
+
function Component(props: FormProps<{
|
|
20
|
+
$: Field<RadioValue | null, string>,
|
|
21
|
+
}>) {
|
|
22
|
+
const form = useMantineForm(props)
|
|
23
|
+
const RadioGroupComponent = form.radioGroup('$')
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<RadioGroupComponent label={RADIO_GROUP_LABEL}>
|
|
27
|
+
<Stack>
|
|
28
|
+
{RADIO_VALUES.map(function (value: RadioValue) {
|
|
29
|
+
const label = RADIO_LABELS[value]
|
|
30
|
+
const RadioComponent = form.radio('$', value)
|
|
31
|
+
return (
|
|
32
|
+
<RadioComponent
|
|
33
|
+
key={label}
|
|
34
|
+
label={label}
|
|
35
|
+
/>
|
|
36
|
+
)
|
|
37
|
+
})}
|
|
38
|
+
</Stack>
|
|
39
|
+
</RadioGroupComponent>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const meta: Meta<typeof Component> = {
|
|
44
|
+
component: Component,
|
|
45
|
+
args: {
|
|
46
|
+
onFieldBlur: action('onFieldBlur'),
|
|
47
|
+
onFieldFocus: action('onFieldFocus'),
|
|
48
|
+
onFieldSubmit: action('onFieldSubmit'),
|
|
49
|
+
onFieldValueChange: action('onFieldValueChange'),
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default meta
|
|
54
|
+
|
|
55
|
+
type Story = StoryObj<typeof Component>
|
|
56
|
+
|
|
57
|
+
export const Empty: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
fields: {
|
|
60
|
+
$: {
|
|
61
|
+
disabled: false,
|
|
62
|
+
required: false,
|
|
63
|
+
value: null,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const Populated: Story = {
|
|
70
|
+
args: {
|
|
71
|
+
fields: {
|
|
72
|
+
$: {
|
|
73
|
+
disabled: false,
|
|
74
|
+
required: false,
|
|
75
|
+
value: '3',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const Required: Story = {
|
|
82
|
+
args: {
|
|
83
|
+
fields: {
|
|
84
|
+
$: {
|
|
85
|
+
disabled: false,
|
|
86
|
+
required: true,
|
|
87
|
+
value: '1',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const Disabled: Story = {
|
|
94
|
+
args: {
|
|
95
|
+
fields: {
|
|
96
|
+
$: {
|
|
97
|
+
disabled: true,
|
|
98
|
+
required: false,
|
|
99
|
+
value: '2',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { composeStories } from '@storybook/react'
|
|
2
|
+
import { toArray } from '@strictly/base'
|
|
3
|
+
import {
|
|
4
|
+
fireEvent,
|
|
5
|
+
render,
|
|
6
|
+
type RenderResult,
|
|
7
|
+
} from '@testing-library/react'
|
|
8
|
+
import {
|
|
9
|
+
type Mock,
|
|
10
|
+
vi,
|
|
11
|
+
} from 'vitest'
|
|
12
|
+
import {
|
|
13
|
+
RADIO_GROUP_LABEL,
|
|
14
|
+
RADIO_LABELS,
|
|
15
|
+
RADIO_VALUES,
|
|
16
|
+
type RadioValue,
|
|
17
|
+
} from './radio_group_constants'
|
|
18
|
+
import * as stories from './radio_group_hooks.stories'
|
|
19
|
+
|
|
20
|
+
const composedStories = composeStories(stories)
|
|
21
|
+
const {
|
|
22
|
+
Empty,
|
|
23
|
+
} = composedStories
|
|
24
|
+
|
|
25
|
+
describe('mantine radio group hooks', function () {
|
|
26
|
+
it.each(toArray(composedStories))('renders %s', function (_name, Story) {
|
|
27
|
+
const wrapper = render(<Story />)
|
|
28
|
+
expect(wrapper.container).toMatchSnapshot()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
describe('events', function () {
|
|
32
|
+
let onFieldValueChange: Mock<(path: '$', value: RadioValue) => void>
|
|
33
|
+
let onFieldFocus: Mock<(path: '$') => void>
|
|
34
|
+
let onFieldBlur: Mock<(path: '$') => void>
|
|
35
|
+
let wrapper: RenderResult
|
|
36
|
+
let radioGroup: HTMLElement
|
|
37
|
+
|
|
38
|
+
beforeEach(async function () {
|
|
39
|
+
onFieldValueChange = vi.fn()
|
|
40
|
+
onFieldFocus = vi.fn()
|
|
41
|
+
onFieldBlur = vi.fn()
|
|
42
|
+
wrapper = render((
|
|
43
|
+
<Empty
|
|
44
|
+
onFieldBlur={onFieldBlur}
|
|
45
|
+
onFieldFocus={onFieldFocus}
|
|
46
|
+
onFieldValueChange={onFieldValueChange}
|
|
47
|
+
/>
|
|
48
|
+
))
|
|
49
|
+
radioGroup = await wrapper.findByLabelText(RADIO_GROUP_LABEL)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe.each(RADIO_VALUES)('selects %s', function (value) {
|
|
53
|
+
let radio: HTMLElement
|
|
54
|
+
beforeEach(async function () {
|
|
55
|
+
const label = RADIO_LABELS[value]
|
|
56
|
+
radio = await wrapper.findByLabelText(label)
|
|
57
|
+
fireEvent.click(radio)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('fires onFieldValueChange', function () {
|
|
61
|
+
expect(onFieldValueChange).toHaveBeenCalledOnce()
|
|
62
|
+
expect(onFieldValueChange).toHaveBeenCalledWith('$', value)
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('focus', function () {
|
|
67
|
+
beforeEach(function () {
|
|
68
|
+
fireEvent.focus(radioGroup)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('fires focus event', function () {
|
|
72
|
+
expect(onFieldFocus).toHaveBeenCalledOnce()
|
|
73
|
+
expect(onFieldFocus).toHaveBeenCalledWith('$')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe('blur', function () {
|
|
77
|
+
beforeEach(function () {
|
|
78
|
+
fireEvent.blur(radioGroup)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('fires blur event', function () {
|
|
82
|
+
expect(onFieldBlur).toHaveBeenCalledOnce()
|
|
83
|
+
expect(onFieldBlur).toHaveBeenCalledWith('$')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('does not refire focus event', function () {
|
|
87
|
+
expect(onFieldFocus).toHaveBeenCalledOnce()
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
92
|
+
})
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { action } from '@storybook/addon-actions'
|
|
2
|
+
import {
|
|
3
|
+
type Meta,
|
|
4
|
+
type StoryObj,
|
|
5
|
+
} from '@storybook/react'
|
|
6
|
+
import { type FormProps } from 'core/props'
|
|
7
|
+
import { useMantineForm } from 'mantine/hooks'
|
|
8
|
+
import { type Field } from 'types/field'
|
|
9
|
+
import { SELECT_LABEL } from './select_hooks_constant'
|
|
10
|
+
|
|
11
|
+
function Component(props: FormProps<{
|
|
12
|
+
$: Field<string | null, string>,
|
|
13
|
+
}>) {
|
|
14
|
+
const form = useMantineForm(props)
|
|
15
|
+
const SelectComponent = form.select('$')
|
|
16
|
+
return (
|
|
17
|
+
<SelectComponent
|
|
18
|
+
data={[
|
|
19
|
+
'a',
|
|
20
|
+
'b',
|
|
21
|
+
'c',
|
|
22
|
+
]}
|
|
23
|
+
label={SELECT_LABEL}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const meta: Meta<typeof Component> = {
|
|
29
|
+
component: Component,
|
|
30
|
+
args: {
|
|
31
|
+
onFieldBlur: action('onFieldBlur'),
|
|
32
|
+
onFieldFocus: action('onFieldFocus'),
|
|
33
|
+
onFieldSubmit: action('onFieldSubmit'),
|
|
34
|
+
onFieldValueChange: action('onFieldValueChange'),
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default meta
|
|
39
|
+
|
|
40
|
+
type Story = StoryObj<typeof Component>
|
|
41
|
+
|
|
42
|
+
export const EmptySelect: Story = {
|
|
43
|
+
args: {
|
|
44
|
+
fields: {
|
|
45
|
+
$: {
|
|
46
|
+
disabled: false,
|
|
47
|
+
required: true,
|
|
48
|
+
value: '',
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const PopulatedSelect: Story = {
|
|
55
|
+
args: {
|
|
56
|
+
fields: {
|
|
57
|
+
$: {
|
|
58
|
+
disabled: false,
|
|
59
|
+
required: true,
|
|
60
|
+
value: 'a',
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const InvalidSelect: Story = {
|
|
67
|
+
args: {
|
|
68
|
+
fields: {
|
|
69
|
+
$: {
|
|
70
|
+
disabled: false,
|
|
71
|
+
required: true,
|
|
72
|
+
value: 'd',
|
|
73
|
+
error: 'invalid option',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { composeStories } from '@storybook/react'
|
|
2
|
+
import { toArray } from '@strictly/base'
|
|
3
|
+
import {
|
|
4
|
+
render,
|
|
5
|
+
} from '@testing-library/react'
|
|
6
|
+
import * as stories from './select_hooks.stories'
|
|
7
|
+
|
|
8
|
+
const composedStories = composeStories(stories)
|
|
9
|
+
describe('mantine select hooks', function () {
|
|
10
|
+
it.each(toArray(composedStories))('renders %s', function (_name, Story) {
|
|
11
|
+
const wrapper = render(<Story />)
|
|
12
|
+
expect(wrapper.container).toMatchSnapshot()
|
|
13
|
+
})
|
|
14
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SELECT_LABEL = 'Select'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const TEXT_INPUT_LABEL = 'Text Input'
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PillsInputField,
|
|
3
|
+
Textarea,
|
|
4
|
+
type TextInputProps,
|
|
5
|
+
} from '@mantine/core'
|
|
6
|
+
import { action } from '@storybook/addon-actions'
|
|
7
|
+
import {
|
|
8
|
+
type Meta,
|
|
9
|
+
type StoryObj,
|
|
10
|
+
} from '@storybook/react'
|
|
11
|
+
import { type FormProps } from 'core/props'
|
|
12
|
+
import {
|
|
13
|
+
type SuppliedTextInputProps,
|
|
14
|
+
type TextInputTarget,
|
|
15
|
+
} from 'mantine/create_text_input'
|
|
16
|
+
import { useMantineForm } from 'mantine/hooks'
|
|
17
|
+
import { type ComponentType } from 'react'
|
|
18
|
+
import { type Field } from 'types/field'
|
|
19
|
+
import { TEXT_INPUT_LABEL } from './text_input_constants'
|
|
20
|
+
|
|
21
|
+
type StoryTextInputProps<T extends TextInputTarget> = SuppliedTextInputProps<T> & Pick<TextInputProps, 'label'>
|
|
22
|
+
|
|
23
|
+
function Component<T extends TextInputTarget>({
|
|
24
|
+
TextInput,
|
|
25
|
+
...props
|
|
26
|
+
}: FormProps<{
|
|
27
|
+
$: Field<string, string>,
|
|
28
|
+
}> & {
|
|
29
|
+
TextInput?: ComponentType<StoryTextInputProps<T>>,
|
|
30
|
+
}) {
|
|
31
|
+
const form = useMantineForm(props)
|
|
32
|
+
const TextInputComponent = form.textInput<'$', StoryTextInputProps<T>>('$', TextInput)
|
|
33
|
+
return <TextInputComponent label={TEXT_INPUT_LABEL} />
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const meta: Meta<typeof Component> = {
|
|
37
|
+
component: Component,
|
|
38
|
+
args: {
|
|
39
|
+
onFieldBlur: action('onFieldBlur'),
|
|
40
|
+
onFieldFocus: action('onFieldFocus'),
|
|
41
|
+
onFieldSubmit: action('onFieldSubmit'),
|
|
42
|
+
onFieldValueChange: action('onFieldValueChange'),
|
|
43
|
+
},
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default meta
|
|
47
|
+
|
|
48
|
+
type Story<
|
|
49
|
+
T extends TextInputTarget = HTMLInputElement,
|
|
50
|
+
> = StoryObj<typeof Component<T>>
|
|
51
|
+
|
|
52
|
+
export const Empty: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
fields: {
|
|
55
|
+
$: {
|
|
56
|
+
disabled: false,
|
|
57
|
+
required: false,
|
|
58
|
+
value: '',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const Populated: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
fields: {
|
|
67
|
+
$: {
|
|
68
|
+
disabled: false,
|
|
69
|
+
required: false,
|
|
70
|
+
value: 'Hello',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const Required: Story = {
|
|
77
|
+
args: {
|
|
78
|
+
fields: {
|
|
79
|
+
$: {
|
|
80
|
+
disabled: false,
|
|
81
|
+
required: true,
|
|
82
|
+
value: 'xxx',
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const Disabled: Story = {
|
|
89
|
+
args: {
|
|
90
|
+
fields: {
|
|
91
|
+
$: {
|
|
92
|
+
disabled: true,
|
|
93
|
+
required: false,
|
|
94
|
+
value: 'xxx',
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export const OverriddenTextarea: Story<HTMLTextAreaElement> = {
|
|
101
|
+
args: {
|
|
102
|
+
fields: {
|
|
103
|
+
$: {
|
|
104
|
+
disabled: false,
|
|
105
|
+
required: false,
|
|
106
|
+
value: 'Textarea',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
TextInput: Textarea,
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const OverriddenPillsInputField: Story = {
|
|
114
|
+
args: {
|
|
115
|
+
fields: {
|
|
116
|
+
$: {
|
|
117
|
+
disabled: false,
|
|
118
|
+
required: false,
|
|
119
|
+
value: 'PillsInputField',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
TextInput: PillsInputField,
|
|
123
|
+
},
|
|
124
|
+
}
|