@strictly/react-form 0.0.3 → 0.0.5

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 (50) hide show
  1. package/.out/.storybook/main.js +3 -1
  2. package/.out/core/mobx/field_adapter_builder.d.ts +1 -1
  3. package/.out/core/mobx/field_adapter_builder.js +1 -2
  4. package/.out/core/mobx/specs/sub_form_field_adapters.tests.d.ts +1 -0
  5. package/.out/core/mobx/specs/sub_form_field_adapters.tests.js +41 -0
  6. package/.out/core/mobx/sub_form_field_adapters.d.ts +7 -0
  7. package/.out/core/mobx/sub_form_field_adapters.js +8 -0
  8. package/.out/index.d.ts +1 -0
  9. package/.out/index.js +1 -0
  10. package/.out/mantine/create_list.d.ts +5 -4
  11. package/.out/mantine/create_list.js +4 -2
  12. package/.out/mantine/create_sub_form.d.ts +6 -0
  13. package/.out/mantine/create_sub_form.js +40 -0
  14. package/.out/mantine/hooks.d.ts +5 -2
  15. package/.out/mantine/hooks.js +9 -0
  16. package/.out/mantine/specs/list_hooks.stories.js +6 -6
  17. package/.out/mantine/specs/sub_form_hooks.stories.d.ts +15 -0
  18. package/.out/mantine/specs/sub_form_hooks.stories.js +107 -0
  19. package/.out/tsconfig.tsbuildinfo +1 -1
  20. package/.out/types/specs/list_fields_of_fields.tests.d.ts +1 -0
  21. package/.out/types/specs/list_fields_of_fields.tests.js +12 -0
  22. package/.out/types/specs/sub_form_fields.tests.d.ts +1 -0
  23. package/.out/types/specs/sub_form_fields.tests.js +12 -0
  24. package/.out/types/sub_form_fields.d.ts +7 -0
  25. package/.out/types/sub_form_fields.js +1 -0
  26. package/.storybook/main.ts +3 -1
  27. package/.turbo/turbo-build.log +8 -8
  28. package/.turbo/turbo-check-types.log +1 -1
  29. package/.turbo/turbo-release$colon$exports.log +1 -1
  30. package/core/mobx/field_adapter_builder.ts +3 -4
  31. package/core/mobx/specs/sub_form_field_adapters.tests.ts +59 -0
  32. package/core/mobx/sub_form_field_adapters.ts +21 -0
  33. package/dist/index.cjs +86 -24
  34. package/dist/index.d.cts +22 -8
  35. package/dist/index.d.ts +22 -8
  36. package/dist/index.js +85 -24
  37. package/index.ts +1 -0
  38. package/mantine/create_list.tsx +10 -4
  39. package/mantine/create_sub_form.tsx +70 -0
  40. package/mantine/hooks.tsx +29 -5
  41. package/mantine/specs/__snapshots__/list_hooks.tests.tsx.snap +56 -8
  42. package/mantine/specs/list_hooks.stories.tsx +16 -6
  43. package/mantine/specs/sub_form_hooks.stories.tsx +135 -0
  44. package/package.json +1 -1
  45. package/types/specs/list_fields_of_fields.tests.ts +29 -0
  46. package/types/specs/sub_form_fields.tests.ts +22 -0
  47. package/types/sub_form_fields.ts +7 -0
  48. package/.out/field_converters/list_converter.d.ts +0 -2
  49. package/.out/field_converters/list_converter.js +0 -13
  50. package/field_converters/list_converter.ts +0 -20
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('ListFieldsOfFields', () => {
2
+ it('matches the expected type of an empty set of fields', () => {
3
+ expectTypeOf().toEqualTypeOf();
4
+ });
5
+ it('matches the expected type of a set of fields containing a single list', () => {
6
+ expectTypeOf().toEqualTypeOf();
7
+ });
8
+ it('matches the expected type of a set of fields containing a multiple fields, including a list', () => {
9
+ expectTypeOf().toEqualTypeOf();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,12 @@
1
+ describe('SubFormFields', () => {
2
+ it('works on single field', () => {
3
+ expectTypeOf().toEqualTypeOf();
4
+ });
5
+ it('works on more two fields', () => {
6
+ expectTypeOf().toEqualTypeOf();
7
+ });
8
+ it('works on subfields', () => {
9
+ expectTypeOf().toEqualTypeOf();
10
+ });
11
+ });
12
+ export {};
@@ -0,0 +1,7 @@
1
+ import { type StringConcatOf } from '@strictly/base';
2
+ import { type Fields } from './field';
3
+ export type SubFormFields<F extends Fields, P extends keyof F> = P extends string ? {
4
+ [K in keyof F as K extends StringConcatOf<`${P}.`, infer S> ? `$.${S}` : never]: F[K];
5
+ } & {
6
+ $: F[P];
7
+ } : never;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,10 +1,12 @@
1
1
  /* eslint-env node */
2
2
  import { type StorybookConfig } from '@storybook/react-vite'
3
+ import { createRequire } from 'module'
3
4
  import {
4
5
  dirname,
5
6
  join,
6
- } from 'path'
7
+ } from 'node:path'
7
8
 
9
+ const require = createRequire(import.meta.url)
8
10
  /**
9
11
  * This function is used to resolve the absolute path of a package.
10
12
  * It is needed in projects that use Yarn PnP or are set up within a monorepo.
@@ -7,12 +7,12 @@ $ tsup
7
7
  CLI Target: esnext
8
8
  CJS Build start
9
9
  ESM Build start
10
- CJS dist/index.cjs 44.90 KB
11
- CJS ⚡️ Build success in 113ms
12
- ESM dist/index.js 41.31 KB
13
- ESM ⚡️ Build success in 115ms
10
+ ESM dist/index.js 43.08 KB
11
+ ESM ⚡️ Build success in 117ms
12
+ CJS dist/index.cjs 46.78 KB
13
+ CJS ⚡️ Build success in 117ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 9820ms
16
- DTS dist/index.d.cts 34.05 KB
17
- DTS dist/index.d.ts 34.05 KB
18
- Done in 10.94s.
15
+ DTS ⚡️ Build success in 9983ms
16
+ DTS dist/index.d.cts 34.96 KB
17
+ DTS dist/index.d.ts 34.96 KB
18
+ Done in 11.02s.
@@ -1,3 +1,3 @@
1
1
  yarn run v1.22.22
2
2
  $ tsc
3
- Done in 7.59s.
3
+ Done in 7.64s.
@@ -1,3 +1,3 @@
1
1
  yarn run v1.22.22
2
2
  $ json -f package.json -f package.exports.json --merge > package.release.json
3
- Done in 0.11s.
3
+ Done in 0.12s.
@@ -6,7 +6,6 @@ import {
6
6
  annotatedIdentityConverter,
7
7
  unreliableIdentityConverter,
8
8
  } from 'field_converters/identity_converter'
9
- import { listConverter } from 'field_converters/list_converter'
10
9
  import { MaybeIdentityConverter } from 'field_converters/maybe_identity_converter'
11
10
  import { prototypingFieldValueFactory } from 'field_value_factories/prototyping_field_value_factory'
12
11
  import {
@@ -266,12 +265,12 @@ export function identityAdapter<
266
265
 
267
266
  export function listAdapter<
268
267
  E,
269
- K extends string,
270
268
  ValuePath extends string,
271
269
  Context,
272
270
  >() {
273
- return new FieldAdapterBuilder<readonly E[], readonly K[], never, ValuePath, Context>(
274
- listConverter<E, K, ValuePath, Context>(),
271
+ return new FieldAdapterBuilder<readonly E[], readonly E[], never, ValuePath, Context>(
272
+ annotatedIdentityConverter<readonly E[], ValuePath, Context>(false),
275
273
  prototypingFieldValueFactory<readonly E[], ValuePath, Context>([]),
274
+ unreliableIdentityConverter<readonly E[], ValuePath, Context>(),
276
275
  )
277
276
  }
@@ -0,0 +1,59 @@
1
+ import { type FieldAdapter } from 'core/mobx/field_adapter'
2
+ import {
3
+ subFormFieldAdapters,
4
+ } from 'core/mobx/sub_form_field_adapters'
5
+ import { mockDeep } from 'vitest-mock-extended'
6
+
7
+ describe('subFormFieldAdapters', () => {
8
+ const fieldAdapter1: FieldAdapter<string, boolean> = mockDeep()
9
+ const fieldAdapter2: FieldAdapter<number, boolean> = mockDeep()
10
+
11
+ describe('empty value', () => {
12
+ const adapters = subFormFieldAdapters({}, '$.a')
13
+
14
+ it('equals expected type', () => {
15
+ expectTypeOf(adapters).toEqualTypeOf<{}>()
16
+ })
17
+
18
+ it('equals expected value', () => {
19
+ expect(adapters).toEqual({})
20
+ })
21
+ })
22
+
23
+ describe('single adapter', () => {
24
+ const adapters = subFormFieldAdapters({
25
+ $: fieldAdapter1,
26
+ }, '$.a')
27
+
28
+ it('equals expected type', () => {
29
+ expectTypeOf(adapters).toEqualTypeOf<{
30
+ '$.a': FieldAdapter<string, boolean>,
31
+ }>()
32
+ })
33
+
34
+ it('equals expected value', () => {
35
+ expect(adapters).toEqual({ '$.a': fieldAdapter1 })
36
+ })
37
+ })
38
+
39
+ describe('multiple adapters', () => {
40
+ const adapters = subFormFieldAdapters({
41
+ '$.x': fieldAdapter1,
42
+ '$.y': fieldAdapter2,
43
+ }, '$.a')
44
+
45
+ it('equals expected type', () => {
46
+ expectTypeOf(adapters).toEqualTypeOf<{
47
+ '$.a.x': FieldAdapter<string, boolean>,
48
+ '$.a.y': FieldAdapter<number, boolean>,
49
+ }>()
50
+ })
51
+
52
+ it('equals expected value', () => {
53
+ expect(adapters).toEqual({
54
+ '$.a.x': fieldAdapter1,
55
+ '$.a.y': fieldAdapter2,
56
+ })
57
+ })
58
+ })
59
+ })
@@ -0,0 +1,21 @@
1
+ import { type StringConcatOf } from '@strictly/base'
2
+ import { type FieldAdapter } from './field_adapter'
3
+
4
+ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string> = {
5
+ [K in keyof SubAdapters as K extends StringConcatOf<'$', infer S> ? `${P}${S}` : never]: SubAdapters[K]
6
+ }
7
+
8
+ export function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string>(
9
+ subAdapters: SubAdapters,
10
+ prefix: P,
11
+ ): SubFormFieldAdapters<SubAdapters, P> {
12
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
13
+ return Object.entries(subAdapters).reduce<Record<string, FieldAdapter>>((acc, [
14
+ subKey,
15
+ subValue,
16
+ ]) => {
17
+ const key = subKey.replace('$', prefix)
18
+ acc[key] = subValue
19
+ return acc
20
+ }, {}) as SubFormFieldAdapters<SubAdapters, P>
21
+ }
package/dist/index.cjs CHANGED
@@ -44,6 +44,7 @@ __export(index_exports, {
44
44
  mergeFieldAdaptersWithTwoWayConverter: () => mergeFieldAdaptersWithTwoWayConverter,
45
45
  mergeValidators: () => mergeValidators,
46
46
  prototypingFieldValueFactory: () => prototypingFieldValueFactory,
47
+ subFormFieldAdapters: () => subFormFieldAdapters,
47
48
  useMantineForm: () => useMantineForm,
48
49
  usePartialComponent: () => usePartialComponent,
49
50
  usePartialObserverComponent: () => usePartialObserverComponent,
@@ -138,20 +139,6 @@ function unreliableIdentityConverter() {
138
139
  };
139
140
  }
140
141
 
141
- // field_converters/list_converter.ts
142
- function listConverter() {
143
- return function(from, valuePath) {
144
- const value = from.map(function(_v, i) {
145
- return `${valuePath}.${i}`;
146
- });
147
- return {
148
- value,
149
- required: false,
150
- readonly: false
151
- };
152
- };
153
- }
154
-
155
142
  // field_converters/maybe_identity_converter.ts
156
143
  var MaybeIdentityConverter = class {
157
144
  constructor(converter, isFrom) {
@@ -240,8 +227,9 @@ function identityAdapter(prototype, required) {
240
227
  }
241
228
  function listAdapter() {
242
229
  return new FieldAdapterBuilder(
243
- listConverter(),
244
- prototypingFieldValueFactory([])
230
+ annotatedIdentityConverter(false),
231
+ prototypingFieldValueFactory([]),
232
+ unreliableIdentityConverter()
245
233
  );
246
234
  }
247
235
 
@@ -774,6 +762,18 @@ function mergeAdaptersWithValidators(adapters, validators) {
774
762
  );
775
763
  }
776
764
 
765
+ // core/mobx/sub_form_field_adapters.ts
766
+ function subFormFieldAdapters(subAdapters, prefix) {
767
+ return Object.entries(subAdapters).reduce((acc, [
768
+ subKey,
769
+ subValue
770
+ ]) => {
771
+ const key = subKey.replace("$", prefix);
772
+ acc[key] = subValue;
773
+ return acc;
774
+ }, {});
775
+ }
776
+
777
777
  // field_converters/integer_to_string_converter.ts
778
778
  var IntegerToStringConverter = class {
779
779
  constructor(isNanError, base = 10) {
@@ -1197,17 +1197,20 @@ function createList(valuePath, List) {
1197
1197
  const propSource = () => {
1198
1198
  const values = [...this.fields[valuePath].value];
1199
1199
  return {
1200
- values
1200
+ values,
1201
+ listPath: valuePath
1201
1202
  };
1202
1203
  };
1203
1204
  return createUnsafePartialObserverComponent(List, propSource);
1204
1205
  }
1205
1206
  function DefaultList({
1206
1207
  values,
1208
+ listPath,
1207
1209
  children
1208
1210
  }) {
1209
1211
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: values.map(function(value, index) {
1210
- return children(value, index);
1212
+ const valuePath = `${listPath}.${index}`;
1213
+ return children(valuePath, value, index);
1211
1214
  }) });
1212
1215
  }
1213
1216
 
@@ -1282,8 +1285,53 @@ function createRadioGroup(valuePath, RadioGroup) {
1282
1285
  return createUnsafePartialObserverComponent(RadioGroup, propSource, ["ErrorRenderer"]);
1283
1286
  }
1284
1287
 
1285
- // mantine/create_text_input.tsx
1288
+ // mantine/create_sub_form.tsx
1289
+ var import_mobx_react2 = require("mobx-react");
1286
1290
  var import_jsx_runtime5 = require("react/jsx-runtime");
1291
+ function createSubForm(valuePath, SubForm, observableProps) {
1292
+ function toKey(subKey) {
1293
+ return subKey.replace("$", valuePath);
1294
+ }
1295
+ function toSubKey(key) {
1296
+ return key.replace(valuePath, "$");
1297
+ }
1298
+ function onFieldValueChange(subKey, value) {
1299
+ observableProps.onFieldValueChange(toKey(subKey), value);
1300
+ }
1301
+ function onFieldBlur(subKey) {
1302
+ observableProps.onFieldBlur?.(toKey(subKey));
1303
+ }
1304
+ function onFieldFocus(subKey) {
1305
+ observableProps.onFieldFocus?.(toKey(subKey));
1306
+ }
1307
+ function onFieldSubmit(subKey) {
1308
+ observableProps.onFieldSubmit?.(toKey(subKey));
1309
+ }
1310
+ return (0, import_mobx_react2.observer)(function() {
1311
+ const subFields = Object.entries(observableProps.fields).reduce((acc, [
1312
+ fieldKey,
1313
+ fieldValue
1314
+ ]) => {
1315
+ if (fieldKey.startsWith(valuePath)) {
1316
+ acc[toSubKey(fieldKey)] = fieldValue;
1317
+ }
1318
+ return acc;
1319
+ }, {});
1320
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1321
+ SubForm,
1322
+ {
1323
+ fields: subFields,
1324
+ onFieldBlur,
1325
+ onFieldFocus,
1326
+ onFieldSubmit,
1327
+ onFieldValueChange
1328
+ }
1329
+ );
1330
+ });
1331
+ }
1332
+
1333
+ // mantine/create_text_input.tsx
1334
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1287
1335
  function createTextInput(valuePath, TextInput) {
1288
1336
  const onChange = (e) => {
1289
1337
  this.onFieldValueChange?.(valuePath, e.target.value);
@@ -1317,7 +1365,7 @@ function createTextInput(valuePath, TextInput) {
1317
1365
  value,
1318
1366
  disabled: readonly,
1319
1367
  required,
1320
- error: error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ErrorRenderer, { error }),
1368
+ error: error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ErrorRenderer, { error }),
1321
1369
  onChange,
1322
1370
  onFocus,
1323
1371
  onBlur,
@@ -1332,7 +1380,7 @@ function createTextInput(valuePath, TextInput) {
1332
1380
  }
1333
1381
 
1334
1382
  // mantine/create_value_input.tsx
1335
- var import_jsx_runtime6 = require("react/jsx-runtime");
1383
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1336
1384
  function createValueInput(valuePath, ValueInput) {
1337
1385
  const onChange = (value) => {
1338
1386
  this.onFieldValueChange?.(valuePath, value);
@@ -1366,7 +1414,7 @@ function createValueInput(valuePath, ValueInput) {
1366
1414
  value,
1367
1415
  disabled: readonly,
1368
1416
  required,
1369
- error: error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ErrorRenderer, { error }),
1417
+ error: error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ErrorRenderer, { error }),
1370
1418
  onChange,
1371
1419
  onFocus,
1372
1420
  onBlur,
@@ -1381,9 +1429,9 @@ function createValueInput(valuePath, ValueInput) {
1381
1429
  }
1382
1430
 
1383
1431
  // mantine/hooks.tsx
1384
- var import_jsx_runtime7 = require("react/jsx-runtime");
1432
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1385
1433
  function SimpleSelect(props) {
1386
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core.Select, { ...props });
1434
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core.Select, { ...props });
1387
1435
  }
1388
1436
  function useMantineForm({
1389
1437
  onFieldValueChange,
@@ -1456,6 +1504,9 @@ var MantineFormImpl = class {
1456
1504
  listCache = new import_base6.Cache(
1457
1505
  createList.bind(this)
1458
1506
  );
1507
+ subFormCache = new import_base6.Cache(
1508
+ createSubForm.bind(this)
1509
+ );
1459
1510
  @import_mobx2.observable.ref
1460
1511
  accessor fields;
1461
1512
  onFieldValueChange;
@@ -1521,6 +1572,16 @@ var MantineFormImpl = class {
1521
1572
  DefaultList
1522
1573
  );
1523
1574
  }
1575
+ // TODO have the returned component take any non-overlapping props as props
1576
+ subForm(valuePath, SubForm) {
1577
+ return this.subFormCache.retrieveOrCreate(
1578
+ valuePath,
1579
+ // strip props from component since we lose information in the cache
1580
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
1581
+ SubForm,
1582
+ this
1583
+ );
1584
+ }
1524
1585
  };
1525
1586
 
1526
1587
  // types/merge_validators.ts
@@ -1587,6 +1648,7 @@ function mergeValidators(validators1, validators2) {
1587
1648
  mergeFieldAdaptersWithTwoWayConverter,
1588
1649
  mergeValidators,
1589
1650
  prototypingFieldValueFactory,
1651
+ subFormFieldAdapters,
1590
1652
  useMantineForm,
1591
1653
  usePartialComponent,
1592
1654
  usePartialObserverComponent,
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Maybe, ElementOfArray, StringKeyOf as StringKeyOf$1, ExhaustiveArrayOfUnion, FriendlyExhaustiveArrayOfUnion } from '@strictly/base';
1
+ import { Maybe, ElementOfArray, StringConcatOf, StringKeyOf as StringKeyOf$1, ExhaustiveArrayOfUnion, FriendlyExhaustiveArrayOfUnion } from '@strictly/base';
2
2
  import { Type, ValueOfType, ReadonlyTypeOfType, FlattenedTypesOfType, ListTypeDef, FlattenedValuesOfType, MobxValueOfType, Accessor, Validator, UnionTypeDef, ValueTypesOfDiscriminatedUnion, LiteralTypeDef } from '@strictly/define';
3
3
  import { ValueOf, SimplifyDeep, ReadonlyDeep, StringKeyOf, Simplify } from 'type-fest';
4
4
  import { ComponentType, ComponentProps, ForwardRefExoticComponent, PropsWithoutRef, DependencyList } from 'react';
@@ -68,7 +68,7 @@ declare function adapterFromTwoWayConverter<From, To, E, ValuePath extends strin
68
68
  declare function adapterFromPrototype<From, To, ValuePath extends string, Context>(converter: AnnotatedFieldConverter<From, To, ValuePath, Context>, prototype: From): FieldAdapterBuilder<From, To, never, ValuePath, Context>;
69
69
  declare function adapterFromPrototype<From, To, E, ValuePath extends string, Context>(converter: TwoWayFieldConverter<From, To, E, ValuePath, Context>, prototype: From): FieldAdapterBuilder<From, To, E, ValuePath, Context>;
70
70
  declare function identityAdapter<V, ValuePath extends string, Context>(prototype: V, required?: boolean): FieldAdapterBuilder<V, V, never, ValuePath, Context>;
71
- declare function listAdapter<E, K extends string, ValuePath extends string, Context>(): FieldAdapterBuilder<readonly E[], readonly K[], never, ValuePath, Context>;
71
+ declare function listAdapter<E, ValuePath extends string, Context>(): FieldAdapterBuilder<readonly E[], readonly E[], never, ValuePath, Context>;
72
72
 
73
73
  type FieldAdaptersOfValues<FlattenedValues extends Readonly<Record<string, any>>, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedValues, string>> = Readonly<Record<keyof FlattenedValues, any>>, Context = any> = {
74
74
  readonly [K in keyof FlattenedValues]: FieldAdapter<FlattenedValues[K], any, any, TypePathsToValuePaths[K], Context>;
@@ -168,6 +168,11 @@ type MergedOfFieldAdaptersWithValidators<FieldAdapters extends Readonly<Record<K
168
168
  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;
169
169
  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>;
170
170
 
171
+ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string> = {
172
+ [K in keyof SubAdapters as K extends StringConcatOf<'$', infer S> ? `${P}${S}` : never]: SubAdapters[K];
173
+ };
174
+ declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string>(subAdapters: SubAdapters, prefix: P): SubFormFieldAdapters<SubAdapters, P>;
175
+
171
176
  /**
172
177
  * Used to extract the supported value paths from a presenter
173
178
  */
@@ -279,6 +284,12 @@ type StringFieldsOfFields<F extends Fields> = {
279
284
  [K in keyof F as ValueTypeOfField<F[K]> extends string | undefined | null ? K : never]: F[K];
280
285
  };
281
286
 
287
+ type SubFormFields<F extends Fields, P extends keyof F> = P extends string ? {
288
+ [K in keyof F as K extends StringConcatOf<`${P}.`, infer S> ? `$.${S}` : never]: F[K];
289
+ } & {
290
+ $: F[P];
291
+ } : never;
292
+
282
293
  type PartialComponent<Component extends ComponentType<any>, CurriedProps, AdditionalProps = {}> = Exclude<keyof CurriedProps, keyof ComponentProps<Component>> extends never ? UnsafePartialComponent<Component, CurriedProps, AdditionalProps> : keyof CurriedProps extends (string | number) ? `unmatched prop: ${Exclude<keyof CurriedProps, keyof ComponentProps<Component>>}` : Exclude<keyof CurriedProps, keyof ComponentProps<Component>>;
283
294
  type UnsafePartialComponent<Component extends ComponentType<any>, CurriedProps, AdditionalProps = {}> = ForwardRefExoticComponent<PropsWithoutRef<RemainingComponentProps<Component, CurriedProps> & AdditionalProps>>;
284
295
  declare function createSimplePartialComponent<Component extends ComponentType<any>, CurriedProps extends Partial<ComponentProps<Component>>>(Component: Component, curriedProps: CurriedProps): PartialComponent<Component, CurriedProps>;
@@ -307,11 +318,12 @@ type MantineFieldComponent<T, P = T, E = any> = UnsafePartialComponent<Component
307
318
 
308
319
  type SuppliedCheckboxProps = Pick<CheckboxProps, 'name' | 'checked' | 'disabled' | 'required' | 'error' | 'onChange' | 'onFocus' | 'onBlur' | 'onKeyUp'>;
309
320
 
310
- type SuppliedListProps<Value = any> = {
321
+ type SuppliedListProps<Value = any, ListPath extends string = string> = {
311
322
  values: readonly Value[];
323
+ listPath: ListPath;
312
324
  };
313
- declare function DefaultList<Value>({ values, children, }: SuppliedListProps<Value> & {
314
- children: (value: Value, index: number) => React.ReactNode;
325
+ declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
326
+ children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
315
327
  }): react_jsx_runtime.JSX.Element;
316
328
 
317
329
  type SuppliedPillProps = Pick<PillProps, 'children' | 'disabled'>;
@@ -357,8 +369,9 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
357
369
  private readonly radioCache;
358
370
  private readonly pillCache;
359
371
  private readonly listCache;
372
+ private readonly subFormCache;
360
373
  accessor fields: F;
361
- onFieldValueChange: (<K extends keyof F>(this: void, key: K, value: F[K]['value']) => void) | undefined;
374
+ onFieldValueChange: <K extends keyof F>(this: void, key: K, value: F[K]['value']) => void;
362
375
  onFieldFocus: ((this: void, key: keyof F) => void) | undefined;
363
376
  onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
364
377
  onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
@@ -375,7 +388,8 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
375
388
  radio<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioProps>(valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<P>): MantineFieldComponent<SuppliedRadioProps, P, ErrorOfField<F[K]>>;
376
389
  pill<K extends keyof AllFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedPillProps, PillProps, ErrorOfField<F[K]>>;
377
390
  pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P>;
378
- list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<ElementOfArray<F[K]>>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]>>>>;
391
+ list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>>;
392
+ subForm<K extends keyof AllFieldsOfFields<F>, S extends SubFormFields<F, K>>(valuePath: K, SubForm: ComponentType<FormProps<S>>): ComponentType;
379
393
  }
380
394
 
381
395
  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<{
@@ -384,4 +398,4 @@ type MergedOfValidators<Validators1 extends Partial<Readonly<Record<Keys, Valida
384
398
  type MergedOfValidator<Validator1 extends Validator, Validator2 extends Validator> = Validator1 extends Validator<infer V, infer E1, infer P, infer C> ? Validator2 extends Validator<V, infer E2, P, C> ? Validator<V, E1 | E2, P, C> : never : never;
385
399
  declare function mergeValidators<Validators1 extends Partial<Readonly<Record<Keys, Validator>>>, Validators2 extends Partial<Readonly<Record<Keys, Validator>>>, Keys extends string = Extract<keyof Validators1 | keyof Validators2, string>>(validators1: Validators1, validators2: Validators2): MergedOfValidators<Validators1, Validators2, Keys>;
386
400
 
387
- export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, DefaultErrorRenderer, type EditorProps, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfPresenter, FormModel, FormPresenter, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfPresenterValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfPresenter, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, useMantineForm, usePartialComponent, usePartialObserverComponent, validatingConverter };
401
+ export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, DefaultErrorRenderer, type EditorProps, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfPresenter, FormModel, FormPresenter, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfPresenterValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfPresenter, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, subFormFieldAdapters, useMantineForm, usePartialComponent, usePartialObserverComponent, validatingConverter };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Maybe, ElementOfArray, StringKeyOf as StringKeyOf$1, ExhaustiveArrayOfUnion, FriendlyExhaustiveArrayOfUnion } from '@strictly/base';
1
+ import { Maybe, ElementOfArray, StringConcatOf, StringKeyOf as StringKeyOf$1, ExhaustiveArrayOfUnion, FriendlyExhaustiveArrayOfUnion } from '@strictly/base';
2
2
  import { Type, ValueOfType, ReadonlyTypeOfType, FlattenedTypesOfType, ListTypeDef, FlattenedValuesOfType, MobxValueOfType, Accessor, Validator, UnionTypeDef, ValueTypesOfDiscriminatedUnion, LiteralTypeDef } from '@strictly/define';
