@strictly/react-form 0.0.15 → 0.0.16

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.
Files changed (38) hide show
  1. package/.out/core/mobx/field_adapter_builder.d.ts +1 -1
  2. package/.out/core/mobx/form_model.d.ts +3 -4
  3. package/.out/core/mobx/form_model.js +27 -23
  4. package/.out/core/mobx/specs/form_model.tests.js +18 -8
  5. package/.out/core/mobx/types.d.ts +4 -4
  6. package/.out/index.d.ts +0 -1
  7. package/.out/index.js +0 -1
  8. package/.out/mantine/create_field_view.d.ts +20 -0
  9. package/.out/mantine/create_field_view.js +54 -0
  10. package/.out/mantine/create_list.js +3 -2
  11. package/.out/mantine/hooks.d.ts +4 -1
  12. package/.out/mantine/hooks.js +13 -1
  13. package/.out/mantine/specs/field_view_hooks.stories.d.ts +12 -0
  14. package/.out/mantine/specs/field_view_hooks.stories.js +61 -0
  15. package/.out/mantine/specs/field_view_hooks.tests.d.ts +1 -0
  16. package/.out/mantine/specs/field_view_hooks.tests.js +12 -0
  17. package/.out/tsconfig.tsbuildinfo +1 -1
  18. package/.turbo/turbo-build.log +8 -8
  19. package/.turbo/turbo-check-types.log +1 -1
  20. package/core/mobx/field_adapter_builder.ts +2 -2
  21. package/core/mobx/form_model.ts +43 -27
  22. package/core/mobx/specs/form_model.tests.ts +28 -11
  23. package/core/mobx/types.ts +4 -4
  24. package/dist/index.cjs +124 -70
  25. package/dist/index.d.cts +26 -26
  26. package/dist/index.d.ts +26 -26
  27. package/dist/index.js +121 -62
  28. package/index.ts +0 -1
  29. package/mantine/create_field_view.tsx +94 -0
  30. package/mantine/create_list.tsx +9 -2
  31. package/mantine/hooks.tsx +18 -1
  32. package/mantine/specs/__snapshots__/field_view_hooks.tests.tsx.snap +153 -0
  33. package/mantine/specs/field_view_hooks.stories.tsx +112 -0
  34. package/mantine/specs/field_view_hooks.tests.tsx +15 -0
  35. package/package.json +1 -1
  36. package/.out/mantine/field_view.d.ts +0 -18
  37. package/.out/mantine/field_view.js +0 -16
  38. package/mantine/field_view.tsx +0 -39
@@ -7,12 +7,12 @@ $ tsup
7
7
  CLI Target: es6
8
8
  CJS Build start
9
9
  ESM Build start
10
- ESM dist/index.js 55.85 KB
11
- ESM ⚡️ Build success in 136ms
12
- CJS dist/index.cjs 59.76 KB
13
- CJS ⚡️ Build success in 141ms
10
+ ESM dist/index.js 57.40 KB
11
+ ESM ⚡️ Build success in 138ms
12
+ CJS dist/index.cjs 61.39 KB
13
+ CJS ⚡️ Build success in 139ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 9792ms
16
- DTS dist/index.d.cts 37.63 KB
17
- DTS dist/index.d.ts 37.63 KB
18
- Done in 10.91s.
15
+ DTS ⚡️ Build success in 9840ms
16
+ DTS dist/index.d.cts 37.86 KB
17
+ DTS dist/index.d.ts 37.86 KB
18
+ Done in 10.97s.
@@ -1,3 +1,3 @@
1
1
  yarn run v1.22.22
2
2
  $ tsc
3
- Done in 7.51s.
3
+ Done in 7.62s.
@@ -336,8 +336,8 @@ export function trimmingStringAdapter<
336
336
 
337
337
  export function listAdapter<
338
338
  E,
