@strictly/react-form 0.0.9 → 0.0.11

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 (60) hide show
  1. package/.out/core/mobx/field_adapter_builder.js +18 -6
  2. package/.out/core/mobx/form_presenter.d.ts +5 -5
  3. package/.out/core/mobx/form_presenter.js +232 -127
  4. package/.out/core/mobx/hooks.d.ts +24 -4
  5. package/.out/core/mobx/hooks.js +26 -5
  6. package/.out/core/mobx/merge_field_adapters_with_validators.js +1 -5
  7. package/.out/core/mobx/specs/fixtures.js +2 -1
  8. package/.out/core/mobx/specs/form_presenter.tests.js +16 -8
  9. package/.out/core/mobx/specs/sub_form_field_adapters.tests.js +2 -1
  10. package/.out/core/mobx/sub_form_field_adapters.d.ts +2 -2
  11. package/.out/field_converters/integer_to_string_converter.js +12 -4
  12. package/.out/field_converters/maybe_identity_converter.js +12 -4
  13. package/.out/field_converters/nullable_to_boolean_converter.js +24 -7
  14. package/.out/field_converters/select_value_type_converter.js +36 -12
  15. package/.out/mantine/create_checkbox.js +8 -4
  16. package/.out/mantine/create_fields_view.d.ts +9 -1
  17. package/.out/mantine/create_fields_view.js +20 -5
  18. package/.out/mantine/create_form.js +1 -1
  19. package/.out/mantine/create_radio_group.js +8 -4
  20. package/.out/mantine/create_text_input.js +8 -4
  21. package/.out/mantine/create_value_input.js +8 -4
  22. package/.out/mantine/hooks.d.ts +2 -1
  23. package/.out/mantine/hooks.js +219 -93
  24. package/.out/mantine/specs/checkbox_hooks.stories.js +13 -1
  25. package/.out/mantine/specs/checkbox_hooks.tests.js +22 -9
  26. package/.out/mantine/specs/create_fields_view.tests.d.ts +1 -0
  27. package/.out/mantine/specs/create_fields_view.tests.js +17 -0
  28. package/.out/mantine/specs/fields_view_hooks.stories.d.ts +6 -2
  29. package/.out/mantine/specs/fields_view_hooks.stories.js +39 -7
  30. package/.out/mantine/specs/fields_view_hooks.tests.js +30 -1
  31. package/.out/mantine/specs/radio_group_hooks.stories.js +13 -1
  32. package/.out/mantine/specs/radio_group_hooks.tests.js +23 -10
  33. package/.out/mantine/specs/select_hooks.stories.js +13 -1
  34. package/.out/mantine/specs/text_input_hooks.stories.js +13 -1
  35. package/.out/mantine/specs/text_input_hooks.tests.js +18 -7
  36. package/.out/mantine/specs/value_input_hooks.stories.js +14 -2
  37. package/.out/tsconfig.tsbuildinfo +1 -1
  38. package/.out/tsup.config.js +2 -9
  39. package/.out/types/merge_validators.js +1 -4
  40. package/.out/util/partial.js +5 -5
  41. package/.out/vitest.workspace.js +2 -10
  42. package/.turbo/turbo-build.log +9 -9
  43. package/.turbo/turbo-check-types.log +1 -1
  44. package/.turbo/turbo-release$colon$exports.log +1 -1
  45. package/core/mobx/form_presenter.ts +15 -14
  46. package/core/mobx/hooks.tsx +197 -0
  47. package/core/mobx/specs/form_presenter.tests.ts +24 -5
  48. package/core/mobx/sub_form_field_adapters.ts +14 -3
  49. package/dist/index.cjs +395 -277
  50. package/dist/index.d.cts +52 -26
  51. package/dist/index.d.ts +52 -26
  52. package/dist/index.js +398 -276
  53. package/mantine/create_fields_view.tsx +66 -31
  54. package/mantine/hooks.tsx +9 -6
  55. package/mantine/specs/__snapshots__/fields_view_hooks.tests.tsx.snap +194 -197
  56. package/mantine/specs/create_fields_view.tests.ts +29 -0
  57. package/mantine/specs/fields_view_hooks.stories.tsx +58 -15
  58. package/mantine/specs/fields_view_hooks.tests.tsx +26 -0
  59. package/package.json +1 -1
  60. package/core/mobx/hooks.ts +0 -112