3
3
  import { ValueOf, SimplifyDeep, ReadonlyDeep, StringKeyOf, Simplify } from 'type-fest';
4
4
  import { ComponentType, ComponentProps, ForwardRefExoticComponent, PropsWithoutRef, DependencyList } from 'react';
@@ -68,7 +68,7 @@ declare function adapterFromTwoWayConverter<From, To, E, ValuePath extends strin
68
68
  declare function adapterFromPrototype<From, To, ValuePath extends string, Context>(converter: AnnotatedFieldConverter<From, To, ValuePath, Context>, prototype: From): FieldAdapterBuilder<From, To, never, ValuePath, Context>;
69
69
  declare function adapterFromPrototype<From, To, E, ValuePath extends string, Context>(converter: TwoWayFieldConverter<From, To, E, ValuePath, Context>, prototype: From): FieldAdapterBuilder<From, To, E, ValuePath, Context>;
70
70
  declare function identityAdapter<V, ValuePath extends string, Context>(prototype: V, required?: boolean): FieldAdapterBuilder<V, V, never, ValuePath, Context>;
71
- declare function listAdapter<E, K extends string, ValuePath extends string, Context>(): FieldAdapterBuilder<readonly E[], readonly K[], never, ValuePath, Context>;
71
+ declare function listAdapter<E, ValuePath extends string, Context>(): FieldAdapterBuilder<readonly E[], readonly E[], never, ValuePath, Context>;
72
72
 
