@strictly/react-form 0.0.7 → 0.0.8
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/.out/core/mobx/hooks.d.ts +5 -1
- package/.out/core/mobx/hooks.js +13 -3
- package/.out/core/mobx/specs/sub_form_field_adapters.tests.js +56 -9
- package/.out/core/mobx/sub_form_field_adapters.d.ts +5 -5
- package/.out/core/mobx/sub_form_field_adapters.js +13 -10
- package/.out/field_converters/nullable_to_boolean_converter.d.ts +2 -2
- package/.out/mantine/create_checkbox.js +1 -0
- package/.out/mantine/create_fields_view.d.ts +1 -1
- package/.out/mantine/create_fields_view.js +4 -4
- package/.out/mantine/create_form.d.ts +1 -1
- package/.out/mantine/create_list.d.ts +1 -1
- package/.out/mantine/create_pill.d.ts +1 -1
- package/.out/mantine/create_radio.d.ts +1 -1
- package/.out/mantine/create_radio_group.js +1 -0
- package/.out/mantine/create_text_input.js +7 -2
- package/.out/mantine/create_value_input.js +1 -0
- package/.out/mantine/error_renderer.d.ts +1 -1
- package/.out/mantine/error_renderer.js +1 -1
- package/.out/mantine/hooks.d.ts +9 -9
- package/.out/mantine/specs/checkbox_hooks.stories.d.ts +2 -6
- package/.out/mantine/specs/checkbox_hooks.stories.js +4 -16
- package/.out/mantine/specs/fields_view_hooks.stories.d.ts +1 -1
- package/.out/mantine/specs/fields_view_hooks.stories.js +6 -3
- package/.out/mantine/specs/form_hooks.stories.d.ts +2 -2
- package/.out/mantine/specs/form_hooks.stories.js +4 -1
- package/.out/mantine/specs/radio_group_hooks.stories.d.ts +2 -6
- package/.out/mantine/specs/radio_group_hooks.stories.js +5 -17
- package/.out/mantine/specs/select_hooks.stories.d.ts +2 -6
- package/.out/mantine/specs/select_hooks.stories.js +4 -16
- package/.out/mantine/specs/text_input_hooks.stories.d.ts +2 -5
- package/.out/mantine/specs/text_input_hooks.stories.js +5 -5
- package/.out/mantine/specs/value_input_hooks.stories.d.ts +2 -5
- package/.out/mantine/specs/value_input_hooks.stories.js +5 -5
- package/.out/mantine/types.d.ts +4 -2
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.turbo/turbo-build.log +8 -8
- package/.turbo/turbo-check-types.log +1 -1
- package/.turbo/turbo-release$colon$exports.log +1 -1
- package/core/mobx/hooks.ts +24 -6
- package/core/mobx/specs/sub_form_field_adapters.tests.ts +108 -15
- package/core/mobx/sub_form_field_adapters.ts +41 -25
- package/dist/index.cjs +52 -27
- package/dist/index.d.cts +25 -19
- package/dist/index.d.ts +25 -19
- package/dist/index.js +52 -27
- package/field_converters/nullable_to_boolean_converter.ts +2 -3
- package/mantine/create_checkbox.tsx +2 -1
- package/mantine/create_fields_view.tsx +17 -14
- package/mantine/create_form.tsx +2 -2
- package/mantine/create_list.tsx +1 -1
- package/mantine/create_pill.tsx +1 -1
- package/mantine/create_radio.tsx +1 -1
- package/mantine/create_radio_group.tsx +6 -2
- package/mantine/create_text_input.tsx +9 -3
- package/mantine/create_value_input.tsx +2 -1
- package/mantine/error_renderer.ts +1 -1
- package/mantine/hooks.tsx +19 -14
- package/mantine/specs/__snapshots__/checkbox_hooks.tests.tsx.snap +1 -64
- package/mantine/specs/__snapshots__/fields_view_hooks.tests.tsx.snap +52 -52
- package/mantine/specs/__snapshots__/radio_group_hooks.tests.tsx.snap +1 -179
- package/mantine/specs/__snapshots__/select_hooks.tests.tsx.snap +1 -83
- package/mantine/specs/__snapshots__/text_input_hooks.tests.tsx.snap +27 -27
- package/mantine/specs/__snapshots__/value_input_hooks.tests.tsx.snap +31 -31
- package/mantine/specs/checkbox_hooks.stories.tsx +5 -21
- package/mantine/specs/fields_view_hooks.stories.tsx +16 -4
- package/mantine/specs/form_hooks.stories.tsx +10 -3
- package/mantine/specs/radio_group_hooks.stories.tsx +6 -20
- package/mantine/specs/select_hooks.stories.tsx +5 -21
- package/mantine/specs/text_input_hooks.stories.tsx +5 -8
- package/mantine/specs/value_input_hooks.stories.tsx +5 -8
- package/mantine/types.ts +7 -3
- package/package.json +2 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -7,12 +7,12 @@ $ tsup
|
|
|
7
7
|
[34mCLI[39m Target: esnext
|
|
8
8
|
[34mCJS[39m Build start
|
|
9
9
|
[34mESM[39m Build start
|
|
10
|
-
[32mCJS[39m [1mdist/index.cjs [22m[32m50.
|
|
11
|
-
[32mCJS[39m ⚡️ Build success in
|
|
12
|
-
[32mESM[39m [1mdist/index.js [22m[32m46.
|
|
13
|
-
[32mESM[39m ⚡️ Build success in
|
|
10
|
+
[32mCJS[39m [1mdist/index.cjs [22m[32m50.73 KB[39m
|
|
11
|
+
[32mCJS[39m ⚡️ Build success in 112ms
|
|
12
|
+
[32mESM[39m [1mdist/index.js [22m[32m46.84 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 113ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
-
[32mDTS[39m [1mdist/index.d.cts [22m[32m36.
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m36.
|
|
18
|
-
Done in 10.
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 9662ms
|
|
16
|
+
[32mDTS[39m [1mdist/index.d.cts [22m[32m36.94 KB[39m
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m36.94 KB[39m
|
|
18
|
+
Done in 10.73s.
|
package/core/mobx/hooks.ts
CHANGED
|
@@ -25,12 +25,16 @@ type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<
|
|
|
25
25
|
export function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(
|
|
26
26
|
presenter: P,
|
|
27
27
|
value: ValueOfPresenter<P>,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
{
|
|
29
|
+
onValidFieldSubmit,
|
|
30
|
+
onValidFormSubmit,
|
|
31
|
+
}: {
|
|
32
|
+
onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void,
|
|
33
|
+
onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void,
|
|
34
|
+
},
|
|
32
35
|
): {
|
|
33
36
|
model: ModelOfPresenter<P>,
|
|
37
|
+
onFormSubmit?: (value: ValueOfPresenter<P>) => void,
|
|
34
38
|
} & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'> {
|
|
35
39
|
const model = useMemo(function () {
|
|
36
40
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
@@ -57,14 +61,14 @@ export function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, a
|
|
|
57
61
|
const onFieldSubmit = useCallback(
|
|
58
62
|
function<Path extends ValuePathsOfPresenter<P>> (valuePath: Path) {
|
|
59
63
|
if (presenter.validateField(model, valuePath)) {
|
|
60
|
-
|
|
64
|
+
onValidFieldSubmit?.(model, valuePath)
|
|
61
65
|
}
|
|
62
66
|
return false
|
|
63
67
|
},
|
|
64
68
|
[
|
|
65
69
|
presenter,
|
|
66
70
|
model,
|
|
67
|
-
|
|
71
|
+
onValidFieldSubmit,
|
|
68
72
|
],
|
|
69
73
|
)
|
|
70
74
|
|
|
@@ -85,10 +89,24 @@ export function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, a
|
|
|
85
89
|
],
|
|
86
90
|
)
|
|
87
91
|
|
|
92
|
+
const onFormSubmit = useCallback(
|
|
93
|
+
function () {
|
|
94
|
+
if (presenter.validateAll(model)) {
|
|
95
|
+
onValidFormSubmit?.(model, model.value)
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
[
|
|
99
|
+
presenter,
|
|
100
|
+
model,
|
|
101
|
+
onValidFormSubmit,
|
|
102
|
+
],
|
|
103
|
+
)
|
|
104
|
+
|
|
88
105
|
return {
|
|
89
106
|
model,
|
|
90
107
|
onFieldValueChange,
|
|
91
108
|
onFieldSubmit,
|
|
92
109
|
onFieldBlur,
|
|
110
|
+
onFormSubmit,
|
|
93
111
|
}
|
|
94
112
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
list,
|
|
2
3
|
numberType,
|
|
3
4
|
object,
|
|
4
5
|
stringType,
|
|
@@ -8,16 +9,18 @@ import {
|
|
|
8
9
|
subFormFieldAdapters,
|
|
9
10
|
} from 'core/mobx/sub_form_field_adapters'
|
|
10
11
|
import { UnreliableFieldConversionType } from 'types/field_converters'
|
|
11
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
mockDeep,
|
|
14
|
+
mockReset,
|
|
15
|
+
} from 'vitest-mock-extended'
|
|
12
16
|
|
|
13
17
|
describe('subFormFieldAdapters', () => {
|
|
14
|
-
const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean>>>()
|
|
15
|
-
const fieldAdapter1: FieldAdapter<string, boolean> = mockedFieldAdapter1
|
|
16
|
-
const mockedFieldAdapter2 = mockDeep<FieldAdapter<number, boolean>>()
|
|
17
|
-
const fieldAdapter2: FieldAdapter<number, boolean> = mockedFieldAdapter2
|
|
18
|
-
|
|
19
18
|
describe('empty value', () => {
|
|
20
|
-
const adapters = subFormFieldAdapters(
|
|
19
|
+
const adapters = subFormFieldAdapters(
|
|
20
|
+
{},
|
|
21
|
+
'$.a',
|
|
22
|
+
stringType,
|
|
23
|
+
)
|
|
21
24
|
|
|
22
25
|
it('equals expected type', () => {
|
|
23
26
|
expectTypeOf(adapters).toEqualTypeOf<{}>()
|
|
@@ -29,15 +32,35 @@ describe('subFormFieldAdapters', () => {
|
|
|
29
32
|
})
|
|
30
33
|
|
|
31
34
|
describe('single adapter', () => {
|
|
35
|
+
const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean, number, '$', string>>>()
|
|
36
|
+
const fieldAdapter1: FieldAdapter<string, boolean, number, '$', string> = mockedFieldAdapter1
|
|
37
|
+
|
|
32
38
|
const type = object().field('a', stringType)
|
|
33
|
-
const
|
|
39
|
+
const subAdapters = {
|
|
34
40
|
$: fieldAdapter1,
|
|
35
|
-
}
|
|
41
|
+
} as const
|
|
42
|
+
const adapters = subFormFieldAdapters<
|
|
43
|
+
typeof subAdapters,
|
|
44
|
+
'$.a',
|
|
45
|
+
{ '$.a': '$.a' },
|
|
46
|
+
typeof type
|
|
47
|
+
>(
|
|
48
|
+
subAdapters,
|
|
49
|
+
'$.a',
|
|
50
|
+
type,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
mockReset(mockedFieldAdapter1)
|
|
55
|
+
})
|
|
36
56
|
|
|
37
57
|
it('equals expected type', () => {
|
|
38
|
-
// TODO toEqualTypeOf (seems to be a TS
|
|
58
|
+
// TODO toEqualTypeOf (cannot reason about revert optionality, seems to be a TS issue as they
|
|
59
|
+
// are both optional AFAICT)
|
|
39
60
|
expectTypeOf(adapters).toMatchTypeOf<{
|
|
40
|
-
'$.a': FieldAdapter<string, boolean
|
|
61
|
+
'$.a': FieldAdapter<string, boolean, number, '$.a', {
|
|
62
|
+
a: string,
|
|
63
|
+
}>,
|
|
41
64
|
}>()
|
|
42
65
|
})
|
|
43
66
|
|
|
@@ -81,12 +104,26 @@ describe('subFormFieldAdapters', () => {
|
|
|
81
104
|
})
|
|
82
105
|
|
|
83
106
|
describe('multiple adapters', () => {
|
|
107
|
+
const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean>>>()
|
|
108
|
+
const fieldAdapter1: FieldAdapter<string, boolean, number> = mockedFieldAdapter1
|
|
109
|
+
const mockedFieldAdapter2 = mockDeep<FieldAdapter<number, boolean>>()
|
|
110
|
+
const fieldAdapter2: FieldAdapter<number, boolean> = mockedFieldAdapter2
|
|
111
|
+
|
|
84
112
|
const type = object()
|
|
85
113
|
.field('a', object().field('x', stringType).field('y', numberType))
|
|
86
|
-
const adapters = subFormFieldAdapters(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
114
|
+
const adapters = subFormFieldAdapters(
|
|
115
|
+
{
|
|
116
|
+
'$.x': fieldAdapter1,
|
|
117
|
+
'$.y': fieldAdapter2,
|
|
118
|
+
},
|
|
119
|
+
'$.a',
|
|
120
|
+
type,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
mockReset(mockedFieldAdapter1)
|
|
125
|
+
mockReset(mockedFieldAdapter2)
|
|
126
|
+
})
|
|
90
127
|
|
|
91
128
|
it('equals expected type', () => {
|
|
92
129
|
// TODO toEqualTypeOf (seems to be a TS error)
|
|
@@ -139,4 +176,60 @@ describe('subFormFieldAdapters', () => {
|
|
|
139
176
|
})
|
|
140
177
|
})
|
|
141
178
|
})
|
|
179
|
+
|
|
180
|
+
describe('list adapter', () => {
|
|
181
|
+
const mockedFieldAdapter1 = mockDeep<Required<FieldAdapter<string, boolean, number, '$', string>>>()
|
|
182
|
+
const fieldAdapter1: FieldAdapter<string, boolean, number, '$', string> = mockedFieldAdapter1
|
|
183
|
+
const type = list(stringType)
|
|
184
|
+
const subAdapters = {
|
|
185
|
+
$: fieldAdapter1,
|
|
186
|
+
}
|
|
187
|
+
const adapters = subFormFieldAdapters<
|
|
188
|
+
typeof subAdapters,
|
|
189
|
+
'$.*',
|
|
190
|
+
{
|
|
191
|
+
'$.*': `$.${number}`,
|
|
192
|
+
},
|
|
193
|
+
typeof type
|
|
194
|
+
>(
|
|
195
|
+
subAdapters,
|
|
196
|
+
'$.*',
|
|
197
|
+
type,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
beforeEach(() => {
|
|
201
|
+
mockReset(mockedFieldAdapter1)
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('equals expected type', () => {
|
|
205
|
+
// TODO toEqualTypeOf (seems to be a TS error)
|
|
206
|
+
expectTypeOf(adapters).toMatchTypeOf<{
|
|
207
|
+
'$.*': FieldAdapter<string, boolean, number, `$.${number}`, string[]>,
|
|
208
|
+
}>()
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('equals expected value', () => {
|
|
212
|
+
expect(adapters).toEqual({
|
|
213
|
+
'$.*': expect.anything(),
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
describe('calls convert with correct paths and values', () => {
|
|
218
|
+
const subContext = 'a'
|
|
219
|
+
const context = [subContext]
|
|
220
|
+
|
|
221
|
+
it('calls $.*', () => {
|
|
222
|
+
const mockedReturnedValue = {
|
|
223
|
+
value: false,
|
|
224
|
+
readonly: false,
|
|
225
|
+
required: false,
|
|
226
|
+
}
|
|
227
|
+
mockedFieldAdapter1.convert.mockReturnValue(mockedReturnedValue)
|
|
228
|
+
|
|
229
|
+
const returnedValue = adapters['$.*'].convert('b', '$.0', context)
|
|
230
|
+
expect(fieldAdapter1.convert).toHaveBeenCalledWith('b', '$', subContext)
|
|
231
|
+
expect(returnedValue).toEqual(mockedReturnedValue)
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
})
|
|
142
235
|
})
|
|
@@ -9,35 +9,51 @@ import {
|
|
|
9
9
|
type FieldAdapter,
|
|
10
10
|
type FromOfFieldAdapter,
|
|
11
11
|
type ToOfFieldAdapter,
|
|
12
|
+
type ValuePathOfFieldAdapter,
|
|
12
13
|
} from './field_adapter'
|
|
13
14
|
|
|
14
|
-
type SubFormFieldAdapter<F extends FieldAdapter,
|
|
15
|
+
type SubFormFieldAdapter<F extends FieldAdapter, ValuePath extends string, Context> = FieldAdapter<
|
|
15
16
|
FromOfFieldAdapter<F>,
|
|
16
17
|
ToOfFieldAdapter<F>,
|
|
17
18
|
ErrorOfFieldAdapter<F>,
|
|
18
|
-
|
|
19
|
+
ValuePathOfFieldAdapter<F> extends StringConcatOf<'$', infer ValuePathSuffix> ? `${ValuePath}${ValuePathSuffix}`
|
|
20
|
+
// assume string (they don't care about the value path as a type) if there the path doesn't have a $ prefix
|
|
21
|
+
: string,
|
|
19
22
|
Context
|
|
20
23
|
>
|
|
21
24
|
|
|
22
|
-
type SubFormFieldAdapters<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
type SubFormFieldAdapters<
|
|
26
|
+
SubAdapters extends Record<string, FieldAdapter>,
|
|
27
|
+
TypePath extends string,
|
|
28
|
+
ValuePath extends string,
|
|
29
|
+
Context,
|
|
30
|
+
> = {
|
|
31
|
+
[
|
|
32
|
+
K in keyof SubAdapters as K extends StringConcatOf<'$', infer TypePathSuffix> ? `${TypePath}${TypePathSuffix}`
|
|
33
|
+
: never
|
|
34
|
+
]: SubFormFieldAdapter<
|
|
35
|
+
SubAdapters[K],
|
|
36
|
+
ValuePath,
|
|
37
|
+
Context
|
|
38
|
+
>
|
|
30
39
|
}
|
|
31
40
|
|
|
32
|
-
export function subFormFieldAdapters<
|
|
33
|
-
|
|
41
|
+
export function subFormFieldAdapters<
|
|
42
|
+
SubAdapters extends Record<string, FieldAdapter>,
|
|
43
|
+
TypePath extends string,
|
|
44
|
+
TypePathsToValuePaths extends Record<TypePath, string>,
|
|
45
|
+
ContextType extends Type,
|
|
46
|
+
>(
|
|
34
47
|
subAdapters: SubAdapters,
|
|
35
|
-
|
|
48
|
+
parentTypePath: TypePath,
|
|
36
49
|
contextType: ContextType,
|
|
37
|
-
): SubFormFieldAdapters<SubAdapters,
|
|
50
|
+
): SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath], ValueOfType<ContextType>> {
|
|
51
|
+
// assume the number of '.' in the type path will correspond to the number of '.' in the value path
|
|
52
|
+
const dotCount = parentTypePath.split('.').length
|
|
38
53
|
function getSubValuePathAndContext(valuePath: string, context: ValueOfType<ContextType>) {
|
|
39
|
-
const
|
|
40
|
-
const
|
|
54
|
+
const parentValuePath = valuePath.split('.').slice(0, dotCount).join('.')
|
|
55
|
+
const subValuePath = valuePath.replace(parentValuePath, '$')
|
|
56
|
+
const subContext = flattenValuesOfType(contextType, context)[parentValuePath]
|
|
41
57
|
return [
|
|
42
58
|
subValuePath,
|
|
43
59
|
subContext,
|
|
@@ -46,23 +62,23 @@ export function subFormFieldAdapters<SubAdapters extends Record<string, FieldAda
|
|
|
46
62
|
|
|
47
63
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
48
64
|
return Object.entries(subAdapters).reduce<Record<string, FieldAdapter>>((acc, [
|
|
49
|
-
|
|
50
|
-
|
|
65
|
+
subTypePath,
|
|
66
|
+
subAdapter,
|
|
51
67
|
]) => {
|
|
52
|
-
const
|
|
68
|
+
const typePath = subTypePath.replace('$', parentTypePath)
|
|
53
69
|
// adapt field adapter with new path and context
|
|
54
70
|
const adaptedAdapter: FieldAdapter = {
|
|
55
71
|
convert: (from, valuePath, context) => {
|
|
56
|
-
return
|
|
72
|
+
return subAdapter.convert(from, ...getSubValuePathAndContext(valuePath, context))
|
|
57
73
|
},
|
|
58
74
|
create: (valuePath, context) => {
|
|
59
|
-
return
|
|
75
|
+
return subAdapter.create(...getSubValuePathAndContext(valuePath, context))
|
|
60
76
|
},
|
|
61
|
-
revert:
|
|
62
|
-
return
|
|
77
|
+
revert: subAdapter.revert && ((from, valuePath, context) => {
|
|
78
|
+
return subAdapter.revert!(from, ...getSubValuePathAndContext(valuePath, context))
|
|
63
79
|
}),
|
|
64
80
|
}
|
|
65
|
-
acc[
|
|
81
|
+
acc[typePath] = adaptedAdapter
|
|
66
82
|
return acc
|
|
67
|
-
}, {}) as SubFormFieldAdapters<SubAdapters,
|
|
83
|
+
}, {}) as SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath], ValueOfType<ContextType>>
|
|
68
84
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -690,7 +690,10 @@ var FormModel = class {
|
|
|
690
690
|
|
|
691
691
|
// core/mobx/hooks.ts
|
|
692
692
|
var import_react = require("react");
|
|
693
|
-
function useDefaultMobxFormHooks(presenter, value,
|
|
693
|
+
function useDefaultMobxFormHooks(presenter, value, {
|
|
694
|
+
onValidFieldSubmit,
|
|
695
|
+
onValidFormSubmit
|
|
696
|
+
}) {
|
|
694
697
|
const model = (0, import_react.useMemo)(function() {
|
|
695
698
|
return presenter.createModel(value);
|
|
696
699
|
}, [
|
|
@@ -710,14 +713,14 @@ function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
|
|
|
710
713
|
const onFieldSubmit = (0, import_react.useCallback)(
|
|
711
714
|
function(valuePath) {
|
|
712
715
|
if (presenter.validateField(model, valuePath)) {
|
|
713
|
-
|
|
716
|
+
onValidFieldSubmit?.(model, valuePath);
|
|
714
717
|
}
|
|
715
718
|
return false;
|
|
716
719
|
},
|
|
717
720
|
[
|
|
718
721
|
presenter,
|
|
719
722
|
model,
|
|
720
|
-
|
|
723
|
+
onValidFieldSubmit
|
|
721
724
|
]
|
|
722
725
|
);
|
|
723
726
|
const onFieldBlur = (0, import_react.useCallback)(
|
|
@@ -733,11 +736,24 @@ function useDefaultMobxFormHooks(presenter, value, onValidSubmit) {
|
|
|
733
736
|
model
|
|
734
737
|
]
|
|
735
738
|
);
|
|
739
|
+
const onFormSubmit = (0, import_react.useCallback)(
|
|
740
|
+
function() {
|
|
741
|
+
if (presenter.validateAll(model)) {
|
|
742
|
+
onValidFormSubmit?.(model, model.value);
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
[
|
|
746
|
+
presenter,
|
|
747
|
+
model,
|
|
748
|
+
onValidFormSubmit
|
|
749
|
+
]
|
|
750
|
+
);
|
|
736
751
|
return {
|
|
737
752
|
model,
|
|
738
753
|
onFieldValueChange,
|
|
739
754
|
onFieldSubmit,
|
|
740
|
-
onFieldBlur
|
|
755
|
+
onFieldBlur,
|
|
756
|
+
onFormSubmit
|
|
741
757
|
};
|
|
742
758
|
}
|
|
743
759
|
|
|
@@ -818,32 +834,34 @@ function mergeAdaptersWithValidators(adapters, validators) {
|
|
|
818
834
|
|
|
819
835
|
// core/mobx/sub_form_field_adapters.ts
|
|
820
836
|
var import_define3 = require("@strictly/define");
|
|
821
|
-
function subFormFieldAdapters(subAdapters,
|
|
837
|
+
function subFormFieldAdapters(subAdapters, parentTypePath, contextType) {
|
|
838
|
+
const dotCount = parentTypePath.split(".").length;
|
|
822
839
|
function getSubValuePathAndContext(valuePath, context) {
|
|
823
|
-
const
|
|
824
|
-
const
|
|
840
|
+
const parentValuePath = valuePath.split(".").slice(0, dotCount).join(".");
|
|
841
|
+
const subValuePath = valuePath.replace(parentValuePath, "$");
|
|
842
|
+
const subContext = (0, import_define3.flattenValuesOfType)(contextType, context)[parentValuePath];
|
|
825
843
|
return [
|
|
826
844
|
subValuePath,
|
|
827
845
|
subContext
|
|
828
846
|
];
|
|
829
847
|
}
|
|
830
848
|
return Object.entries(subAdapters).reduce((acc, [
|
|
831
|
-
|
|
832
|
-
|
|
849
|
+
subTypePath,
|
|
850
|
+
subAdapter
|
|
833
851
|
]) => {
|
|
834
|
-
const
|
|
852
|
+
const typePath = subTypePath.replace("$", parentTypePath);
|
|
835
853
|
const adaptedAdapter = {
|
|
836
854
|
convert: (from, valuePath, context) => {
|
|
837
|
-
return
|
|
855
|
+
return subAdapter.convert(from, ...getSubValuePathAndContext(valuePath, context));
|
|
838
856
|
},
|
|
839
857
|
create: (valuePath, context) => {
|
|
840
|
-
return
|
|
858
|
+
return subAdapter.create(...getSubValuePathAndContext(valuePath, context));
|
|
841
859
|
},
|
|
842
|
-
revert:
|
|
843
|
-
return
|
|
860
|
+
revert: subAdapter.revert && ((from, valuePath, context) => {
|
|
861
|
+
return subAdapter.revert(from, ...getSubValuePathAndContext(valuePath, context));
|
|
844
862
|
})
|
|
845
863
|
};
|
|
846
|
-
acc[
|
|
864
|
+
acc[typePath] = adaptedAdapter;
|
|
847
865
|
return acc;
|
|
848
866
|
}, {});
|
|
849
867
|
}
|
|
@@ -1057,7 +1075,7 @@ function DefaultErrorRenderer({
|
|
|
1057
1075
|
error
|
|
1058
1076
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1059
1077
|
}) {
|
|
1060
|
-
return error;
|
|
1078
|
+
return JSON.stringify(error);
|
|
1061
1079
|
}
|
|
1062
1080
|
|
|
1063
1081
|
// mantine/hooks.tsx
|
|
@@ -1288,15 +1306,19 @@ function createFieldsView(valuePath, FieldsView, observableProps) {
|
|
|
1288
1306
|
observableProps.onFieldSubmit?.(toKey(subKey));
|
|
1289
1307
|
}
|
|
1290
1308
|
return (0, import_mobx_react2.observer)(function(props) {
|
|
1291
|
-
const subFields = Object.entries(observableProps.fields).reduce(
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1309
|
+
const subFields = Object.entries(observableProps.fields).reduce(
|
|
1310
|
+
(acc, [
|
|
1311
|
+
fieldKey,
|
|
1312
|
+
fieldValue
|
|
1313
|
+
]) => {
|
|
1314
|
+
if (fieldKey.startsWith(valuePath)) {
|
|
1315
|
+
acc[toSubKey(fieldKey)] = fieldValue;
|
|
1316
|
+
}
|
|
1317
|
+
return acc;
|
|
1318
|
+
},
|
|
1319
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
1320
|
+
{}
|
|
1321
|
+
);
|
|
1300
1322
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1301
1323
|
FieldsView,
|
|
1302
1324
|
{
|
|
@@ -1452,13 +1474,16 @@ function createTextInput(valuePath, TextInput) {
|
|
|
1452
1474
|
const propSource = ({
|
|
1453
1475
|
ErrorRenderer = DefaultErrorRenderer
|
|
1454
1476
|
}) => {
|
|
1477
|
+
const field = this.fields[valuePath];
|
|
1478
|
+
if (field == null) {
|
|
1479
|
+
throw new Error(`invalid field ${valuePath}`);
|
|
1480
|
+
}
|
|
1455
1481
|
const {
|
|
1456
1482
|
readonly,
|
|
1457
1483
|
required,
|
|
1458
1484
|
value,
|
|
1459
1485
|
error
|
|
1460
|
-
|
|
1461
|
-
} = this.fields[valuePath];
|
|
1486
|
+
} = field;
|
|
1462
1487
|
return {
|
|
1463
1488
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
1464
1489
|
name: valuePath,
|
package/dist/index.d.cts
CHANGED
|
@@ -181,8 +181,12 @@ type FormFieldsOfPresenter<Presenter extends FormPresenter<any, any, any, any>>
|
|
|
181
181
|
|
|
182
182
|
type ValueOfPresenter<P extends FormPresenter<any, any, any, any>> = P extends FormPresenter<infer T, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
|
|
183
183
|
type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<P['createModel']>;
|
|
184
|
-
declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>,
|
|
184
|
+
declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>, { onValidFieldSubmit, onValidFormSubmit, }: {
|
|
185
|
+
onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void;
|
|
186
|
+
onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void;
|
|
187
|
+
}): {
|
|
185
188
|
model: ModelOfPresenter<P>;
|
|
189
|
+
onFormSubmit?: (value: ValueOfPresenter<P>) => void;
|
|
186
190
|
} & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'>;
|
|
187
191
|
|
|
188
192
|
type MergedOfFieldAdaptersWithTwoWayConverter<FieldAdapters extends Readonly<Record<string, FieldAdapter>>, E, Context> = {
|
|
@@ -204,11 +208,11 @@ type MergedOfFieldAdaptersWithValidators<FieldAdapters extends Readonly<Record<K
|
|
|
204
208
|
type MergedOfFieldAdapterWithValidator<A extends FieldAdapter, V extends Validator | undefined> = undefined extends V ? A : A extends FieldAdapter<infer From, infer To, infer E1, infer P1, infer C1> ? V extends Validator<From, infer E2, infer P2, infer C2> ? FieldAdapter<From, To, E1 | E2, P1 | P2, C1 | C2> : never : never;
|
|
205
209
|
declare function mergeAdaptersWithValidators<FieldAdapters extends Readonly<Record<Key, FieldAdapter>>, Validators extends Readonly<Record<string, Validator>>, Key extends keyof Validators = keyof Validators>(adapters: FieldAdapters, validators: Validators): MergedOfFieldAdaptersWithValidators<FieldAdapters, Validators, Key>;
|
|
206
210
|
|
|
207
|
-
type SubFormFieldAdapter<F extends FieldAdapter,
|
|
208
|
-
type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>,
|
|
209
|
-
[K in keyof SubAdapters as K extends StringConcatOf<'$', infer
|
|
211
|
+
type SubFormFieldAdapter<F extends FieldAdapter, ValuePath extends string, Context> = FieldAdapter<FromOfFieldAdapter<F>, ToOfFieldAdapter<F>, ErrorOfFieldAdapter<F>, ValuePathOfFieldAdapter<F> extends StringConcatOf<'$', infer ValuePathSuffix> ? `${ValuePath}${ValuePathSuffix}` : string, Context>;
|
|
212
|
+
type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, ValuePath extends string, Context> = {
|
|
213
|
+
[K in keyof SubAdapters as K extends StringConcatOf<'$', infer TypePathSuffix> ? `${TypePath}${TypePathSuffix}` : never]: SubFormFieldAdapter<SubAdapters[K], ValuePath, Context>;
|
|
210
214
|
};
|
|
211
|
-
declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>,
|
|
215
|
+
declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, TypePath extends string, TypePathsToValuePaths extends Record<TypePath, string>, ContextType extends Type>(subAdapters: SubAdapters, parentTypePath: TypePath, contextType: ContextType): SubFormFieldAdapters<SubAdapters, TypePath, TypePathsToValuePaths[TypePath], ValueOfType<ContextType>>;
|
|
212
216
|
|
|
213
217
|
declare class IntegerToStringConverter<E, ValuePath extends string, Context> implements TwoWayFieldConverter<number, string, E, ValuePath, Context> {
|
|
214
218
|
private readonly isNanError;
|
|
@@ -218,14 +222,14 @@ declare class IntegerToStringConverter<E, ValuePath extends string, Context> imp
|
|
|
218
222
|
revert(from: string): UnreliableFieldConversion<number, E>;
|
|
219
223
|
}
|
|
220
224
|
|
|
221
|
-
declare class NullableToBooleanConverter<T extends Type,
|
|
225
|
+
declare class NullableToBooleanConverter<T extends Type, ValuePath extends string, Context, NullType extends null | undefined> implements TwoWayFieldConverterWithValueFactory<ValueOfType<ReadonlyTypeOfType<T>> | NullType, boolean, never, ValuePath, Context> {
|
|
222
226
|
private readonly typeDef;
|
|
223
227
|
private readonly prototype;
|
|
224
228
|
private readonly nullType;
|
|
225
229
|
readonly defaultValue: ValueOfType<ReadonlyTypeOfType<T>> | NullType;
|
|
226
230
|
constructor(typeDef: T, prototype: ValueOfType<ReadonlyTypeOfType<T>>, nullType: NullType, defaultToNull?: boolean);
|
|
227
231
|
convert(from: ValueOfType<ReadonlyTypeOfType<T>> | NullType): AnnotatedFieldConversion<boolean>;
|
|
228
|
-
revert(from: boolean): UnreliableFieldConversion<ValueOfType<ReadonlyTypeOfType<T>> | NullType,
|
|
232
|
+
revert(from: boolean): UnreliableFieldConversion<ValueOfType<ReadonlyTypeOfType<T>> | NullType, never>;
|
|
229
233
|
create(): ValueOfType<ReadonlyTypeOfType<T>> | NullType;
|
|
230
234
|
}
|
|
231
235
|
|
|
@@ -269,7 +273,7 @@ type ErrorRendererProps<E> = {
|
|
|
269
273
|
error: E;
|
|
270
274
|
};
|
|
271
275
|
type ErrorRenderer<E = any> = ComponentType<ErrorRendererProps<E>>;
|
|
272
|
-
declare function DefaultErrorRenderer({ error, }: ErrorRendererProps<any>):
|
|
276
|
+
declare function DefaultErrorRenderer({ error, }: ErrorRendererProps<any>): string;
|
|
273
277
|
|
|
274
278
|
type ValueTypeOfField<F extends Field> = F extends Field<infer V> ? V : never;
|
|
275
279
|
|
|
@@ -319,8 +323,10 @@ type MantineForm<F extends Fields> = {
|
|
|
319
323
|
onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
|
|
320
324
|
onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
|
|
321
325
|
};
|
|
322
|
-
type MantineFieldComponent<T, P = T, E = any> = UnsafePartialComponent<ComponentType<P>, T,
|
|
323
|
-
|
|
326
|
+
type MantineFieldComponent<T, P = T, E = any> = UnsafePartialComponent<ComponentType<P>, T, [
|
|
327
|
+
E
|
|
328
|
+
] extends [never] ? {} : {
|
|
329
|
+
ErrorRenderer: ErrorRenderer<E>;
|
|
324
330
|
}>;
|
|
325
331
|
|
|
326
332
|
type SuppliedCheckboxProps = Pick<CheckboxProps, 'name' | 'checked' | 'disabled' | 'required' | 'error' | 'onChange' | 'onFocus' | 'onBlur' | 'onKeyUp'>;
|
|
@@ -384,21 +390,21 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
|
|
|
384
390
|
onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
|
|
385
391
|
onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
|
|
386
392
|
constructor(fields: F);
|
|
387
|
-
textInput<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, TextInputProps
|
|
388
|
-
textInput<K extends keyof StringFieldsOfFields<F>, P extends SuppliedTextInputProps<any>>(valuePath: K, TextInput?: ComponentType<P>): MantineFieldComponent<SuppliedTextInputProps, P
|
|
393
|
+
textInput<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, TextInputProps, ErrorOfField<F[K]>>;
|
|
394
|
+
textInput<K extends keyof StringFieldsOfFields<F>, P extends SuppliedTextInputProps<any>>(valuePath: K, TextInput?: ComponentType<P>): MantineFieldComponent<SuppliedTextInputProps, P, ErrorOfField<F[K]>>;
|
|
389
395
|
valueInput<K extends keyof AllFieldsOfFields<F>, P extends SuppliedValueInputProps<ValueTypeOfField<F[K]>, any>>(valuePath: K, ValueInput: ComponentType<P>): MantineFieldComponent<SuppliedValueInputProps<ValueTypeOfField<F[K]>>, P, ErrorOfField<F[K]>>;
|
|
390
396
|
select<K extends keyof StringFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedTextInputProps, ComponentProps<typeof SimpleSelect>, ErrorOfField<F[K]>>;
|
|
391
|
-
checkbox<K extends keyof BooleanFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedCheckboxProps, CheckboxProps
|
|
397
|
+
checkbox<K extends keyof BooleanFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedCheckboxProps, CheckboxProps, ErrorOfField<F[K]>>;
|
|
392
398
|
checkbox<K extends keyof BooleanFieldsOfFields<F>, P extends SuppliedCheckboxProps>(valuePath: K, Checkbox: ComponentType<P>): MantineFieldComponent<SuppliedCheckboxProps, P, ErrorOfField<F[K]>>;
|
|
393
|
-
radioGroup<K extends keyof StringFieldsOfFields<F
|
|
394
|
-
radioGroup<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioGroupProps>(valuePath: K, RadioGroup: ComponentType<P>): MantineFieldComponent<SuppliedRadioGroupProps, P
|
|
399
|
+
radioGroup<K extends keyof StringFieldsOfFields<F>, P extends RadioGroupProps = RadioGroupProps>(valuePath: K): MantineFieldComponent<SuppliedRadioGroupProps, P, ErrorOfField<F[K]>>;
|
|
400
|
+
radioGroup<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioGroupProps>(valuePath: K, RadioGroup: ComponentType<P>): MantineFieldComponent<SuppliedRadioGroupProps, P, ErrorOfField<F[K]>>;
|
|
395
401
|
radio<K extends keyof StringFieldsOfFields<F>>(valuePath: K, value: ValueTypeOfField<F[K]>): MantineFieldComponent<SuppliedRadioProps, RadioProps, ErrorOfField<F[K]>>;
|
|
396
402
|
radio<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioProps>(valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<P>): MantineFieldComponent<SuppliedRadioProps, P, ErrorOfField<F[K]>>;
|
|
397
403
|
pill<K extends keyof AllFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedPillProps, PillProps, ErrorOfField<F[K]>>;
|
|
398
|
-
pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P
|
|
399
|
-
list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K
|
|
400
|
-
fieldsView<K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>): MantineFieldComponent<FieldsViewProps<P['fields']>, P>;
|
|
401
|
-
form<K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P>;
|
|
404
|
+
pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P, ErrorOfField<F[K]>>;
|
|
405
|
+
list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>, never>;
|
|
406
|
+
fieldsView<K extends keyof AllFieldsOfFields<F>, P extends FieldsViewProps<Fields> = FieldsViewProps<SubFormFields<F, K>>>(valuePath: K, FieldsView: ComponentType<P>): MantineFieldComponent<FieldsViewProps<P['fields']>, P, never>;
|
|
407
|
+
form<K extends keyof AllFieldsOfFields<F>, P extends FormProps<ValueTypeOfField<F[K]>> = FormProps<ValueTypeOfField<F[K]>>>(valuePath: K, Form: ComponentType<P>): MantineFieldComponent<FormProps<ValueTypeOfField<F[K]>>, P, never>;
|
|
402
408
|
}
|
|
403
409
|
|
|
404
410
|
type MergedOfValidators<Validators1 extends Partial<Readonly<Record<Keys, Validator>>>, Validators2 extends Partial<Readonly<Record<Keys, Validator>>>, Keys extends string = Extract<keyof Validators1 | keyof Validators2, string>> = Simplify<{
|