@@ -5,13 +5,25 @@ import { TrimmingStringConverter } from 'field_converters/trimming_string_conver
5
5
  import { prototypingFieldValueFactory } from 'field_value_factories/prototyping_field_value_factory';
6
6
  import { UnreliableFieldConversionType, } from 'types/field_converters';
7
7
  class FieldAdapterBuilder {
8
- convert;
9
- create;
10
- revert;
11
8
  constructor(convert, create, revert) {
12
- this.convert = convert;
13
- this.create = create;
14
- this.revert = revert;
9
+ Object.defineProperty(this, "convert", {
10
+ enumerable: true,
11
+ configurable: true,
12
+ writable: true,
13
+ value: convert
14
+ });
15
+ Object.defineProperty(this, "create", {
16
+ enumerable: true,
17
+ configurable: true,
18
+ writable: true,
19
+ value: create
20
+ });
21
+ Object.defineProperty(this, "revert", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: revert
26
+ });
15
27
  }
16
28
  chain(converter, reverter) {
17
29
  return new FieldAdapterBuilder(chainAnnotatedFieldConverter(this.convert, converter), this.create, this.revert && reverter && chainUnreliableFieldConverter(reverter, this.revert));
@@ -20,9 +20,9 @@ type FlattenedErrors<ValuePathsToAdapters extends Readonly<Record<string, FieldA
20
20
  export type ValuePathsToAdaptersOf<TypePathsToAdapters extends Partial<Readonly<Record<string, FieldAdapter>>>, ValuePathsToTypePaths extends Readonly<Record<string, string>>> = keyof TypePathsToAdapters extends ValueOf<ValuePathsToTypePaths> ? {
21
21
  readonly [K in keyof ValuePathsToTypePaths as unknown extends TypePathsToAdapters[ValuePathsToTypePaths[K]] ? never : K]: NonNullable<TypePathsToAdapters[ValuePathsToTypePaths[K]]>;
22
22
  } : never;
23
- export declare class FormPresenter<T extends Type, ValueToTypePaths extends Readonly<Record<string, string>>, TypePathsToAdapters extends FlattenedTypePathsToAdaptersOf<FlattenedValuesOfType<T, '*'>, ValueOfType<ReadonlyTypeOfType<T>>>, ValuePathsToAdapters extends ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths> = ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>> {
23
+ export declare abstract class FormPresenter<T extends Type, ValueToTypePaths extends Readonly<Record<string, string>>, TypePathsToAdapters extends FlattenedTypePathsToAdaptersOf<FlattenedValuesOfType<T, '*'>, ValueOfType<ReadonlyTypeOfType<T>>>, ValuePathsToAdapters extends ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths> = ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>> {
24
24
  readonly type: T;
25
- private readonly adapters;
25
+ protected readonly adapters: TypePathsToAdapters;
26
26
  constructor(type: T, adapters: TypePathsToAdapters);
27
27
  private maybeGetAdapterForValuePath;
28
28
  private getAdapterForValuePath;
@@ -33,12 +33,12 @@ export declare class FormPresenter<T extends Type, ValueToTypePaths extends Read
33
33
  removeListItem<K extends keyof FlattenedListTypesOfType<T>>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, elementValuePath: `${K}.${number}`): void;
34
34
  private internalSetFieldValue;
35
35
  clearFieldError<K extends keyof ValuePathsToAdapters>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, valuePath: K): void;
36
- clearFieldValue<K extends StringKeyOf<ValuePathsToAdapters>>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, valuePath: K): void;
36
+ clearFieldValue<K extends StringKeyOf<ValueToTypePaths>>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, valuePath: K): void;
37
37
  clearAll(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, value: ValueOfType<T>): void;
38
38
  isValuePathActive<K extends keyof ValuePathsToAdapters>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, valuePath: K): boolean;
39
- validateField<K extends keyof ValuePathsToAdapters>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, valuePath: K): boolean;
39
+ validateField<K extends keyof ValuePathsToAdapters>(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>, valuePath: K, ignoreDefaultValue?: boolean): boolean;
40
40
  validateAll(model: FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>): boolean;