73
73
  type FieldAdaptersOfValues<FlattenedValues extends Readonly<Record<string, any>>, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedValues, string>> = Readonly<Record<keyof FlattenedValues, any>>, Context = any> = {
74
74
  readonly [K in keyof FlattenedValues]: FieldAdapter<FlattenedValues[K], any, any, TypePathsToValuePaths[K], Context>;
@@ -168,6 +168,11 @@ type MergedOfFieldAdaptersWithValidators<FieldAdapters extends Readonly<Record<K
168
168
  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;
169
169
  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>;
170
170
 
171
+ type SubFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string> = {
172
+ [K in keyof SubAdapters as K extends StringConcatOf<'$', infer S> ? `${P}${S}` : never]: SubAdapters[K];
173
+ };
174
+ declare function subFormFieldAdapters<SubAdapters extends Record<string, FieldAdapter>, P extends string>(subAdapters: SubAdapters, prefix: P): SubFormFieldAdapters<SubAdapters, P>;
175
+
171
176
  /**
172
177
  * Used to extract the supported value paths from a presenter
173
178
  */
@@ -279,6 +284,12 @@ type StringFieldsOfFields<F extends Fields> = {
279
284
  [K in keyof F as ValueTypeOfField<F[K]> extends string | undefined | null ? K : never]: F[K];
280
285
  };
281
286
 
287
+ type SubFormFields<F extends Fields, P extends keyof F> = P extends string ? {
288
+ [K in keyof F as K extends StringConcatOf<`${P}.`, infer S> ? `$.${S}` : never]: F[K];
289
+ } & {
290
+ $: F[P];
291
+ } : never;
292
+
282
293
  type PartialComponent<Component extends ComponentType<any>, CurriedProps, AdditionalProps = {}> = Exclude<keyof CurriedProps, keyof ComponentProps<Component>> extends never ? UnsafePartialComponent<Component, CurriedProps, AdditionalProps> : keyof CurriedProps extends (string | number) ? `unmatched prop: ${Exclude<keyof CurriedProps, keyof ComponentProps<Component>>}` : Exclude<keyof CurriedProps, keyof ComponentProps<Component>>;
283
294
  type UnsafePartialComponent<Component extends ComponentType<any>, CurriedProps, AdditionalProps = {}> = ForwardRefExoticComponent<PropsWithoutRef<RemainingComponentProps<Component, CurriedProps> & AdditionalProps>>;
284
295
  declare function createSimplePartialComponent<Component extends ComponentType<any>, CurriedProps extends Partial<ComponentProps<Component>>>(Component: Component, curriedProps: CurriedProps): PartialComponent<Component, CurriedProps>;
@@ -307,11 +318,12 @@ type MantineFieldComponent<T, P = T, E = any> = UnsafePartialComponent<Component
307
318
 
308
319
  type SuppliedCheckboxProps = Pick<CheckboxProps, 'name' | 'checked' | 'disabled' | 'required' | 'error' | 'onChange' | 'onFocus' | 'onBlur' | 'onKeyUp'>;
309
320
 
310
- type SuppliedListProps<Value = any> = {
321
+ type SuppliedListProps<Value = any, ListPath extends string = string> = {
311
322
  values: readonly Value[];
323
+ listPath: ListPath;
312
324
  };
313
- declare function DefaultList<Value>({ values, children, }: SuppliedListProps<Value> & {
314
- children: (value: Value, index: number) => React.ReactNode;
325
+ declare function DefaultList<Value, ListPath extends string>({ values, listPath, children, }: SuppliedListProps<Value, ListPath> & {
326
+ children: (valuePath: `${ListPath}.${number}`, value: Value, index: number) => React.ReactNode;
315
327
  }): react_jsx_runtime.JSX.Element;
316
328
 
317
329
  type SuppliedPillProps = Pick<PillProps, 'children' | 'disabled'>;
@@ -357,8 +369,9 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
357
369
  private readonly radioCache;
358
370
  private readonly pillCache;
359
371
  private readonly listCache;
372
+ private readonly subFormCache;
360
373
  accessor fields: F;
361
- onFieldValueChange: (<K extends keyof F>(this: void, key: K, value: F[K]['value']) => void) | undefined;
374
+ onFieldValueChange: <K extends keyof F>(this: void, key: K, value: F[K]['value']) => void;
362
375
  onFieldFocus: ((this: void, key: keyof F) => void) | undefined;
363
376
  onFieldBlur: ((this: void, key: keyof F) => void) | undefined;
364
377
  onFieldSubmit: ((this: void, key: keyof F) => boolean | void) | undefined;
@@ -375,7 +388,8 @@ declare class MantineFormImpl<F extends Fields> implements MantineForm<F> {
375
388
  radio<K extends keyof StringFieldsOfFields<F>, P extends SuppliedRadioProps>(valuePath: K, value: ValueTypeOfField<F[K]>, Radio: ComponentType<P>): MantineFieldComponent<SuppliedRadioProps, P, ErrorOfField<F[K]>>;
376
389
  pill<K extends keyof AllFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedPillProps, PillProps, ErrorOfField<F[K]>>;
377
390
  pill<K extends keyof AllFieldsOfFields<F>, P extends SuppliedPillProps>(valuePath: K, Pill: ComponentType<P>): MantineFieldComponent<SuppliedPillProps, P>;
378
- list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<ElementOfArray<F[K]>>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]>>>>;
391
+ list<K extends keyof ListFieldsOfFields<F>>(valuePath: K): MantineFieldComponent<SuppliedListProps<`${K}.${number}`>, ComponentProps<typeof DefaultList<ElementOfArray<F[K]['value']>, K>>>;
392
+ subForm<K extends keyof AllFieldsOfFields<F>, S extends SubFormFields<F, K>>(valuePath: K, SubForm: ComponentType<FormProps<S>>): ComponentType;
379
393
  }
380
394
 
381
395
  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<{
@@ -384,4 +398,4 @@ type MergedOfValidators<Validators1 extends Partial<Readonly<Record<Keys, Valida
384
398
  type MergedOfValidator<Validator1 extends Validator, Validator2 extends Validator> = Validator1 extends Validator<infer V, infer E1, infer P, infer C> ? Validator2 extends Validator<V, infer E2, P, C> ? Validator<V, E1 | E2, P, C> : never : never;
385
399
  declare function mergeValidators<Validators1 extends Partial<Readonly<Record<Keys, Validator>>>, Validators2 extends Partial<Readonly<Record<Keys, Validator>>>, Keys extends string = Extract<keyof Validators1 | keyof Validators2, string>>(validators1: Validators1, validators2: Validators2): MergedOfValidators<Validators1, Validators2, Keys>;
386
400
 
387
- export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, DefaultErrorRenderer, type EditorProps, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfPresenter, FormModel, FormPresenter, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfPresenterValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfPresenter, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, useMantineForm, usePartialComponent, usePartialObserverComponent, validatingConverter };
401
+ export { AbstractSelectValueTypeConverter, type AnnotatedFieldConversion, type AnnotatedFieldConverter, type Annotation, DefaultErrorRenderer, type EditorProps, type ErrorOfField, type ErrorOfFieldAdapter, type ErrorRenderer, type ErrorRendererProps, type Field, type FieldAdapter, type FieldAdaptersOfValues, type FieldValueFactory, type Fields, type FlattenedAdaptersOfFields, type FlattenedConvertedFieldsOf, type FlattenedTypePathsToAdaptersOf, type FormFieldsOfFieldAdapters, type FormFieldsOfPresenter, FormModel, FormPresenter, type FormProps, type FromOfFieldAdapter, IntegerToStringConverter, type MergedOfFieldAdaptersWithTwoWayConverter, type MergedOfFieldAdaptersWithValidators, type MergedOfValidator, type MergedOfValidators, NullableToBooleanConverter, type PartialComponent, SelectDiscriminatedUnionConverter, SelectLiteralConverter, SelectStringConverter, type ToOfFieldAdapter, type ToValueOfPresenterValuePath, TrimmingStringConverter, type TwoWayFieldConverter, type TwoWayFieldConverterWithValueFactory, type UnreliableFieldConversion, UnreliableFieldConversionType, type UnreliableFieldConverter, type UnsafePartialComponent, type ValuePathOfFieldAdapter, type ValuePathsOfPresenter, type ValuePathsToAdaptersOf, adapter, adapterFromPrototype, adapterFromTwoWayConverter, createPartialComponent, createPartialObserverComponent, createSimplePartialComponent, createUnsafePartialObserverComponent, identityAdapter, listAdapter, mergeAdaptersWithValidators, mergeFieldAdaptersWithTwoWayConverter, mergeValidators, prototypingFieldValueFactory, subFormFieldAdapters, useMantineForm, usePartialComponent, usePartialObserverComponent, validatingConverter };