339
- ValuePath extends string,
340
- Context,
339
+ ValuePath extends string = string,
340
+ Context = unknown,
341
341
  >() {
342
342
  return new FieldAdapterBuilder<readonly E[], readonly E[], never, ValuePath, Context>(
343
343
  annotatedIdentityConverter<readonly E[], ValuePath, Context>(false),
@@ -105,11 +105,18 @@ export type ValuePathsToAdaptersOf<
105
105
  : never
106
106
 
107
107
  export type ContextOf<TypePathsToAdapters extends Partial<Readonly<Record<string, FieldAdapter>>>> =
108
- UnionToIntersection<{
109
- readonly [
110
- K in keyof TypePathsToAdapters
111
- ]: TypePathsToAdapters[K] extends undefined ? undefined : ContextOfFieldAdapter<NonNullable<TypePathsToAdapters[K]>>
112
- }[keyof TypePathsToAdapters]>
108
+ UnionToIntersection<
109
+ | {
110
+ readonly [
111
+ K in keyof TypePathsToAdapters
112
+ ]: TypePathsToAdapters[K] extends undefined ? undefined
113
+ // ignore unspecified values
114
+ : unknown extends ContextOfFieldAdapter<NonNullable<TypePathsToAdapters[K]>> ? never
115
+ : ContextOfFieldAdapter<NonNullable<TypePathsToAdapters[K]>>
116
+ }[keyof TypePathsToAdapters]
117
+ // ensure we have at least one thing to intersect (can end up with a `never` context otherwise)
118
+ | {}
119
+ >
113
120
 
114
121
  export abstract class FormModel<
115
122
  T extends Type,
@@ -140,7 +147,6 @@ export abstract class FormModel<
140
147
  ) {
141
148
  this.value = mobxCopy(type, value)
142
149
  this.flattenedTypeDefs = flattenTypesOfType(type)
143
- const contextValue = this.toContext(value)
144
150
  // pre-populate field overrides for consistent behavior when default information is overwritten
145
151
  // then returned to
146
152
  const conversions = flattenValueTo(
@@ -149,11 +155,14 @@ export abstract class FormModel<
149
155
  () => {},
150
156
  (
151
157
  _t: StrictTypeDef,
152
- value: AnyValueType,
158
+ fieldValue: AnyValueType,
153
159
  _setter,
154
160
  typePath,
155
161
  valuePath,
156
162
  ): AnnotatedFieldConversion<FieldOverride> | undefined => {
163
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
164
+ const contextValue = this.toContext(value, valuePath as keyof ValuePathsToAdapters)
165
+
157
166
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
158
167
  const adapter = this.adapters[typePath as keyof TypePathsToAdapters]
159
168
  if (adapter == null) {
@@ -168,7 +177,7 @@ export abstract class FormModel<
168
177
  return
169
178
  }
170
179
  // cannot call this.context yet as the "this" pointer has not been fully created
171
- return convert(value, valuePath, contextValue)
180
+ return convert(fieldValue, valuePath, contextValue)
172
181
  },
173
182
  )
174
183
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
@@ -177,12 +186,10 @@ export abstract class FormModel<
177
186
  }) as FlattenedFieldOverrides<ValuePathsToAdapters>
178
187
  }
179
188
 
180
- @computed.struct
181
- get context() {
182
- return this.toContext(this.value)
183
- }
184
-
185
- protected abstract toContext(value: ValueOfType<ReadonlyTypeOfType<T>>): ContextType
189
+ protected abstract toContext(
190
+ value: ValueOfType<ReadonlyTypeOfType<T>>,
191
+ valuePath: keyof ValuePathsToAdapters,
192
+ ): ContextType
186
193
 
187
194
  @computed