41
- createModel(value: ValueOfType<ReadonlyTypeOfType<T>>): FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>;
41
+ abstract createModel(value: ValueOfType<ReadonlyTypeOfType<T>>): FormModel<T, ValueToTypePaths, TypePathsToAdapters, ValuePathsToAdapters>;
42
42
  }
43
43
  export declare class FormModel<T extends Type, ValueToTypePaths extends Readonly<Record<string, string>>, TypePathsToAdapters extends FlattenedTypePathsToAdaptersOf<FlattenedValuesOfType<T, '*'>, ValueOfType<ReadonlyTypeOfType<T>>>, ValuePathsToAdapters extends ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths> = ValuePathsToAdaptersOf<TypePathsToAdapters, ValueToTypePaths>> {
44
44
  private readonly type;
@@ -1,13 +1,66 @@
1
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
2
+ var useValue = arguments.length > 2;
3
+ for (var i = 0; i < initializers.length; i++) {
4
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
5
+ }
6
+ return useValue ? value : void 0;
7
+ };
8
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
9
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
10
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
11
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
12
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
13
+ var _, done = false;
14
+ for (var i = decorators.length - 1; i >= 0; i--) {
15
+ var context = {};
16
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
17
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
18
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
19
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
20
+ if (kind === "accessor") {
21
+ if (result === void 0) continue;
22
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
23
+ if (_ = accept(result.get)) descriptor.get = _;
24
+ if (_ = accept(result.set)) descriptor.set = _;
25
+ if (_ = accept(result.init)) initializers.unshift(_);
26
+ }
27
+ else if (_ = accept(result)) {
28
+ if (kind === "field") initializers.unshift(_);
29
+ else descriptor[key] = _;
30
+ }
31
+ }
32
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
33
+ done = true;
34
+ };
35
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
36
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
37
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
38
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
39
+ };
40
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
41
+ if (kind === "m") throw new TypeError("Private method is not writable");
42
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
43
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
44
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
45
+ };
1
46
  import { assertExists, assertExistsAndReturn, assertState, checkValidNumber, map, toArray, UnreachableError, } from '@strictly/base';
2
47
  import { flattenAccessorsOfType, flattenTypesOfType, flattenValuesOfType, flattenValueTo, jsonPathPop, mobxCopy, valuePathToTypePath, } from '@strictly/define';
3
48
  import { computed, observable, runInAction, } from 'mobx';
4
49
  import { UnreliableFieldConversionType, } from 'types/field_converters';
5
50
  export class FormPresenter {
6
- type;
7
- adapters;
8
51
  constructor(type, adapters) {
9
- this.type = type;
10
- this.adapters = adapters;
52
+ Object.defineProperty(this, "type", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: type
57
+ });
58
+ Object.defineProperty(this, "adapters", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: adapters
63
+ });
11
64
  }
