@strictly/react-form 0.0.10 → 0.0.12
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/field_adapter_builder.js +18 -6
- package/.out/core/mobx/{form_presenter.d.ts → form_model.d.ts} +15 -21
- package/.out/core/mobx/form_model.js +513 -0
- package/.out/core/mobx/hooks.d.ts +6 -25
- package/.out/core/mobx/hooks.js +14 -50
- package/.out/core/mobx/merge_field_adapters_with_validators.js +1 -5
- package/.out/core/mobx/specs/fixtures.js +2 -1
- package/.out/core/mobx/specs/{form_presenter.tests.js → form_model.tests.js} +52 -43
- package/.out/core/mobx/specs/sub_form_field_adapters.tests.js +2 -1
- package/.out/core/mobx/types.d.ts +4 -4
- package/.out/field_converters/integer_to_string_converter.js +12 -4
- package/.out/field_converters/maybe_identity_converter.js +12 -4
- package/.out/field_converters/nullable_to_boolean_converter.js +24 -7
- package/.out/field_converters/select_value_type_converter.js +36 -12
- package/.out/index.d.ts +1 -1
- package/.out/index.js +1 -1
- package/.out/mantine/create_checkbox.js +8 -4
- package/.out/mantine/create_fields_view.js +7 -4
- package/.out/mantine/create_form.js +1 -1
- package/.out/mantine/create_radio_group.js +8 -4
- package/.out/mantine/create_text_input.js +8 -4
- package/.out/mantine/create_value_input.js +8 -4
- package/.out/mantine/hooks.js +218 -92
- package/.out/mantine/specs/checkbox_hooks.stories.js +13 -1
- package/.out/mantine/specs/checkbox_hooks.tests.js +22 -9
- package/.out/mantine/specs/fields_view_hooks.stories.js +15 -2
- package/.out/mantine/specs/fields_view_hooks.tests.js +12 -3
- package/.out/mantine/specs/radio_group_hooks.stories.js +13 -1
- package/.out/mantine/specs/radio_group_hooks.tests.js +23 -10
- package/.out/mantine/specs/select_hooks.stories.js +13 -1
- package/.out/mantine/specs/text_input_hooks.stories.js +13 -1
- package/.out/mantine/specs/text_input_hooks.tests.js +18 -7
- package/.out/mantine/specs/value_input_hooks.stories.js +14 -2
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.out/tsup.config.js +2 -9
- package/.out/types/merge_validators.js +1 -4
- package/.out/util/partial.js +5 -5
- package/.out/vitest.workspace.js +2 -10
- package/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-check-types.log +1 -1
- package/.turbo/turbo-release$colon$exports.log +1 -1
- package/core/mobx/{form_presenter.ts → form_model.ts} +287 -329
- package/core/mobx/hooks.tsx +26 -123
- package/core/mobx/specs/{form_presenter.tests.ts → form_model.tests.ts} +101 -94
- package/core/mobx/types.ts +12 -12
- package/dist/index.cjs +639 -600
- package/dist/index.d.cts +51 -73
- package/dist/index.d.ts +51 -73
- package/dist/index.js +644 -601
- package/index.ts +1 -1
- package/mantine/hooks.tsx +2 -0
- package/package.json +1 -1
- package/.out/core/mobx/form_presenter.js +0 -422
- /package/.out/core/mobx/specs/{form_presenter.tests.d.ts → form_model.tests.d.ts} +0 -0
package/core/mobx/hooks.tsx
CHANGED
|
@@ -3,194 +3,97 @@ import {
|
|
|
3
3
|
type ValueOfType,
|
|
4
4
|
} from '@strictly/define'
|
|
5
5
|
import {
|
|
6
|
-
type FieldsViewProps,
|
|
7
|
-
} from 'core/props'
|
|
8
|
-
import {
|
|
9
|
-
type ComponentType,
|
|
10
6
|
useCallback,
|
|
11
|
-
useMemo,
|
|
12
7
|
} from 'react'
|
|
8
|
+
import { type FormModel } from './form_model'
|
|
13
9
|
import {
|
|
14
|
-
|
|
15
|
-
type
|
|
16
|
-
|
|
17
|
-
import { type FormPresenter } from './form_presenter'
|
|
18
|
-
import {
|
|
19
|
-
type FormFieldsOfPresenter,
|
|
20
|
-
type ToValueOfPresenterValuePath,
|
|
21
|
-
type ValuePathsOfPresenter,
|
|
10
|
+
type FormFieldsOfModel,
|
|
11
|
+
type ToValueOfModelValuePath,
|
|
12
|
+
type ValuePathsOfModel,
|
|
22
13
|
} from './types'
|
|
23
14
|
|
|
24
15
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25
|
-
type
|
|
16
|
+
type ValueOfModel<M extends FormModel<any, any, any, any>> = M extends FormModel<infer T, any, any, any>
|
|
26
17
|
? ValueOfType<ReadonlyTypeOfType<T>>
|
|
27
18
|
: never
|
|
28
19
|
|
|
29
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
-
type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<P['createModel']>
|
|
31
|
-
|
|
32
|
-
export function useDefaultMobxFormHooks<
|
|
33
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
34
|
-
P extends FormPresenter<any, any, any, any>,
|
|
35
|
-
C extends ComponentType<FieldsViewProps<F>>,
|
|
36
|
-
F extends FormFieldsOfPresenter<P> = FormFieldsOfPresenter<P>,
|
|
37
|
-
>(
|
|
38
|
-
presenter: P,
|
|
39
|
-
value: ValueOfPresenter<P>,
|
|
40
|
-
options?: {
|
|
41
|
-
onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void,
|
|
42
|
-
onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void,
|
|
43
|
-
},
|
|
44
|
-
): {
|
|
45
|
-
model: ModelOfPresenter<P>,
|
|
46
|
-
FormFields?: UnsafePartialComponent<C, FieldsViewProps<F>>,
|
|
47
|
-
onFormSubmit: () => void,
|
|
48
|
-
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void,
|
|
49
|
-
onFieldFocus?(this: void, key: keyof F): void,
|
|
50
|
-
onFieldBlur?(this: void, key: keyof F): void,
|
|
51
|
-
onFieldSubmit?(this: void, key: keyof F): boolean | void,
|
|
52
|
-
}
|
|
53
20
|
export function useDefaultMobxFormHooks<
|
|
54
21
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
F extends FormFieldsOfPresenter<P> = FormFieldsOfPresenter<P>,
|
|
22
|
+
M extends FormModel<any, any, any, any>,
|
|
23
|
+
F extends FormFieldsOfModel<M> = FormFieldsOfModel<M>,
|
|
58
24
|
>(
|
|
59
|
-
|
|
60
|
-
value: ValueOfPresenter<P>,
|
|
61
|
-
options: {
|
|
62
|
-
onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void,
|
|
63
|
-
onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void,
|
|
64
|
-
FormFieldsView: C,
|
|
65
|
-
},
|
|
66
|
-
): {
|
|
67
|
-
model: ModelOfPresenter<P>,
|
|
68
|
-
FormFields: UnsafePartialComponent<C, FieldsViewProps<F>>,
|
|
69
|
-
onFormSubmit: () => void,
|
|
70
|
-
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void,
|
|
71
|
-
onFieldFocus?(this: void, key: keyof F): void,
|
|
72
|
-
onFieldBlur?(this: void, key: keyof F): void,
|
|
73
|
-
onFieldSubmit?(this: void, key: keyof F): boolean | void,
|
|
74
|
-
}
|
|
75
|
-
export function useDefaultMobxFormHooks<
|
|
76
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
-
P extends FormPresenter<any, any, any, any>,
|
|
78
|
-
C extends FieldsViewProps<F>,
|
|
79
|
-
F extends FormFieldsOfPresenter<P> = FormFieldsOfPresenter<P>,
|
|
80
|
-
>(
|
|
81
|
-
presenter: P,
|
|
82
|
-
value: ValueOfPresenter<P>,
|
|
25
|
+
model: M,
|
|
83
26
|
{
|
|
84
27
|
onValidFieldSubmit,
|
|
85
28
|
onValidFormSubmit,
|
|
86
|
-
FormFieldsView,
|
|
87
29
|
}: {
|
|
88
|
-
onValidFieldSubmit?: <Path extends
|
|
89
|
-
onValidFormSubmit?: (
|
|
90
|
-
FormFieldsView?: ComponentType<C>,
|
|
30
|
+
onValidFieldSubmit?: <Path extends ValuePathsOfModel<M>>(valuePath: Path) => void,
|
|
31
|
+
onValidFormSubmit?: (value: ValueOfModel<M>) => void,
|
|
91
32
|
} = {},
|
|
92
33
|
): {
|
|
93
|
-
model: ModelOfPresenter<P>,
|
|
94
|
-
FormFields?: UnsafePartialComponent<ComponentType<C>, FieldsViewProps<F>> | undefined,
|
|
95
34
|
onFormSubmit: () => void,
|
|
96
35
|
onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void,
|
|
97
36
|
onFieldFocus?(this: void, key: keyof F): void,
|
|
98
37
|
onFieldBlur?(this: void, key: keyof F): void,
|
|
99
38
|
onFieldSubmit?(this: void, key: keyof F): boolean | void,
|
|
100
39
|
} {
|
|
101
|
-
const model = useMemo(function () {
|
|
102
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
103
|
-
return presenter.createModel(value) as ReturnType<P['createModel']>
|
|
104
|
-
}, [
|
|
105
|
-
presenter,
|
|
106
|
-
value,
|
|
107
|
-
])
|
|
108
|
-
|
|
109
40
|
const onFieldValueChange = useCallback(
|
|
110
|
-
function<Path extends
|
|
41
|
+
function<Path extends ValuePathsOfModel<M>> (
|
|
111
42
|
path: Path,
|
|
112
|
-
value:
|
|
43
|
+
value: ToValueOfModelValuePath<M, Path>,
|
|
113
44
|
) {
|
|
114
|
-
|
|
115
|
-
|
|
45
|
+
// TODO do in one action
|
|
46
|
+
model.clearFieldError(path)
|
|
47
|
+
model.setFieldValue<Path>(path, value)
|
|
116
48
|
},
|
|
117
|
-
[
|
|
118
|
-
presenter,
|
|
119
|
-
model,
|
|
120
|
-
],
|
|
49
|
+
[model],
|
|
121
50
|
)
|
|
122
51
|
|
|
123
52
|
const onFieldSubmit = useCallback(
|
|
124
|
-
function<Path extends
|
|
125
|
-
if (
|
|
126
|
-
onValidFieldSubmit?.(
|
|
53
|
+
function<Path extends ValuePathsOfModel<M>> (valuePath: Path) {
|
|
54
|
+
if (model.validateField(valuePath)) {
|
|
55
|
+
onValidFieldSubmit?.(valuePath)
|
|
127
56
|
}
|
|
128
57
|
return false
|
|
129
58
|
},
|
|
130
59
|
[
|
|
131
|
-
presenter,
|
|
132
60
|
model,
|
|
133
61
|
onValidFieldSubmit,
|
|
134
62
|
],
|
|
135
63
|
)
|
|
136
64
|
|
|
137
65
|
const onFieldBlur = useCallback(
|
|
138
|
-
function<Path extends
|
|
66
|
+
function<Path extends ValuePathsOfModel<M>> (path: Path) {
|
|
139
67
|
// work around potential loss of focus prior to state potentially invalidating change triggering
|
|
140
68
|
// (e.g. changing a discriminator)
|
|
141
69
|
// TODO debounce?
|
|
142
70
|
setTimeout(function () {
|
|
143
|
-
if (
|
|
144
|
-
|
|
71
|
+
if (model.isValuePathActive(path)) {
|
|
72
|
+
model.validateField(path, true)
|
|
145
73
|
}
|
|
146
74
|
}, 100)
|
|
147
75
|
},
|
|
148
|
-
[
|
|
149
|
-
presenter,
|
|
150
|
-
model,
|
|
151
|
-
],
|
|
76
|
+
[model],
|
|
152
77
|
)
|
|
153
78
|
|
|
154
79
|
const onFormSubmit = useCallback(
|
|
155
80
|
function () {
|
|
156
|
-
if (
|
|
157
|
-
onValidFormSubmit?.(model
|
|
81
|
+
if (model.validateAll()) {
|
|
82
|
+
onValidFormSubmit?.(model.value)
|
|
158
83
|
}
|
|
159
84
|
},
|
|
160
85
|
[
|
|
161
|
-
presenter,
|
|
162
86
|
model,
|
|
163
87
|
onValidFormSubmit,
|
|
164
88
|
],
|
|
165
89
|
)
|
|
166
90
|
|
|
167
|
-
|
|
168
|
-
if (FormFieldsView == null) {
|
|
169
|
-
return undefined
|
|
170
|
-
}
|
|
171
|
-
return createUnsafePartialObserverComponent(FormFieldsView, (): FieldsViewProps<F> => {
|
|
172
|
-
return {
|
|
173
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
174
|
-
fields: model.fields as C['fields'],
|
|
175
|
-
onFieldBlur,
|
|
176
|
-
onFieldSubmit,
|
|
177
|
-
onFieldValueChange,
|
|
178
|
-
}
|
|
179
|
-
})
|
|
180
|
-
}, [
|
|
181
|
-
model,
|
|
182
|
-
FormFieldsView,
|
|
183
|
-
onFieldBlur,
|
|
184
|
-
onFieldSubmit,
|
|
185
|
-
onFieldValueChange,
|
|
186
|
-
])
|
|
91
|
+
// TODO have option to automatically bind all these callbacks to a FieldsView parameter
|
|
187
92
|
|
|
188
93
|
return {
|
|
189
|
-
model,
|
|
190
94
|
onFieldValueChange,
|
|
191
95
|
onFieldSubmit,
|
|
192
96
|
onFieldBlur,
|
|
193
97
|
onFormSubmit,
|
|
194
|
-
FormFields,
|
|
195
98
|
}
|
|
196
99
|
}
|
|
@@ -6,14 +6,10 @@ import {
|
|
|
6
6
|
nullType,
|
|
7
7
|
numberType,
|
|
8
8
|
object,
|
|
9
|
-
type ReadonlyOfTypeDef,
|
|
10
|
-
type ReadonlyTypeOfType,
|
|
11
9
|
record,
|
|
12
10
|
stringType,
|
|
13
|
-
type Type,
|
|
14
11
|
union,
|
|
15
12
|
type ValueOfType,
|
|
16
|
-
type ValueOfTypeDef,
|
|
17
13
|
type ValueToTypePathsOfType,
|
|
18
14
|
} from '@strictly/define'
|
|
19
15
|
import { type FieldAdapter } from 'core/mobx/field_adapter'
|
|
@@ -24,9 +20,8 @@ import {
|
|
|
24
20
|
import {
|
|
25
21
|
type FlattenedTypePathsToAdaptersOf,
|
|
26
22
|
FormModel,
|
|
27
|
-
FormPresenter,
|
|
28
23
|
type ValuePathsToAdaptersOf,
|
|
29
|
-
} from 'core/mobx/
|
|
24
|
+
} from 'core/mobx/form_model'
|
|
30
25
|
import { IntegerToStringConverter } from 'field_converters/integer_to_string_converter'
|
|
31
26
|
import { NullableToBooleanConverter } from 'field_converters/nullable_to_boolean_converter'
|
|
32
27
|
import { SelectDiscriminatedUnionConverter } from 'field_converters/select_value_type_converter'
|
|
@@ -43,21 +38,6 @@ import {
|
|
|
43
38
|
|
|
44
39
|
const IS_NAN_ERROR = 1
|
|
45
40
|
|
|
46
|
-
class TestFormPresenter<
|
|
47
|
-
T extends Type,
|
|
48
|
-
ValueToTypePaths extends Readonly<Record<string, string>>,
|
|
49
|
-
TypePathsToAdapters extends FlattenedTypePathsToAdaptersOf<
|
|
50
|
-
FlattenedValuesOfType<T, '*'>,
|
|
51
|
-
ValueOfType<ReadonlyTypeOfType<T>>
|
|
52
|
-
>,
|
|
53
|
-
> extends FormPresenter<T, ValueToTypePaths, TypePathsToAdapters> {
|
|
54
|
-
override createModel(value: ValueOfTypeDef<ReadonlyOfTypeDef<T['definition']>, {}>): FormModel<T, ValueToTypePaths,
|
|
55
|
-
TypePathsToAdapters, ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>>
|
|
56
|
-
{
|
|
57
|
-
return new FormModel(this.type, value, this.adapters)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
41
|
const originalIntegerToStringAdapter = adapterFromTwoWayConverter(
|
|
62
42
|
new IntegerToStringConverter(IS_NAN_ERROR),
|
|
63
43
|
prototypingFieldValueFactory(0),
|
|
@@ -492,20 +472,12 @@ describe('all', function () {
|
|
|
492
472
|
// TODO union
|
|
493
473
|
})
|
|
494
474
|
|
|
495
|
-
describe('
|
|
475
|
+
describe('FormModel', function () {
|
|
496
476
|
describe('literal', function () {
|
|
497
477
|
const typeDef = numberType
|
|
498
478
|
const adapters = {
|
|
499
479
|
$: integerToStringAdapter,
|
|
500
480
|
} as const
|
|
501
|
-
const presenter = new TestFormPresenter<
|
|
502
|
-
typeof typeDef,
|
|
503
|
-
ValueToTypePathsOfType<typeof typeDef>,
|
|
504
|
-
typeof adapters
|
|
505
|
-
>(
|
|
506
|
-
typeDef,
|
|
507
|
-
adapters,
|
|
508
|
-
)
|
|
509
481
|
const originalValue: ValueOfType<typeof typeDef> = 2
|
|
510
482
|
let model: FormModel<
|
|
511
483
|
typeof typeDef,
|
|
@@ -513,13 +485,21 @@ describe('all', function () {
|
|
|
513
485
|
typeof adapters
|
|
514
486
|
>
|
|
515
487
|
beforeEach(function () {
|
|
516
|
-
model =
|
|
488
|
+
model = new FormModel<
|
|
489
|
+
typeof typeDef,
|
|
490
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
491
|
+
typeof adapters
|
|
492
|
+
>(
|
|
493
|
+
typeDef,
|
|
494
|
+
originalValue,
|
|
495
|
+
adapters,
|
|
496
|
+
)
|
|
517
497
|
})
|
|
518
498
|
|
|
519
499
|
describe('setFieldValueAndValidate', function () {
|
|
520
500
|
describe('success', function () {
|
|
521
501
|
beforeEach(function () {
|
|
522
|
-
|
|
502
|
+
model.setFieldValueAndValidate<'$'>('$', '1')
|
|
523
503
|
})
|
|
524
504
|
|
|
525
505
|
it('does set the underlying value', function () {
|
|
@@ -539,7 +519,7 @@ describe('all', function () {
|
|
|
539
519
|
describe('failure', function () {
|
|
540
520
|
describe('conversion fails', function () {
|
|
541
521
|
beforeEach(function () {
|
|
542
|
-
|
|
522
|
+
model.setFieldValueAndValidate<'$'>('$', 'x')
|
|
543
523
|
})
|
|
544
524
|
|
|
545
525
|
it('does not set the underlying value', function () {
|
|
@@ -565,7 +545,7 @@ describe('all', function () {
|
|
|
565
545
|
error: errorCode,
|
|
566
546
|
value: [newValue],
|
|
567
547
|
})
|
|
568
|
-
|
|
548
|
+
model.setFieldValueAndValidate<'$'>('$', '-1')
|
|
569
549
|
})
|
|
570
550
|
|
|
571
551
|
it('does set the underlying value', function () {
|
|
@@ -596,7 +576,7 @@ describe('all', function () {
|
|
|
596
576
|
],
|
|
597
577
|
] as const)('setFieldValue to %s', function (newValue, expectedValue) {
|
|
598
578
|
beforeEach(function () {
|
|
599
|
-
|
|
579
|
+
model.setFieldValue<'$'>('$', newValue)
|
|
600
580
|
})
|
|
601
581
|
|
|
602
582
|
it('does set the underlying value', function () {
|
|
@@ -619,14 +599,6 @@ describe('all', function () {
|
|
|
619
599
|
const converters = {
|
|
620
600
|
'$.*': integerToStringAdapter,
|
|
621
601
|
} as const
|
|
622
|
-
const presenter = new TestFormPresenter<
|
|
623
|
-
typeof typeDef,
|
|
624
|
-
ValueToTypePathsOfType<typeof typeDef>,
|
|
625
|
-
typeof converters
|
|
626
|
-
>(
|
|
627
|
-
typeDef,
|
|
628
|
-
converters,
|
|
629
|
-
)
|
|
630
602
|
let originalValue: ValueOfType<typeof typeDef>
|
|
631
603
|
let model: FormModel<
|
|
632
604
|
typeof typeDef,
|
|
@@ -639,13 +611,21 @@ describe('all', function () {
|
|
|
639
611
|
3,
|
|
640
612
|
7,
|
|
641
613
|
]
|
|
642
|
-
model =
|
|
614
|
+
model = new FormModel<
|
|
615
|
+
typeof typeDef,
|
|
616
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
617
|
+
typeof converters
|
|
618
|
+
>(
|
|
619
|
+
typeDef,
|
|
620
|
+
originalValue,
|
|
621
|
+
converters,
|
|
622
|
+
)
|
|
643
623
|
})
|
|
644
624
|
|
|
645
625
|
describe('setFieldValueAndValidate', function () {
|
|
646
626
|
describe('success', function () {
|
|
647
627
|
beforeEach(function () {
|
|
648
|
-
|
|
628
|
+
model.setFieldValueAndValidate<'$.0'>('$.0', '100')
|
|
649
629
|
})
|
|
650
630
|
|
|
651
631
|
it('sets the underlying value', function () {
|
|
@@ -668,7 +648,7 @@ describe('all', function () {
|
|
|
668
648
|
|
|
669
649
|
describe('failure', function () {
|
|
670
650
|
beforeEach(function () {
|
|
671
|
-
|
|
651
|
+
model.setFieldValueAndValidate<'$.0'>('$.0', 'x')
|
|
672
652
|
})
|
|
673
653
|
|
|
674
654
|
it('does not set the underlying value', function () {
|
|
@@ -691,7 +671,7 @@ describe('all', function () {
|
|
|
691
671
|
'x',
|
|
692
672
|
])('setFieldValue to %s', function (newValue) {
|
|
693
673
|
beforeEach(function () {
|
|
694
|
-
|
|
674
|
+
model.setFieldValue('$.0', newValue)
|
|
695
675
|
})
|
|
696
676
|
|
|
697
677
|
it('does not set the underlying value', function () {
|
|
@@ -710,10 +690,10 @@ describe('all', function () {
|
|
|
710
690
|
|
|
711
691
|
describe('validate', function () {
|
|
712
692
|
beforeEach(function () {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
693
|
+
model.setFieldValue('$.0', 'x')
|
|
694
|
+
model.setFieldValue('$.1', '2')
|
|
695
|
+
model.setFieldValue('$.2', 'z')
|
|
696
|
+
model.validateAll()
|
|
717
697
|
})
|
|
718
698
|
|
|
719
699
|
it('contains errors for all invalid fields', function () {
|
|
@@ -756,7 +736,7 @@ describe('all', function () {
|
|
|
756
736
|
})
|
|
757
737
|
|
|
758
738
|
it('supplies the full, previous context when converting', function () {
|
|
759
|
-
|
|
739
|
+
model.setFieldValueAndValidate('$.2', '4')
|
|
760
740
|
|
|
761
741
|
expect(integerToStringAdapter.revert).toHaveBeenCalledOnce()
|
|
762
742
|
expect(integerToStringAdapter.revert).toHaveBeenCalledWith(
|
|
@@ -782,7 +762,7 @@ describe('all', function () {
|
|
|
782
762
|
model.errors['$.0'] = 0
|
|
783
763
|
model.errors['$.1'] = 1
|
|
784
764
|
model.errors['$.2'] = 2
|
|
785
|
-
|
|
765
|
+
model.addListItem('$', null, 0)
|
|
786
766
|
})
|
|
787
767
|
|
|
788
768
|
it('adds the list item to the underlying value', function () {
|
|
@@ -839,7 +819,7 @@ describe('all', function () {
|
|
|
839
819
|
|
|
840
820
|
describe('add defined value', function () {
|
|
841
821
|
beforeEach(function () {
|
|
842
|
-
|
|
822
|
+
model.addListItem('$', [5])
|
|
843
823
|
})
|
|
844
824
|
|
|
845
825
|
it('adds the expected value at the end', function () {
|
|
@@ -881,7 +861,7 @@ describe('all', function () {
|
|
|
881
861
|
|
|
882
862
|
describe('remove first item', function () {
|
|
883
863
|
beforeEach(function () {
|
|
884
|
-
|
|
864
|
+
model.removeListItem('$.0')
|
|
885
865
|
})
|
|
886
866
|
|
|
887
867
|
it('updates the underlying value', function () {
|
|
@@ -907,7 +887,7 @@ describe('all', function () {
|
|
|
907
887
|
|
|
908
888
|
describe('remove second item', function () {
|
|
909
889
|
beforeEach(function () {
|
|
910
|
-
|
|
890
|
+
model.removeListItem('$.1')
|
|
911
891
|
})
|
|
912
892
|
|
|
913
893
|
it('updates the underlying value', function () {
|
|
@@ -930,6 +910,25 @@ describe('all', function () {
|
|
|
930
910
|
})
|
|
931
911
|
})
|
|
932
912
|
})
|
|
913
|
+
|
|
914
|
+
describe('remove two items', function () {
|
|
915
|
+
beforeEach(function () {
|
|
916
|
+
model.removeListItem('$.0', '$.1')
|
|
917
|
+
})
|
|
918
|
+
|
|
919
|
+
it('updates the underlying value', function () {
|
|
920
|
+
expect(model.value).toEqual([7])
|
|
921
|
+
})
|
|
922
|
+
|
|
923
|
+
it('updates the field values and errors', function () {
|
|
924
|
+
expect(model.fields).toEqual({
|
|
925
|
+
'$.0': expect.objectContaining({
|
|
926
|
+
value: '7',
|
|
927
|
+
error: 2,
|
|
928
|
+
}),
|
|
929
|
+
})
|
|
930
|
+
})
|
|
931
|
+
})
|
|
933
932
|
})
|
|
934
933
|
})
|
|
935
934
|
|
|
@@ -946,14 +945,6 @@ describe('all', function () {
|
|
|
946
945
|
'$.*': integerToStringAdapter,
|
|
947
946
|
} as const
|
|
948
947
|
type ValueToTypePaths = ValueToTypePathsOfType<typeof type>
|
|
949
|
-
const presenter = new TestFormPresenter<
|
|
950
|
-
typeof type,
|
|
951
|
-
ValueToTypePaths,
|
|
952
|
-
typeof adapters
|
|
953
|
-
>(
|
|
954
|
-
type,
|
|
955
|
-
adapters,
|
|
956
|
-
)
|
|
957
948
|
let originalValue: ValueOfType<typeof type>
|
|
958
949
|
let model: FormModel<
|
|
959
950
|
typeof type,
|
|
@@ -962,7 +953,15 @@ describe('all', function () {
|
|
|
962
953
|
>
|
|
963
954
|
beforeEach(function () {
|
|
964
955
|
originalValue = null
|
|
965
|
-
model =
|
|
956
|
+
model = new FormModel<
|
|
957
|
+
typeof type,
|
|
958
|
+
ValueToTypePaths,
|
|
959
|
+
typeof adapters
|
|
960
|
+
>(
|
|
961
|
+
type,
|
|
962
|
+
originalValue,
|
|
963
|
+
adapters,
|
|
964
|
+
)
|
|
966
965
|
})
|
|
967
966
|
|
|
968
967
|
it('has the expected fields', function () {
|
|
@@ -979,7 +978,7 @@ describe('all', function () {
|
|
|
979
978
|
describe('setFieldValueAndValidate', function () {
|
|
980
979
|
describe('success', function () {
|
|
981
980
|
beforeEach(function () {
|
|
982
|
-
|
|
981
|
+
model.setFieldValueAndValidate<'$'>('$', true)
|
|
983
982
|
})
|
|
984
983
|
|
|
985
984
|
it('sets the underlying value', function () {
|
|
@@ -1016,21 +1015,21 @@ describe('all', function () {
|
|
|
1016
1015
|
'$.x:a': identityAdapter(0).narrow,
|
|
1017
1016
|
'$.y:b': identityAdapter(false).narrow,
|
|
1018
1017
|
} as const
|
|
1019
|
-
const presenter = new TestFormPresenter<
|
|
1020
|
-
typeof type,
|
|
1021
|
-
ValueToTypePaths,
|
|
1022
|
-
typeof adapters
|
|
1023
|
-
>(
|
|
1024
|
-
type,
|
|
1025
|
-
adapters,
|
|
1026
|
-
)
|
|
1027
1018
|
|
|
1028
1019
|
describe('isValuePathActive', function () {
|
|
1029
1020
|
describe('discriminator x', function () {
|
|
1030
|
-
const model =
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1021
|
+
const model = new FormModel<
|
|
1022
|
+
typeof type,
|
|
1023
|
+
ValueToTypePaths,
|
|
1024
|
+
typeof adapters
|
|
1025
|
+
>(
|
|
1026
|
+
type,
|
|
1027
|
+
{
|
|
1028
|
+
d: 'x',
|
|
1029
|
+
a: 1,
|
|
1030
|
+
},
|
|
1031
|
+
adapters,
|
|
1032
|
+
)
|
|
1034
1033
|
it.each([
|
|
1035
1034
|
[
|
|
1036
1035
|
'$',
|
|
@@ -1045,16 +1044,24 @@ describe('all', function () {
|
|
|
1045
1044
|
false,
|
|
1046
1045
|
],
|
|
1047
1046
|
] as const)('value path %s is active %s', function (path, expected) {
|
|
1048
|
-
const isValid =
|
|
1047
|
+
const isValid = model.isValuePathActive(path)
|
|
1049
1048
|
expect(isValid).toBe(expected)
|
|
1050
1049
|
})
|
|
1051
1050
|
})
|
|
1052
1051
|
|
|
1053
1052
|
describe('discriminator y', function () {
|
|
1054
|
-
const model =
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1053
|
+
const model = new FormModel<
|
|
1054
|
+
typeof type,
|
|
1055
|
+
ValueToTypePaths,
|
|
1056
|
+
typeof adapters
|
|
1057
|
+
>(
|
|
1058
|
+
type,
|
|
1059
|
+
{
|
|
1060
|
+
d: 'y',
|
|
1061
|
+
b: false,
|
|
1062
|
+
},
|
|
1063
|
+
adapters,
|
|
1064
|
+
)
|
|
1058
1065
|
it.each([
|
|
1059
1066
|
[
|
|
1060
1067
|
'$',
|
|
@@ -1069,7 +1076,7 @@ describe('all', function () {
|
|
|
1069
1076
|
true,
|
|
1070
1077
|
],
|
|
1071
1078
|
] as const)('value path %s is active %s', function (path, expected) {
|
|
1072
|
-
const isValid =
|
|
1079
|
+
const isValid = model.isValuePathActive(path)
|
|
1073
1080
|
expect(isValid).toBe(expected)
|
|
1074
1081
|
})
|
|
1075
1082
|
})
|
|
@@ -1087,14 +1094,6 @@ describe('all', function () {
|
|
|
1087
1094
|
$: '$',
|
|
1088
1095
|
'$.fake': '$.fake',
|
|
1089
1096
|
}
|
|
1090
|
-
const presenter = new TestFormPresenter<
|
|
1091
|
-
typeof typeDef,
|
|
1092
|
-
JsonPaths,
|
|
1093
|
-
typeof converters
|
|
1094
|
-
>(
|
|
1095
|
-
typeDef,
|
|
1096
|
-
converters,
|
|
1097
|
-
)
|
|
1098
1097
|
let originalValue: ValueOfType<typeof typeDef>
|
|
1099
1098
|
let model: FormModel<
|
|
1100
1099
|
typeof typeDef,
|
|
@@ -1103,7 +1102,15 @@ describe('all', function () {
|
|
|
1103
1102
|
>
|
|
1104
1103
|
beforeEach(function () {
|
|
1105
1104
|
originalValue = 1
|
|
1106
|
-
model =
|
|
1105
|
+
model = new FormModel<
|
|
1106
|
+
typeof typeDef,
|
|
1107
|
+
JsonPaths,
|
|
1108
|
+
typeof converters
|
|
1109
|
+
>(
|
|
1110
|
+
typeDef,
|
|
1111
|
+
originalValue,
|
|
1112
|
+
converters,
|
|
1113
|
+
)
|
|
1107
1114
|
})
|
|
1108
1115
|
|
|
1109
1116
|
it('returns the default value for the fake field', function () {
|
|
@@ -1114,7 +1121,7 @@ describe('all', function () {
|
|
|
1114
1121
|
|
|
1115
1122
|
describe('setting fake field', function () {
|
|
1116
1123
|
beforeEach(function () {
|
|
1117
|
-
|
|
1124
|
+
model.setFieldValue('$.fake', true)
|
|
1118
1125
|
})
|
|
1119
1126
|
|
|
1120
1127
|
it('stores the new value', function () {
|
package/core/mobx/types.ts
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
import { type ToOfFieldAdapter } from './field_adapter'
|
|
3
3
|
import {
|
|
4
4
|
type FlattenedConvertedFieldsOf,
|
|
5
|
-
type
|
|
6
|
-
} from './
|
|
5
|
+
type FormModel,
|
|
6
|
+
} from './form_model'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Used to extract the supported value paths from a presenter
|
|
10
10
|
*/
|
|
11
|
-
export type
|
|
11
|
+
export type ValuePathsOfModel<
|
|
12
12
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
Presenter extends
|
|
14
|
-
> = Presenter extends
|
|
13
|
+
Presenter extends FormModel<any, any, any, any>,
|
|
14
|
+
> = Presenter extends FormModel<
|
|
15
15
|
infer _1,
|
|
16
16
|
infer _2,
|
|
17
17
|
infer _3,
|
|
@@ -23,11 +23,11 @@ export type ValuePathsOfPresenter<
|
|
|
23
23
|
* Used to extract the render type (so the value that is passed to the view) of a given value path
|
|
24
24
|
* from a presenter
|
|
25
25
|
*/
|
|
26
|
-
export type
|
|
26
|
+
export type ToValueOfModelValuePath<
|
|
27
27
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
-
Presenter extends
|
|
29
|
-
K extends
|
|
30
|
-
> = Presenter extends
|
|
28
|
+
Presenter extends FormModel<any, any, any, any>,
|
|
29
|
+
K extends ValuePathsOfModel<Presenter>,
|
|
30
|
+
> = Presenter extends FormModel<
|
|
31
31
|
infer _1,
|
|
32
32
|
infer _2,
|
|
33
33
|
infer _3,
|
|
@@ -42,10 +42,10 @@ export type ToValueOfPresenterValuePath<
|
|
|
42
42
|
* is less typing, albeit at the cost of potentially getting type errors
|
|
43
43
|
* reported a long way away from the source
|
|
44
44
|
*/
|
|
45
|
-
export type
|
|
45
|
+
export type FormFieldsOfModel<
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
-
Presenter extends
|
|
48
|
-
> = Presenter extends
|
|
47
|
+
Presenter extends FormModel<any, any, any, any>,
|
|
48
|
+
> = Presenter extends FormModel<
|
|
49
49
|
infer _1,
|
|
50
50
|
infer _2,
|
|
51
51
|
infer _3,
|