188
195
  get fields(): SimplifyDeep<FlattenedConvertedFieldsOf<ValuePathsToAdapters>> {
@@ -256,6 +263,7 @@ export abstract class FormModel<
256
263
  const accessor = this.getAccessorForValuePath(valuePath)
257
264
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
258
265
  const fieldTypeDef = this.flattenedTypeDefs[typePath as string]
266
+ const context = this.toContext(this.value, valuePath)
259
267
  const {
260
268
  value,
261
269
  required,
@@ -267,14 +275,14 @@ export abstract class FormModel<
267
275
  ? mobxCopy(
268
276
  fieldTypeDef,
269
277
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
270
- create(valuePath as string, this.context),
278
+ create(valuePath as string, context),
271
279
  )
272
280
  // fake values can't be copied
273
281
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
274
- : create(valuePath as string, this.context),
282
+ : create(valuePath as string, context),
275
283
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
276
284
  valuePath as string,
277
- this.context,
285
+ context,
278
286
  )
279
287
  const error = this.errors[valuePath]
280
288
  return {
@@ -360,7 +368,9 @@ export abstract class FormModel<
360
368
  : elementAdapter.create(
361
369
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
362
370
  elementTypePath as string,
363
- this.context,
371
+ // TODO what can we use for the value path here?
372
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
373
+ this.toContext(this.value, valuePath as unknown as keyof ValuePathsToAdapters),
364
374
  )
365
375
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
366
376
  const originalList: any[] = accessor.value
@@ -505,7 +515,7 @@ export abstract class FormModel<
505
515
  assertExists(revert, 'setting value not supported {}', valuePath)
506
516
 
507
517
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
508
- const conversion = revert(value, valuePath as any, this.context)
518
+ const conversion = revert(value, valuePath as any, this.toContext(this.value, valuePath))
509
519
  const accessor = this.getAccessorForValuePath(valuePath)
510
520
  return runInAction(() => {
511
521
  this.fieldOverrides[valuePath] = [value]
@@ -548,10 +558,12 @@ export abstract class FormModel<
548
558
  convert,
549
559
  create,
550
560
  } = adapter
551
- const value = create(valuePath, this.context)
561
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
562
+ const context = this.toContext(this.value, valuePath as unknown as keyof ValuePathsToAdapters)
563
+ const value = create(valuePath, context)
552
564
  const {
553
565
  value: displayValue,
554
- } = convert(value, valuePath, this.context)
566
+ } = convert(value, valuePath, context)
555
567
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
556
568
  const key = valuePath as unknown as keyof ValuePathsToAdapters
557
569
  runInAction(() => {
@@ -586,16 +598,18 @@ export abstract class FormModel<
586
598
  } = this.getAdapterForValuePath(valuePath)
587
599
  const fieldOverride = this.fieldOverrides[valuePath]
588
600
  const accessor = this.getAccessorForValuePath(valuePath)
601
+ const context = this.toContext(this.value, valuePath)
602
+
589
603
  const {
590
604
  value: storedValue,
591
605
  } = convert(
592
606
  accessor != null
593
607
  ? accessor.value
594
608
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
595
- : create(valuePath as string, this.context),
609
+ : create(valuePath as string, context),
596
610
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
597
611
  valuePath as string,
598
- this.context,
612
+ context,
599
613
  )
600
614
  const value = fieldOverride != null
601
615
  ? fieldOverride[0]
@@ -605,13 +619,13 @@ export abstract class FormModel<
605
619
  if (ignoreDefaultValue) {
606
620
  const {
607
621
  value: defaultDisplayValue,
608
- } = convert(create(valuePath, this.context), valuePath, this.context)
622
+ } = convert(create(valuePath, context), valuePath, context)
609
623
  if (defaultDisplayValue === value) {
610
624
  return true
611
625
  }
612
626
  }
613
627
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
614
- const conversion = revert(value, valuePath as string, this.context)
628
+ const conversion = revert(value, valuePath as string, context)
615
629
  return runInAction(() => {
616
630
  switch (conversion.type) {
617
631
  case UnreliableFieldConversionType.Failure:
@@ -662,16 +676,18 @@ export abstract class FormModel<
662
676
  return success
663
677
  }
664
678
  const fieldOverride = this.fieldOverrides[adapterPath]
679
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
680
+ const context = this.toContext(this.value, valuePath as keyof ValuePathsToAdapters)
665
681
  const {
666
682
  value: storedValue,
667
- } = convert(accessor.value, valuePath, this.context)
683
+ } = convert(accessor.value, valuePath, context)
668
684
  const value = fieldOverride != null
669
685
  ? fieldOverride[0]
670
686
  : storedValue
671
687
  // TODO more nuanced comparison
672
688
  const dirty = fieldOverride != null && fieldOverride[0] !== storedValue
673
689
 
674
- const conversion = revert(value, valuePath, this.context)
690
+ const conversion = revert(value, valuePath, context)
675
691
  switch (conversion.type) {
676
692
  case UnreliableFieldConversionType.Failure:
677
693
  this.errors[adapterPath] = conversion.error
@@ -13,7 +13,9 @@ import {
13
13
  type ValueOfType,
14
14
  type ValueToTypePathsOfType,
15
15
  } from '@strictly/define'
16
- import { type FieldAdapter } from 'core/mobx/field_adapter'
16
+ import {
17
+ type FieldAdapter,
18
+ } from 'core/mobx/field_adapter'
17
19
  import {
18
20
  adapterFromTwoWayConverter,
19
21
  identityAdapter,
@@ -27,7 +29,9 @@ import { IntegerToStringConverter } from 'field_converters/integer_to_string_con
27
29
  import { NullableToBooleanConverter } from 'field_converters/nullable_to_boolean_converter'
28
30
  import { SelectDiscriminatedUnionConverter } from 'field_converters/select_value_type_converter'
29
31
  import { prototypingFieldValueFactory } from 'field_value_factories/prototyping_field_value_factory'
30
- import { type Simplify } from 'type-fest'
32
+ import {
33
+ type Simplify,
34
+ } from 'type-fest'
31
35
  import { type Field } from 'types/field'
32
36
  import {
33
37
  UnreliableFieldConversionType,
@@ -54,9 +58,13 @@ class TestFormModel<
54
58
  {}
55
59
  >,
56
60
  > extends FormModel<T, ValueToTypePaths, TypePathsToAdapters, {}> {
57
- override toContext() {
61
+ override toContext(
62
+ value: ValueOfType<T>,
63
+ valuePath: keyof ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>,
64
+ ) {
58
65
  return {
59
- ctx: true,
66
+ value,
67
+ valuePath,
60
68
  }
61
69
  }
62
70
  }
@@ -740,10 +748,10 @@ describe('all', function () {
740
748
 
741
749
  // no longer passes context, but will pass context eventually again
742
750
  describe('passes context', function () {
743
- let contextCopy: number[]
751
+ let contextCopy: string
744
752
  beforeEach(function () {
745
753
  integerToStringAdapter.revert.mockImplementationOnce(function (_value, _path, context) {
746
- contextCopy = { ...context }
754
+ contextCopy = JSON.stringify(context)
747
755
  return {
748
756
  type: UnreliableFieldConversionType.Success,
749
757
  value: 1,
@@ -751,7 +759,7 @@ describe('all', function () {
751
759
  })
752
760
  })
753
761
 
754
- it('supplies the full, previous context when converting', function () {
762
+ it('supplies the context when converting', function () {
755
763
  model.setFieldValueAndValidate('$.2', '4')
756
764
 
757
765
  expect(integerToStringAdapter.revert).toHaveBeenCalledOnce()
@@ -759,14 +767,23 @@ describe('all', function () {
759
767
  '4',
760
768
  '$.2',
761
769
  {
762
- ctx: true,
770
+ // the supplied value isn't a copy, so it will be the model value, even
771
+ // if the value has since changed
772
+ value: model.value,
773
+ valuePath: '$.2',
763
774
  },
764
775
  )
765
776
  })
766
777
 
767
- it('supplies the context', function () {
768
- expect(contextCopy).toEqual({
769
- ctx: true,
778
+ it('supplies the correct context value at the time it is being checked', function () {
779
+ // the copy will show the supplied value however
780
+ expect(JSON.parse(contextCopy)).toEqual({
781
+ value: [
782
+ 1,
783
+ 3,
784
+ 7,
785
+ ],
786
+ valuePath: '$.2',
770
787
  })
771
788
  })
772
789
  })
@@ -6,7 +6,7 @@ import {
6
6
  } from './form_model'
7
7
 
8
8
  /**
9
- * Used to extract the supported value paths from a presenter
9
+ * Used to extract the supported value paths from a model
10
10
  */
11
11
  export type ValuePathsOfModel<
12
12
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -22,7 +22,7 @@ export type ValuePathsOfModel<
22
22
 
23
23
  /**
24
24
  * Used to extract the render type (so the value that is passed to the view) of a given value path
25
- * from a presenter
25
+ * from a model
26
26
  */
27
27
  export type ToValueOfModelValuePath<
28
28
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -38,9 +38,9 @@ export type ToValueOfModelValuePath<
38
38
  : never
39
39
 
40
40
  /**
41
- * Extracts the form fields from the presenter. The recommended way is to
41
+ * Extracts the form fields from a form model. The recommended way is to
42
42
  * define the form fields explicitly and use that type to enforce the types
43
- * of your converters, but generating the FormFields from your presenter
43
+ * of your converters, but generating the FormFields from your model
44
44
  * is less typing, albeit at the cost of potentially getting type errors
45
45
  * reported a long way away from the source
46
46
  */