12
65
  maybeGetAdapterForValuePath(valuePath) {
13
66
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
@@ -34,7 +87,7 @@ export class FormPresenter {
34
87
  const listValuePath = valuePath;
35
88
  const accessor = model.accessors[valuePath];
36
89
  const listTypePath = this.typePath(valuePath);
37
- const definedIndex = index ?? accessor.value.length;
90
+ const definedIndex = index !== null && index !== void 0 ? index : accessor.value.length;
38
91
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
92
  const elementTypePath = `${listTypePath}.*`;
40
93
  const elementAdapter = assertExistsAndReturn(this.adapters[elementTypePath], 'no adapter specified for list {} ({})', elementTypePath, valuePath);
@@ -165,7 +218,7 @@ export class FormPresenter {
165
218
  return false;
166
219
  case UnreliableFieldConversionType.Success:
167
220
  delete model.errors[valuePath];
168
- accessor?.set(conversion.value);
221
+ accessor === null || accessor === void 0 ? void 0 : accessor.set(conversion.value);
169
222
  return true;
170
223
  default:
171
224
  throw new UnreachableError(conversion);
@@ -188,8 +241,7 @@ export class FormPresenter {
188
241
  return;
189
242
  }
190
243
  const { convert, create, } = adapter;
191
- const accessor = model.accessors[valuePath];
192
- const value = accessor == null ? create(valuePath, model.value) : accessor.value;
244
+ const value = create(valuePath, model.value);
193
245
  const { value: displayValue, } = convert(value, valuePath, model.value);
194
246
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
195
247
  const key = valuePath;
@@ -211,7 +263,7 @@ export class FormPresenter {
211
263
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
212
264
  return keys.has(valuePath);
213
265
  }
214
- validateField(model, valuePath) {
266
+ validateField(model, valuePath, ignoreDefaultValue = false) {
215
267
  const { convert, revert, create, } = this.getAdapterForValuePath(valuePath);
216
268
  const fieldOverride = model.fieldOverrides[valuePath];
217
269
  const accessor = model.getAccessorForValuePath(valuePath);
@@ -226,6 +278,12 @@ export class FormPresenter {
226
278
  : storedValue;
227
279
  const dirty = storedValue !== value;
228
280
  assertExists(revert, 'changing field directly not supported {}', valuePath);
281
+ if (ignoreDefaultValue) {
282
+ const { value: defaultDisplayValue, } = convert(create(valuePath, model.value), valuePath, model.value);
283
+ if (defaultDisplayValue === value) {
284
+ return true;
285
+ }
286
+ }
229
287
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
230
288
  const conversion = revert(value, valuePath, model.value);
231
289
  return runInAction(function () {
@@ -293,128 +351,175 @@ export class FormPresenter {
293
351
  }, true);
294
352
  });
295
353
  }
296
- createModel(value) {
297
- return new FormModel(this.type, value, this.adapters);
298
- }
299
354
  }
300
- export class FormModel {
301
- type;
302
- adapters;
303
- @observable.ref
304
- accessor value;
305
- @observable.shallow
306
- accessor fieldOverrides;
307
- @observable.shallow
308
- accessor errors = {};
309
- flattenedTypeDefs;
310
- constructor(type, value, adapters) {
311
- this.type = type;
312
- this.adapters = adapters;
313
- this.value = mobxCopy(type, value);
314
- this.flattenedTypeDefs = flattenTypesOfType(type);
315
- // pre-populate field overrides for consistent behavior when default information is overwritten
316
- // then returned to
317
- const conversions = flattenValueTo(type, this.value, () => { }, (_t, value, _setter, typePath, valuePath) => {
318
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
319
- const adapter = this.adapters[typePath];
320
- if (adapter == null) {
321
- return;
355
+ let FormModel = (() => {
356
+ var _a, _FormModel_value_accessor_storage, _FormModel_fieldOverrides_accessor_storage, _FormModel_errors_accessor_storage;
357
+ var _b, _c, _d;
358
+ let _instanceExtraInitializers = [];
359
+ let _value_decorators;
360
+ let _value_initializers = [];
361
+ let _value_extraInitializers = [];
362
+ let _fieldOverrides_decorators;
363
+ let _fieldOverrides_initializers = [];
364
+ let _fieldOverrides_extraInitializers = [];
365
+ let _errors_decorators;
366
+ let _errors_initializers = [];
367
+ let _errors_extraInitializers = [];
368
+ let _get_fields_decorators;
369
+ let _get_knownFields_decorators;
370
+ let _get_accessors_decorators;
371
+ return _a = class FormModel {
372
+ get value() { return __classPrivateFieldGet(this, _FormModel_value_accessor_storage, "f"); }
373
+ set value(value) { __classPrivateFieldSet(this, _FormModel_value_accessor_storage, value, "f"); }
374
+ get fieldOverrides() { return __classPrivateFieldGet(this, _FormModel_fieldOverrides_accessor_storage, "f"); }
375
+ set fieldOverrides(value) { __classPrivateFieldSet(this, _FormModel_fieldOverrides_accessor_storage, value, "f"); }
376
+ get errors() { return __classPrivateFieldGet(this, _FormModel_errors_accessor_storage, "f"); }
377
+ set errors(value) { __classPrivateFieldSet(this, _FormModel_errors_accessor_storage, value, "f"); }
378
+ constructor(type, value, adapters) {
379
+ Object.defineProperty(this, "type", {
380
+ enumerable: true,
381
+ configurable: true,
382
+ writable: true,
383
+ value: (__runInitializers(this, _instanceExtraInitializers), type)
384
+ });
385
+ Object.defineProperty(this, "adapters", {
386
+ enumerable: true,
387
+ configurable: true,
388
+ writable: true,
389
+ value: adapters
390
+ });
391
+ _FormModel_value_accessor_storage.set(this, __runInitializers(this, _value_initializers, void 0));
392
+ _FormModel_fieldOverrides_accessor_storage.set(this, (__runInitializers(this, _value_extraInitializers), __runInitializers(this, _fieldOverrides_initializers, void 0)));
393
+ _FormModel_errors_accessor_storage.set(this, (__runInitializers(this, _fieldOverrides_extraInitializers), __runInitializers(this, _errors_initializers, {})));
394
+ Object.defineProperty(this, "flattenedTypeDefs", {
395
+ enumerable: true,
396
+ configurable: true,
397
+ writable: true,
398
+ value: __runInitializers(this, _errors_extraInitializers)
399
+ });
400
+ this.value = mobxCopy(type, value);
401
+ this.flattenedTypeDefs = flattenTypesOfType(type);
402
+ // pre-populate field overrides for consistent behavior when default information is overwritten
403
+ // then returned to
404
+ const conversions = flattenValueTo(type, this.value, () => { }, (_t, value, _setter, typePath, valuePath) => {
405
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
406
+ const adapter = this.adapters[typePath];
407
+ if (adapter == null) {
408
+ return;
409
+ }
410
+ const { convert, revert, } = adapter;
411
+ if (revert == null) {
412
+ // no need to store a temporary value if the value cannot be written back
413
+ return;
414
+ }
415
+ return convert(value, valuePath, this.value);
416
+ });
417
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
418
+ this.fieldOverrides = map(conversions, function (_k, v) {
419
+ return v && [v.value];
420
+ });
322
421
  }
323
- const { convert, revert, } = adapter;
324
- if (revert == null) {
325
- // no need to store a temporary value if the value cannot be written back
326
- return;
422
+ get fields() {
423
+ return new Proxy(this.knownFields, {
424
+ get: (target, prop) => {
425
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
426
+ const field = target[prop];
427
+ if (field != null) {
428
+ return field;
429
+ }
430
+ if (typeof prop === 'string') {
431
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
432
+ return this.maybeSynthesizeFieldByValuePath(prop);
433
+ }
434
+ },
435
+ });
327
436
  }
328
- return convert(value, valuePath, this.value);
329
- });
330
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
331
- this.fieldOverrides = map(conversions, function (_k, v) {
332
- return v && [v.value];
333
- });
334
- }
335
- @computed
336
- get fields() {
337
- return new Proxy(this.knownFields, {
338
- get: (target, prop) => {
339
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
340
- const field = target[prop];
341
- if (field != null) {
342
- return field;
343
- }
344
- if (typeof prop === 'string') {
437
+ get knownFields() {
438
+ return flattenValueTo(this.type, this.value, () => { },
439
+ // TODO swap these to valuePath, typePath in flatten
440
+ (_t, _v, _setter, typePath, valuePath) => {
441
+ return this.synthesizeFieldByPaths(
442
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
443
+ valuePath,
345
444
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
346
- return this.maybeSynthesizeFieldByValuePath(prop);
445
+ typePath);
446
+ });
447
+ }
448
+ maybeSynthesizeFieldByValuePath(valuePath) {
449
+ let typePath;
450
+ try {
451
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
452
+ typePath = valuePathToTypePath(this.type,
453
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
454
+ valuePath, true);
347
455
  }
348
- },
349
- });
350
- }
351
- @computed
352
- get knownFields() {
353
- return flattenValueTo(this.type, this.value, () => { },
354
- // TODO swap these to valuePath, typePath in flatten
355
- (_t, _v, _setter, typePath, valuePath) => {
356
- return this.synthesizeFieldByPaths(
357
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
358
- valuePath,
359
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
360
- typePath);
361
- });
362
- }
363
- maybeSynthesizeFieldByValuePath(valuePath) {
364
- let typePath;
365
- try {
366
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
367
- typePath = valuePathToTypePath(this.type,
368
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
369
- valuePath, true);
370
- }
371
- catch (e) {
372
- // TODO make jsonValuePathToTypePath return null in the event of an invalid
373
- // value path instead of throwing an exception
374
- // assume that the path was invalid
375
- return;
376
- }
377
- return this.synthesizeFieldByPaths(valuePath, typePath);
378
- }
379
- synthesizeFieldByPaths(valuePath, typePath) {
380
- const adapter = this.adapters[typePath];
381
- if (adapter == null) {
382
- // invalid path, which can happen
383
- return;
384
- }
385
- const { convert, create, } = adapter;
386
- const fieldOverride = this.fieldOverrides[valuePath];
387
- const accessor = this.getAccessorForValuePath(valuePath);
388
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
389
- const fieldTypeDef = this.flattenedTypeDefs[typePath];
390
- const { value, required, readonly, } = convert(accessor != null
391
- ? accessor.value
392
- : fieldTypeDef != null
393
- ? mobxCopy(fieldTypeDef,
456
+ catch (e) {
457
+ // TODO make jsonValuePathToTypePath return null in the event of an invalid
458
+ // value path instead of throwing an exception
459
+ // assume that the path was invalid
460
+ return;
461
+ }
462
+ return this.synthesizeFieldByPaths(valuePath, typePath);
463
+ }
464
+ synthesizeFieldByPaths(valuePath, typePath) {
465
+ const adapter = this.adapters[typePath];
466
+ if (adapter == null) {
467
+ // invalid path, which can happen
468
+ return;
469
+ }
470
+ const { convert, create, } = adapter;
471
+ const fieldOverride = this.fieldOverrides[valuePath];
472
+ const accessor = this.getAccessorForValuePath(valuePath);
394
473
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
395
- create(valuePath, this.value))
396
- // fake values can't be copied
474
+ const fieldTypeDef = this.flattenedTypeDefs[typePath];
475
+ const { value, required, readonly, } = convert(accessor != null
476
+ ? accessor.value
477
+ : fieldTypeDef != null
478
+ ? mobxCopy(fieldTypeDef,
479
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
480
+ create(valuePath, this.value))
481
+ // fake values can't be copied
482
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
483
+ : create(valuePath, this.value),
397
484
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
398
- : create(valuePath, this.value),
399
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
400
- valuePath, this.value);
401
- const error = this.errors[valuePath];
402
- return {
403
- value: fieldOverride != null ? fieldOverride[0] : value,
404
- error,
405
- readonly,
406
- required,
407
- };
408
- }
409
- getAccessorForValuePath(valuePath) {
410
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
411
- return this.accessors[valuePath];
412
- }
413
- @computed
414
- // should only be referenced internally, so loosely typed
415
- get accessors() {
416
- return flattenAccessorsOfType(this.type, this.value, (value) => {
417
- this.value = mobxCopy(this.type, value);
418
- });
419
- }
420
- }
485
+ valuePath, this.value);
486
+ const error = this.errors[valuePath];
487
+ return {
488
+ value: fieldOverride != null ? fieldOverride[0] : value,
489
+ error,
490
+ readonly,
491
+ required,
492
+ };
493
+ }
494
+ getAccessorForValuePath(valuePath) {
495
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
496
+ return this.accessors[valuePath];
497
+ }
498
+ get accessors() {
499
+ return flattenAccessorsOfType(this.type, this.value, (value) => {
500
+ this.value = mobxCopy(this.type, value);
501
+ });
502
+ }
503
+ },
504
+ _FormModel_value_accessor_storage = new WeakMap(),
505
+ _FormModel_fieldOverrides_accessor_storage = new WeakMap(),
506
+ _FormModel_errors_accessor_storage = new WeakMap(),
507
+ (() => {
508
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
509
+ _value_decorators = [(_b = observable).ref.bind(_b)];
510
+ _fieldOverrides_decorators = [(_c = observable).shallow.bind(_c)];
511
+ _errors_decorators = [(_d = observable).shallow.bind(_d)];
512
+ _get_fields_decorators = [computed];
513
+ _get_knownFields_decorators = [computed];
514
+ _get_accessors_decorators = [computed];
515
+ __esDecorate(_a, null, _value_decorators, { kind: "accessor", name: "value", static: false, private: false, access: { has: obj => "value" in obj, get: obj => obj.value, set: (obj, value) => { obj.value = value; } }, metadata: _metadata }, _value_initializers, _value_extraInitializers);
516
+ __esDecorate(_a, null, _fieldOverrides_decorators, { kind: "accessor", name: "fieldOverrides", static: false, private: false, access: { has: obj => "fieldOverrides" in obj, get: obj => obj.fieldOverrides, set: (obj, value) => { obj.fieldOverrides = value; } }, metadata: _metadata }, _fieldOverrides_initializers, _fieldOverrides_extraInitializers);
517
+ __esDecorate(_a, null, _errors_decorators, { kind: "accessor", name: "errors", static: false, private: false, access: { has: obj => "errors" in obj, get: obj => obj.errors, set: (obj, value) => { obj.errors = value; } }, metadata: _metadata }, _errors_initializers, _errors_extraInitializers);
518
+ __esDecorate(_a, null, _get_fields_decorators, { kind: "getter", name: "fields", static: false, private: false, access: { has: obj => "fields" in obj, get: obj => obj.fields }, metadata: _metadata }, null, _instanceExtraInitializers);
519
+ __esDecorate(_a, null, _get_knownFields_decorators, { kind: "getter", name: "knownFields", static: false, private: false, access: { has: obj => "knownFields" in obj, get: obj => obj.knownFields }, metadata: _metadata }, null, _instanceExtraInitializers);
520
+ __esDecorate(_a, null, _get_accessors_decorators, { kind: "getter", name: "accessors", static: false, private: false, access: { has: obj => "accessors" in obj, get: obj => obj.accessors }, metadata: _metadata }, null, _instanceExtraInitializers);
521
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
522
+ })(),
523
+ _a;
524
+ })();
525
+ export { FormModel };
@@ -1,14 +1,34 @@
1
1
  import { type ReadonlyTypeOfType, type ValueOfType } from '@strictly/define';
2
2
  import { type FieldsViewProps } from 'core/props';
3
+ import { type ComponentType } from 'react';
4
+ import { type UnsafePartialComponent } from 'util/partial';
3
5
  import { type FormPresenter } from './form_presenter';
4
- import { type ValuePathsOfPresenter } from './types';
6
+ import { type FormFieldsOfPresenter, type ValuePathsOfPresenter } from './types';
5
7
  type ValueOfPresenter<P extends FormPresenter<any, any, any, any>> = P extends FormPresenter<infer T, any, any, any> ? ValueOfType<ReadonlyTypeOfType<T>> : never;
6
8
  type ModelOfPresenter<P extends FormPresenter<any, any, any, any>> = ReturnType<P['createModel']>;
7
- export declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>>(presenter: P, value: ValueOfPresenter<P>, { onValidFieldSubmit, onValidFormSubmit, }?: {
9
+ export declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>, C extends ComponentType<FieldsViewProps<F>>, F extends FormFieldsOfPresenter<P> = FormFieldsOfPresenter<P>>(presenter: P, value: ValueOfPresenter<P>, options?: {
8
10
  onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void;
9
11
  onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void;
10
12
  }): {
11
13
  model: ModelOfPresenter<P>;
12
- onFormSubmit?: () => void;
13
- } & Omit<FieldsViewProps<ModelOfPresenter<P>['fields']>, 'fields'>;
14
+ FormFields?: UnsafePartialComponent<C, FieldsViewProps<F>>;
15
+ onFormSubmit: () => void;
16
+ onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
17
+ onFieldFocus?(this: void, key: keyof F): void;
18
+ onFieldBlur?(this: void, key: keyof F): void;
19
+ onFieldSubmit?(this: void, key: keyof F): boolean | void;
20
+ };
21
+ export declare function useDefaultMobxFormHooks<P extends FormPresenter<any, any, any, any>, C extends ComponentType<FieldsViewProps<F>>, F extends FormFieldsOfPresenter<P> = FormFieldsOfPresenter<P>>(presenter: P, value: ValueOfPresenter<P>, options: {
22
+ onValidFieldSubmit?: <Path extends ValuePathsOfPresenter<P>>(model: ModelOfPresenter<P>, valuePath: Path) => void;
23
+ onValidFormSubmit?: (model: ModelOfPresenter<P>, value: ValueOfPresenter<P>) => void;
24
+ FormFieldsView: C;
25
+ }): {
26
+ model: ModelOfPresenter<P>;
27
+ FormFields: UnsafePartialComponent<C, FieldsViewProps<F>>;
28
+ onFormSubmit: () => void;
29
+ onFieldValueChange<K extends keyof F>(this: void, key: K, value: F[K]['value']): void;
30
+ onFieldFocus?(this: void, key: keyof F): void;
31
+ onFieldBlur?(this: void, key: keyof F): void;
32
+ onFieldSubmit?(this: void, key: keyof F): boolean | void;
33
+ };
14
34
  export {};
@@ -1,6 +1,6 @@
1
1
  import { useCallback, useMemo, } from 'react';
2
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
- export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit, onValidFormSubmit, } = {}) {
2
+ import { createUnsafePartialObserverComponent, } from 'util/partial';
3
+ export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit, onValidFormSubmit, FormFieldsView, } = {}) {
4
4
  const model = useMemo(function () {
5
5
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
6
6
  return presenter.createModel(value);
@@ -17,7 +17,7 @@ export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit,
17
17
  ]);
18
18
  const onFieldSubmit = useCallback(function (valuePath) {
19
19
  if (presenter.validateField(model, valuePath)) {
20
- onValidFieldSubmit?.(model, valuePath);
20
+ onValidFieldSubmit === null || onValidFieldSubmit === void 0 ? void 0 : onValidFieldSubmit(model, valuePath);
21
21
  }
22
22
  return false;
23
23
  }, [
@@ -31,7 +31,7 @@ export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit,
31
31
  // TODO debounce?
32
32
  setTimeout(function () {
33
33
  if (presenter.isValuePathActive(model, path)) {
34
- presenter.validateField(model, path);
34
+ presenter.validateField(model, path, true);
35
35
  }
36
36
  }, 100);
37
37
  }, [
@@ -40,18 +40,39 @@ export function useDefaultMobxFormHooks(presenter, value, { onValidFieldSubmit,
40
40
  ]);
41
41
  const onFormSubmit = useCallback(function () {
42
42
  if (presenter.validateAll(model)) {
43
- onValidFormSubmit?.(model, model.value);
43
+ onValidFormSubmit === null || onValidFormSubmit === void 0 ? void 0 : onValidFormSubmit(model, model.value);
44
44
  }
45
45
  }, [
46
46
  presenter,
47
47
  model,
48
48
  onValidFormSubmit,
49
49
  ]);
50
+ const FormFields = useMemo(() => {
51
+ if (FormFieldsView == null) {
52
+ return undefined;
53
+ }
54
+ return createUnsafePartialObserverComponent(FormFieldsView, () => {
55
+ return {
56
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
57
+ fields: model.fields,
58
+ onFieldBlur,
59
+ onFieldSubmit,
60
+ onFieldValueChange,
61
+ };
62
+ });
63
+ }, [
64
+ model,
65
+ FormFieldsView,
66
+ onFieldBlur,
67
+ onFieldSubmit,
68
+ onFieldValueChange,
69
+ ]);
50
70
  return {
51
71
  model,
52
72
  onFieldValueChange,
53
73
  onFieldSubmit,
54
74
  onFieldBlur,
55
75
  onFormSubmit,
76
+ FormFields,
56
77
  };
57
78
  }
@@ -35,11 +35,7 @@ export function mergeAdaptersWithValidators(adapters, validators) {
35
35
  readonly: readonly1 || readonly2,
36
36
  };
37
37
  }
38
- acc[key] = {
39
- ...adapter,
40
- convert,
41
- revert: adapter.revert && revert,
42
- };
38
+ acc[key] = Object.assign(Object.assign({}, adapter), { convert, revert: adapter.revert && revert });
43
39
  return acc;
44
40
  }, {});
45
41
  }
@@ -3,9 +3,10 @@ export function createMockedAdapter(_original) {
3
3
  return mock();
4
4
  }
5
5
  export function resetMockAdapter({ convert, revert, create, }, mockedAdapter) {
6
+ var _a;
6
7
  mockReset(mockedAdapter);
7
8
  if (revert) {
8
- mockedAdapter.revert?.mockImplementation(revert);
9
+ (_a = mockedAdapter.revert) === null || _a === void 0 ? void 0 : _a.mockImplementation(revert);
9
10
  }
10
11
  mockedAdapter.convert.mockImplementation(convert);
11
12
  mockedAdapter.create.mockImplementation(create);