@jfdevelops/react-multi-step-form 1.0.0-alpha.26 → 1.0.0-alpha.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/field.cjs +15 -4
- package/dist/field.cjs.map +1 -1
- package/dist/field.d.cts +34 -6
- package/dist/field.d.mts +34 -6
- package/dist/field.mjs +15 -4
- package/dist/field.mjs.map +1 -1
- package/dist/hooks/use-selector.cjs +2 -1
- package/dist/hooks/use-selector.cjs.map +1 -1
- package/dist/hooks/use-selector.mjs +2 -1
- package/dist/hooks/use-selector.mjs.map +1 -1
- package/dist/step-schema.cjs +42 -33
- package/dist/step-schema.cjs.map +1 -1
- package/dist/step-schema.d.cts +2 -2
- package/dist/step-schema.d.mts +2 -2
- package/dist/step-schema.mjs +42 -33
- package/dist/step-schema.mjs.map +1 -1
- package/package.json +1 -1
package/dist/field.cjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
const require_selector = require('./selector.cjs');
|
|
1
2
|
let react = require("react");
|
|
3
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
2
4
|
|
|
3
5
|
//#region src/field.tsx
|
|
4
6
|
let field;
|
|
5
7
|
(function(_field) {
|
|
6
|
-
function create(
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
function create(options) {
|
|
9
|
+
const { propsCreator, subscribe, getValue, selectorCtx } = options;
|
|
10
|
+
const Field = (props) => {
|
|
11
|
+
const { name, children, selectorFn } = props;
|
|
9
12
|
const subscribeFn = subscribe || (() => () => {});
|
|
10
13
|
const getValueFn = getValue || (() => void 0);
|
|
11
14
|
const currentValue = (0, react.useSyncExternalStore)(subscribeFn, () => getValueFn(name), () => getValueFn(name));
|
|
@@ -14,8 +17,16 @@ let field;
|
|
|
14
17
|
...createdProps,
|
|
15
18
|
defaultValue: currentValue
|
|
16
19
|
};
|
|
20
|
+
if (selectorFn) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_selector.selector.create(() => selectorCtx, subscribeFn), {
|
|
21
|
+
selector: selectorFn,
|
|
22
|
+
children: (value) => children({
|
|
23
|
+
...createdProps,
|
|
24
|
+
selected: { value }
|
|
25
|
+
})
|
|
26
|
+
});
|
|
17
27
|
return children(createdProps);
|
|
18
|
-
}
|
|
28
|
+
};
|
|
29
|
+
return (0, react.memo)(Field);
|
|
19
30
|
}
|
|
20
31
|
_field.create = create;
|
|
21
32
|
})(field || (field = {}));
|
package/dist/field.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.cjs","names":[],"sources":["../src/field.tsx"],"sourcesContent":["import type {\n AnyResolvedStep,\n fields,\n Override,\n Updater,\n} from '@jfdevelops/multi-step-form-core';\nimport type { ReactNode } from 'react';\nimport { memo, useSyncExternalStore } from 'react';\n\nexport namespace field {\n type sharedProps<TField extends string> = {\n /**\n * The name of the field.\n */\n name: TField;\n };\n\n
|
|
1
|
+
{"version":3,"file":"field.cjs","names":["Field: field.component<TResolvedStep, TSteps, TChosenSteps>","selector"],"sources":["../src/field.tsx"],"sourcesContent":["import type {\n AnyResolvedStep,\n Expand,\n fields,\n HelperFnChosenSteps,\n HelperFnCtx,\n Override,\n StepNumbers,\n Updater,\n} from '@jfdevelops/multi-step-form-core';\nimport type { ReactNode } from 'react';\nimport { memo, useSyncExternalStore } from 'react';\nimport type { SelectorFn } from './hooks/use-selector';\nimport { selector } from './selector';\n\nexport namespace field {\n type sharedProps<TField extends string> = {\n /**\n * The name of the field.\n */\n name: TField;\n };\n\n // aliases for types in `fields` namespace\n type getDeep<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = fields.getDeep<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>\n >;\n type resolveDeepPath<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>\n > = fields.resolveDeepPath<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>,\n TField\n >;\n type get<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = fields.get<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>\n >;\n\n export type childrenProps<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TValue extends resolveDeepPath<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TField\n > = resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>\n > = sharedProps<TField> &\n Override<\n get<TResolvedStep, TSteps, TChosenSteps>[fields.parentOf<TField>],\n 'defaultValue',\n TValue\n > & {\n /**\n * A useful wrapper around `update` to update the specific field.\n * @param value The new value for the field.\n */\n onInputChange: (value: Updater<TValue>) => void;\n /**\n * Resets the field's value to the original value that was\n * defined in the config.\n */\n reset: () => void;\n };\n export type childrenPropsWithSelected<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TSelected\n > = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {\n selected: {\n /**\n * The result of the `selectorFn`.\n */\n value: TSelected;\n };\n };\n export type selectorChildrenProps<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TSelected\n > = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {\n selected: {\n /**\n * The selected value.\n */\n value: TSelected;\n };\n };\n export type props<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TSelected\n > = sharedProps<TField> & {\n selectorFn?: SelectorFn<TResolvedStep, TSteps, TChosenSteps, TSelected>;\n children: (\n props: [TSelected] extends [never]\n ? childrenProps<TResolvedStep, TSteps, TChosenSteps, TField>\n : childrenPropsWithSelected<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TField,\n TSelected\n >\n ) => ReactNode;\n };\n export type component<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = <\n field extends fields.getDeep<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>\n >,\n selected = never\n >(\n props: props<TResolvedStep, TSteps, TChosenSteps, field, selected>\n ) => ReactNode;\n\n export type createOptions<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = {\n propsCreator: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(\n name: TField\n ) => field.childrenProps<TResolvedStep, TSteps, TChosenSteps, TField>;\n subscribe?: (listener: () => void) => () => void;\n getValue?: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(\n name: TField\n ) => resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>;\n selectorCtx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>;\n };\n\n /**\n * Create a field.\n * @param propsCreator\n * @param subscribe - Optional subscription function for reactivity\n * @param getValue - Optional function to get the current field value reactively\n * @returns\n */\n export function create<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n >(options: createOptions<TResolvedStep, TSteps, TChosenSteps>) {\n const { propsCreator, subscribe, getValue, selectorCtx } = options;\n\n const Field: field.component<TResolvedStep, TSteps, TChosenSteps> = (\n props\n ) => {\n const { name, children, selectorFn } = props;\n\n // Always call the hook, but use no-op functions if subscribe/getValue aren't provided\n const subscribeFn = subscribe || (() => () => {});\n const getValueFn = getValue || (() => undefined);\n\n // Subscribe to changes to trigger rerenders\n const currentValue = useSyncExternalStore(\n subscribeFn,\n () => getValueFn(name),\n () => getValueFn(name)\n );\n\n let createdProps = propsCreator(name);\n\n // If getValue is provided, override defaultValue with the reactive value\n if (getValue) {\n createdProps = {\n ...createdProps,\n defaultValue: currentValue,\n } as typeof createdProps;\n }\n\n if (selectorFn) {\n const Selector = selector.create<TResolvedStep, TSteps, TChosenSteps>(\n () => selectorCtx,\n subscribeFn\n );\n\n return (\n <Selector selector={selectorFn}>\n {(value) =>\n children({\n ...createdProps,\n selected: { value: value as never },\n })\n }\n </Selector>\n );\n }\n\n return children(createdProps as never);\n };\n\n return memo(Field);\n }\n}\n"],"mappings":";;;;;;;CAmKS,SAAS,OAId,SAA6D;EAC7D,MAAM,EAAE,cAAc,WAAW,UAAU,gBAAgB;EAE3D,MAAMA,SACJ,UACG;GACH,MAAM,EAAE,MAAM,UAAU,eAAe;GAGvC,MAAM,cAAc,0BAA0B;GAC9C,MAAM,aAAa,mBAAmB;GAGtC,MAAM,+CACJ,mBACM,WAAW,KAAK,QAChB,WAAW,KAAK,CACvB;GAED,IAAI,eAAe,aAAa,KAAK;AAGrC,OAAI,SACF,gBAAe;IACb,GAAG;IACH,cAAc;IACf;AAGH,OAAI,WAMF,QACE,2CANeC,0BAAS,aAClB,aACN,YACD;IAGW,UAAU;eAChB,UACA,SAAS;KACP,GAAG;KACH,UAAU,EAAS,OAAgB;KACpC,CAAC;KAEK;AAIf,UAAO,SAAS,aAAsB;;AAGxC,yBAAY,MAAM"}
|
package/dist/field.d.cts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SelectorFn } from "./hooks/use-selector.cjs";
|
|
2
|
+
import { AnyResolvedStep, Expand, HelperFnChosenSteps, HelperFnCtx, Override, StepNumbers, Updater, fields } from "@jfdevelops/multi-step-form-core";
|
|
3
|
+
import * as react0 from "react";
|
|
2
4
|
import { ReactNode } from "react";
|
|
3
5
|
|
|
4
6
|
//#region src/field.d.ts
|
|
@@ -9,7 +11,10 @@ declare namespace field {
|
|
|
9
11
|
*/
|
|
10
12
|
name: TField;
|
|
11
13
|
};
|
|
12
|
-
|
|
14
|
+
type getDeep<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = fields.getDeep<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>>;
|
|
15
|
+
type resolveDeepPath<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>> = fields.resolveDeepPath<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>, TField>;
|
|
16
|
+
type get<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = fields.get<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>>;
|
|
17
|
+
export type childrenProps<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TValue extends resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField> = resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>> = sharedProps<TField> & Override<get<TResolvedStep, TSteps, TChosenSteps>[fields.parentOf<TField>], 'defaultValue', TValue> & {
|
|
13
18
|
/**
|
|
14
19
|
* A useful wrapper around `update` to update the specific field.
|
|
15
20
|
* @param value The new value for the field.
|
|
@@ -21,10 +26,33 @@ declare namespace field {
|
|
|
21
26
|
*/
|
|
22
27
|
reset: () => void;
|
|
23
28
|
};
|
|
24
|
-
export type
|
|
25
|
-
|
|
29
|
+
export type childrenPropsWithSelected<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TSelected> = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {
|
|
30
|
+
selected: {
|
|
31
|
+
/**
|
|
32
|
+
* The result of the `selectorFn`.
|
|
33
|
+
*/
|
|
34
|
+
value: TSelected;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export type selectorChildrenProps<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TSelected> = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {
|
|
38
|
+
selected: {
|
|
39
|
+
/**
|
|
40
|
+
* The selected value.
|
|
41
|
+
*/
|
|
42
|
+
value: TSelected;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export type props<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TSelected> = sharedProps<TField> & {
|
|
46
|
+
selectorFn?: SelectorFn<TResolvedStep, TSteps, TChosenSteps, TSelected>;
|
|
47
|
+
children: (props: [TSelected] extends [never] ? childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> : childrenPropsWithSelected<TResolvedStep, TSteps, TChosenSteps, TField, TSelected>) => ReactNode;
|
|
48
|
+
};
|
|
49
|
+
export type component<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = <field$1 extends fields.getDeep<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>>, selected = never>(props: props<TResolvedStep, TSteps, TChosenSteps, field$1, selected>) => ReactNode;
|
|
50
|
+
export type createOptions<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = {
|
|
51
|
+
propsCreator: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(name: TField) => field$1.childrenProps<TResolvedStep, TSteps, TChosenSteps, TField>;
|
|
52
|
+
subscribe?: (listener: () => void) => () => void;
|
|
53
|
+
getValue?: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(name: TField) => resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>;
|
|
54
|
+
selectorCtx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>;
|
|
26
55
|
};
|
|
27
|
-
export type component<TResolvedStep extends AnyResolvedStep, TTargetStep extends keyof TResolvedStep> = <TField extends fields.getDeep<TResolvedStep, TTargetStep>>(props: props<TResolvedStep, TTargetStep, TField>) => ReactNode;
|
|
28
56
|
/**
|
|
29
57
|
* Create a field.
|
|
30
58
|
* @param propsCreator
|
|
@@ -32,7 +60,7 @@ declare namespace field {
|
|
|
32
60
|
* @param getValue - Optional function to get the current field value reactively
|
|
33
61
|
* @returns
|
|
34
62
|
*/
|
|
35
|
-
export function create<TResolvedStep extends AnyResolvedStep,
|
|
63
|
+
export function create<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>>(options: createOptions<TResolvedStep, TSteps, TChosenSteps>): react0.MemoExoticComponent<component<TResolvedStep, TSteps, TChosenSteps>>;
|
|
36
64
|
export {};
|
|
37
65
|
}
|
|
38
66
|
//#endregion
|
package/dist/field.d.mts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SelectorFn } from "./hooks/use-selector.mjs";
|
|
2
|
+
import { AnyResolvedStep, Expand, HelperFnChosenSteps, HelperFnCtx, Override, StepNumbers, Updater, fields } from "@jfdevelops/multi-step-form-core";
|
|
3
|
+
import * as react0 from "react";
|
|
2
4
|
import { ReactNode } from "react";
|
|
3
5
|
|
|
4
6
|
//#region src/field.d.ts
|
|
@@ -9,7 +11,10 @@ declare namespace field {
|
|
|
9
11
|
*/
|
|
10
12
|
name: TField;
|
|
11
13
|
};
|
|
12
|
-
|
|
14
|
+
type getDeep<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = fields.getDeep<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>>;
|
|
15
|
+
type resolveDeepPath<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>> = fields.resolveDeepPath<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>, TField>;
|
|
16
|
+
type get<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = fields.get<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>>;
|
|
17
|
+
export type childrenProps<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TValue extends resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField> = resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>> = sharedProps<TField> & Override<get<TResolvedStep, TSteps, TChosenSteps>[fields.parentOf<TField>], 'defaultValue', TValue> & {
|
|
13
18
|
/**
|
|
14
19
|
* A useful wrapper around `update` to update the specific field.
|
|
15
20
|
* @param value The new value for the field.
|
|
@@ -21,10 +26,33 @@ declare namespace field {
|
|
|
21
26
|
*/
|
|
22
27
|
reset: () => void;
|
|
23
28
|
};
|
|
24
|
-
export type
|
|
25
|
-
|
|
29
|
+
export type childrenPropsWithSelected<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TSelected> = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {
|
|
30
|
+
selected: {
|
|
31
|
+
/**
|
|
32
|
+
* The result of the `selectorFn`.
|
|
33
|
+
*/
|
|
34
|
+
value: TSelected;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export type selectorChildrenProps<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TSelected> = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {
|
|
38
|
+
selected: {
|
|
39
|
+
/**
|
|
40
|
+
* The selected value.
|
|
41
|
+
*/
|
|
42
|
+
value: TSelected;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export type props<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>, TSelected> = sharedProps<TField> & {
|
|
46
|
+
selectorFn?: SelectorFn<TResolvedStep, TSteps, TChosenSteps, TSelected>;
|
|
47
|
+
children: (props: [TSelected] extends [never] ? childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> : childrenPropsWithSelected<TResolvedStep, TSteps, TChosenSteps, TField, TSelected>) => ReactNode;
|
|
48
|
+
};
|
|
49
|
+
export type component<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = <field$1 extends fields.getDeep<TResolvedStep, HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>>, selected = never>(props: props<TResolvedStep, TSteps, TChosenSteps, field$1, selected>) => ReactNode;
|
|
50
|
+
export type createOptions<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>> = {
|
|
51
|
+
propsCreator: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(name: TField) => field$1.childrenProps<TResolvedStep, TSteps, TChosenSteps, TField>;
|
|
52
|
+
subscribe?: (listener: () => void) => () => void;
|
|
53
|
+
getValue?: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(name: TField) => resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>;
|
|
54
|
+
selectorCtx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>;
|
|
26
55
|
};
|
|
27
|
-
export type component<TResolvedStep extends AnyResolvedStep, TTargetStep extends keyof TResolvedStep> = <TField extends fields.getDeep<TResolvedStep, TTargetStep>>(props: props<TResolvedStep, TTargetStep, TField>) => ReactNode;
|
|
28
56
|
/**
|
|
29
57
|
* Create a field.
|
|
30
58
|
* @param propsCreator
|
|
@@ -32,7 +60,7 @@ declare namespace field {
|
|
|
32
60
|
* @param getValue - Optional function to get the current field value reactively
|
|
33
61
|
* @returns
|
|
34
62
|
*/
|
|
35
|
-
export function create<TResolvedStep extends AnyResolvedStep,
|
|
63
|
+
export function create<TResolvedStep extends AnyResolvedStep, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>>(options: createOptions<TResolvedStep, TSteps, TChosenSteps>): react0.MemoExoticComponent<component<TResolvedStep, TSteps, TChosenSteps>>;
|
|
36
64
|
export {};
|
|
37
65
|
}
|
|
38
66
|
//#endregion
|
package/dist/field.mjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { selector } from "./selector.mjs";
|
|
1
2
|
import { memo, useSyncExternalStore } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
4
|
|
|
3
5
|
//#region src/field.tsx
|
|
4
6
|
let field;
|
|
5
7
|
(function(_field) {
|
|
6
|
-
function create(
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
function create(options) {
|
|
9
|
+
const { propsCreator, subscribe, getValue, selectorCtx } = options;
|
|
10
|
+
const Field = (props) => {
|
|
11
|
+
const { name, children, selectorFn } = props;
|
|
9
12
|
const subscribeFn = subscribe || (() => () => {});
|
|
10
13
|
const getValueFn = getValue || (() => void 0);
|
|
11
14
|
const currentValue = useSyncExternalStore(subscribeFn, () => getValueFn(name), () => getValueFn(name));
|
|
@@ -14,8 +17,16 @@ let field;
|
|
|
14
17
|
...createdProps,
|
|
15
18
|
defaultValue: currentValue
|
|
16
19
|
};
|
|
20
|
+
if (selectorFn) return /* @__PURE__ */ jsx(selector.create(() => selectorCtx, subscribeFn), {
|
|
21
|
+
selector: selectorFn,
|
|
22
|
+
children: (value) => children({
|
|
23
|
+
...createdProps,
|
|
24
|
+
selected: { value }
|
|
25
|
+
})
|
|
26
|
+
});
|
|
17
27
|
return children(createdProps);
|
|
18
|
-
}
|
|
28
|
+
};
|
|
29
|
+
return memo(Field);
|
|
19
30
|
}
|
|
20
31
|
_field.create = create;
|
|
21
32
|
})(field || (field = {}));
|
package/dist/field.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.mjs","names":[],"sources":["../src/field.tsx"],"sourcesContent":["import type {\n AnyResolvedStep,\n fields,\n Override,\n Updater,\n} from '@jfdevelops/multi-step-form-core';\nimport type { ReactNode } from 'react';\nimport { memo, useSyncExternalStore } from 'react';\n\nexport namespace field {\n type sharedProps<TField extends string> = {\n /**\n * The name of the field.\n */\n name: TField;\n };\n\n
|
|
1
|
+
{"version":3,"file":"field.mjs","names":["Field: field.component<TResolvedStep, TSteps, TChosenSteps>"],"sources":["../src/field.tsx"],"sourcesContent":["import type {\n AnyResolvedStep,\n Expand,\n fields,\n HelperFnChosenSteps,\n HelperFnCtx,\n Override,\n StepNumbers,\n Updater,\n} from '@jfdevelops/multi-step-form-core';\nimport type { ReactNode } from 'react';\nimport { memo, useSyncExternalStore } from 'react';\nimport type { SelectorFn } from './hooks/use-selector';\nimport { selector } from './selector';\n\nexport namespace field {\n type sharedProps<TField extends string> = {\n /**\n * The name of the field.\n */\n name: TField;\n };\n\n // aliases for types in `fields` namespace\n type getDeep<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = fields.getDeep<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>\n >;\n type resolveDeepPath<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>\n > = fields.resolveDeepPath<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>,\n TField\n >;\n type get<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = fields.get<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>\n >;\n\n export type childrenProps<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TValue extends resolveDeepPath<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TField\n > = resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>\n > = sharedProps<TField> &\n Override<\n get<TResolvedStep, TSteps, TChosenSteps>[fields.parentOf<TField>],\n 'defaultValue',\n TValue\n > & {\n /**\n * A useful wrapper around `update` to update the specific field.\n * @param value The new value for the field.\n */\n onInputChange: (value: Updater<TValue>) => void;\n /**\n * Resets the field's value to the original value that was\n * defined in the config.\n */\n reset: () => void;\n };\n export type childrenPropsWithSelected<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TSelected\n > = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {\n selected: {\n /**\n * The result of the `selectorFn`.\n */\n value: TSelected;\n };\n };\n export type selectorChildrenProps<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TSelected\n > = childrenProps<TResolvedStep, TSteps, TChosenSteps, TField> & {\n selected: {\n /**\n * The selected value.\n */\n value: TSelected;\n };\n };\n export type props<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>,\n TSelected\n > = sharedProps<TField> & {\n selectorFn?: SelectorFn<TResolvedStep, TSteps, TChosenSteps, TSelected>;\n children: (\n props: [TSelected] extends [never]\n ? childrenProps<TResolvedStep, TSteps, TChosenSteps, TField>\n : childrenPropsWithSelected<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TField,\n TSelected\n >\n ) => ReactNode;\n };\n export type component<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = <\n field extends fields.getDeep<\n TResolvedStep,\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TChosenSteps>\n >,\n selected = never\n >(\n props: props<TResolvedStep, TSteps, TChosenSteps, field, selected>\n ) => ReactNode;\n\n export type createOptions<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n > = {\n propsCreator: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(\n name: TField\n ) => field.childrenProps<TResolvedStep, TSteps, TChosenSteps, TField>;\n subscribe?: (listener: () => void) => () => void;\n getValue?: <TField extends getDeep<TResolvedStep, TSteps, TChosenSteps>>(\n name: TField\n ) => resolveDeepPath<TResolvedStep, TSteps, TChosenSteps, TField>;\n selectorCtx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>;\n };\n\n /**\n * Create a field.\n * @param propsCreator\n * @param subscribe - Optional subscription function for reactivity\n * @param getValue - Optional function to get the current field value reactively\n * @returns\n */\n export function create<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n >(options: createOptions<TResolvedStep, TSteps, TChosenSteps>) {\n const { propsCreator, subscribe, getValue, selectorCtx } = options;\n\n const Field: field.component<TResolvedStep, TSteps, TChosenSteps> = (\n props\n ) => {\n const { name, children, selectorFn } = props;\n\n // Always call the hook, but use no-op functions if subscribe/getValue aren't provided\n const subscribeFn = subscribe || (() => () => {});\n const getValueFn = getValue || (() => undefined);\n\n // Subscribe to changes to trigger rerenders\n const currentValue = useSyncExternalStore(\n subscribeFn,\n () => getValueFn(name),\n () => getValueFn(name)\n );\n\n let createdProps = propsCreator(name);\n\n // If getValue is provided, override defaultValue with the reactive value\n if (getValue) {\n createdProps = {\n ...createdProps,\n defaultValue: currentValue,\n } as typeof createdProps;\n }\n\n if (selectorFn) {\n const Selector = selector.create<TResolvedStep, TSteps, TChosenSteps>(\n () => selectorCtx,\n subscribeFn\n );\n\n return (\n <Selector selector={selectorFn}>\n {(value) =>\n children({\n ...createdProps,\n selected: { value: value as never },\n })\n }\n </Selector>\n );\n }\n\n return children(createdProps as never);\n };\n\n return memo(Field);\n }\n}\n"],"mappings":";;;;;;;CAmKS,SAAS,OAId,SAA6D;EAC7D,MAAM,EAAE,cAAc,WAAW,UAAU,gBAAgB;EAE3D,MAAMA,SACJ,UACG;GACH,MAAM,EAAE,MAAM,UAAU,eAAe;GAGvC,MAAM,cAAc,0BAA0B;GAC9C,MAAM,aAAa,mBAAmB;GAGtC,MAAM,eAAe,qBACnB,mBACM,WAAW,KAAK,QAChB,WAAW,KAAK,CACvB;GAED,IAAI,eAAe,aAAa,KAAK;AAGrC,OAAI,SACF,gBAAe;IACb,GAAG;IACH,cAAc;IACf;AAGH,OAAI,WAMF,QACE,oBANe,SAAS,aAClB,aACN,YACD;IAGW,UAAU;eAChB,UACA,SAAS;KACP,GAAG;KACH,UAAU,EAAS,OAAgB;KACpC,CAAC;KAEK;AAIf,UAAO,SAAS,aAAsB;;AAGxC,SAAO,KAAK,MAAM"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
let __jfdevelops_multi_step_form_core__internals = require("@jfdevelops/multi-step-form-core/_internals");
|
|
1
2
|
let react = require("react");
|
|
2
3
|
|
|
3
4
|
//#region src/hooks/use-selector.ts
|
|
@@ -10,7 +11,7 @@ function createUseSelector(createCtx, subscribe) {
|
|
|
10
11
|
snapshotCacheRef.current = { value: newValue };
|
|
11
12
|
return newValue;
|
|
12
13
|
}
|
|
13
|
-
if (!
|
|
14
|
+
if (!__jfdevelops_multi_step_form_core__internals.path.equalsAtPaths({ value: snapshotCacheRef.current.value }, ["value"], newValue).ok) snapshotCacheRef.current = { value: newValue };
|
|
14
15
|
return snapshotCacheRef.current.value;
|
|
15
16
|
};
|
|
16
17
|
return (0, react.useSyncExternalStore)(subscribe, () => getSnapshot(), () => getSnapshot());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-selector.cjs","names":[],"sources":["../../src/hooks/use-selector.ts"],"sourcesContent":["import type {\n AnyResolvedStep,\n StepNumbers,\n HelperFnChosenSteps,\n Expand,\n HelperFnCtx,\n} from '@jfdevelops/multi-step-form-core';\nimport { useSyncExternalStore, useRef } from 'react';\n\nexport type UseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n> = ReturnType<typeof createUseSelector<TResolvedStep, TSteps, TChosenSteps>>;\nexport type SelectorFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TSelected\n> = (\n ctx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>\n) => TSelected;\n\nexport function createUseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n>(\n createCtx: () => Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>,\n subscribe: (listener: () => void) => () => void\n) {\n return <selected>(\n selector: SelectorFn<TResolvedStep, TSteps, TChosenSteps, selected>\n ) => {\n const snapshotCacheRef = useRef<{ value: selected } | null>(null);\n\n const getSnapshot = () => {\n const currentCtx = createCtx();\n const newValue = selector(currentCtx);\n\n // Cache the result to ensure stable reference\n if (snapshotCacheRef.current === null) {\n snapshotCacheRef.current = { value: newValue };\n
|
|
1
|
+
{"version":3,"file":"use-selector.cjs","names":["path"],"sources":["../../src/hooks/use-selector.ts"],"sourcesContent":["import type {\n AnyResolvedStep,\n StepNumbers,\n HelperFnChosenSteps,\n Expand,\n HelperFnCtx,\n} from '@jfdevelops/multi-step-form-core';\nimport { path } from '@jfdevelops/multi-step-form-core/_internals';\nimport { useSyncExternalStore, useRef } from 'react';\n\nexport type UseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n> = ReturnType<typeof createUseSelector<TResolvedStep, TSteps, TChosenSteps>>;\nexport type SelectorFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TSelected\n> = (\n ctx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>\n) => TSelected;\n\nexport function createUseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n>(\n createCtx: () => Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>,\n subscribe: (listener: () => void) => () => void\n) {\n return <selected>(\n selector: SelectorFn<TResolvedStep, TSteps, TChosenSteps, selected>\n ) => {\n const snapshotCacheRef = useRef<{ value: selected } | null>(null);\n\n const getSnapshot = () => {\n const currentCtx = createCtx();\n const newValue = selector(currentCtx);\n\n // Cache the result to ensure stable reference\n if (snapshotCacheRef.current === null) {\n snapshotCacheRef.current = { value: newValue };\n return newValue;\n }\n\n // Only update if the value actually changed (deep comparison using path.equalsAtPaths)\n const comparisonResult = path.equalsAtPaths(\n { value: snapshotCacheRef.current.value },\n ['value'],\n newValue\n );\n\n if (!comparisonResult.ok) {\n snapshotCacheRef.current = { value: newValue };\n }\n\n return snapshotCacheRef.current.value;\n };\n\n return useSyncExternalStore(\n subscribe,\n () => getSnapshot(),\n () => getSnapshot()\n );\n };\n}\n"],"mappings":";;;;AAwBA,SAAgB,kBAKd,WACA,WACA;AACA,SACE,aACG;EACH,MAAM,qCAAsD,KAAK;EAEjE,MAAM,oBAAoB;GAExB,MAAM,WAAW,SADE,WAAW,CACO;AAGrC,OAAI,iBAAiB,YAAY,MAAM;AACrC,qBAAiB,UAAU,EAAE,OAAO,UAAU;AAC9C,WAAO;;AAUT,OAAI,CANqBA,kDAAK,cAC5B,EAAE,OAAO,iBAAiB,QAAQ,OAAO,EACzC,CAAC,QAAQ,EACT,SACD,CAEqB,GACpB,kBAAiB,UAAU,EAAE,OAAO,UAAU;AAGhD,UAAO,iBAAiB,QAAQ;;AAGlC,yCACE,iBACM,aAAa,QACb,aAAa,CACpB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { path } from "@jfdevelops/multi-step-form-core/_internals";
|
|
1
2
|
import { useRef, useSyncExternalStore } from "react";
|
|
2
3
|
|
|
3
4
|
//#region src/hooks/use-selector.ts
|
|
@@ -10,7 +11,7 @@ function createUseSelector(createCtx, subscribe) {
|
|
|
10
11
|
snapshotCacheRef.current = { value: newValue };
|
|
11
12
|
return newValue;
|
|
12
13
|
}
|
|
13
|
-
if (!
|
|
14
|
+
if (!path.equalsAtPaths({ value: snapshotCacheRef.current.value }, ["value"], newValue).ok) snapshotCacheRef.current = { value: newValue };
|
|
14
15
|
return snapshotCacheRef.current.value;
|
|
15
16
|
};
|
|
16
17
|
return useSyncExternalStore(subscribe, () => getSnapshot(), () => getSnapshot());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-selector.mjs","names":[],"sources":["../../src/hooks/use-selector.ts"],"sourcesContent":["import type {\n AnyResolvedStep,\n StepNumbers,\n HelperFnChosenSteps,\n Expand,\n HelperFnCtx,\n} from '@jfdevelops/multi-step-form-core';\nimport { useSyncExternalStore, useRef } from 'react';\n\nexport type UseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n> = ReturnType<typeof createUseSelector<TResolvedStep, TSteps, TChosenSteps>>;\nexport type SelectorFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TSelected\n> = (\n ctx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>\n) => TSelected;\n\nexport function createUseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n>(\n createCtx: () => Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>,\n subscribe: (listener: () => void) => () => void\n) {\n return <selected>(\n selector: SelectorFn<TResolvedStep, TSteps, TChosenSteps, selected>\n ) => {\n const snapshotCacheRef = useRef<{ value: selected } | null>(null);\n\n const getSnapshot = () => {\n const currentCtx = createCtx();\n const newValue = selector(currentCtx);\n\n // Cache the result to ensure stable reference\n if (snapshotCacheRef.current === null) {\n snapshotCacheRef.current = { value: newValue };\n
|
|
1
|
+
{"version":3,"file":"use-selector.mjs","names":[],"sources":["../../src/hooks/use-selector.ts"],"sourcesContent":["import type {\n AnyResolvedStep,\n StepNumbers,\n HelperFnChosenSteps,\n Expand,\n HelperFnCtx,\n} from '@jfdevelops/multi-step-form-core';\nimport { path } from '@jfdevelops/multi-step-form-core/_internals';\nimport { useSyncExternalStore, useRef } from 'react';\n\nexport type UseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n> = ReturnType<typeof createUseSelector<TResolvedStep, TSteps, TChosenSteps>>;\nexport type SelectorFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TSelected\n> = (\n ctx: Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>\n) => TSelected;\n\nexport function createUseSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>\n>(\n createCtx: () => Expand<HelperFnCtx<TResolvedStep, TSteps, TChosenSteps>>,\n subscribe: (listener: () => void) => () => void\n) {\n return <selected>(\n selector: SelectorFn<TResolvedStep, TSteps, TChosenSteps, selected>\n ) => {\n const snapshotCacheRef = useRef<{ value: selected } | null>(null);\n\n const getSnapshot = () => {\n const currentCtx = createCtx();\n const newValue = selector(currentCtx);\n\n // Cache the result to ensure stable reference\n if (snapshotCacheRef.current === null) {\n snapshotCacheRef.current = { value: newValue };\n return newValue;\n }\n\n // Only update if the value actually changed (deep comparison using path.equalsAtPaths)\n const comparisonResult = path.equalsAtPaths(\n { value: snapshotCacheRef.current.value },\n ['value'],\n newValue\n );\n\n if (!comparisonResult.ok) {\n snapshotCacheRef.current = { value: newValue };\n }\n\n return snapshotCacheRef.current.value;\n };\n\n return useSyncExternalStore(\n subscribe,\n () => getSnapshot(),\n () => getSnapshot()\n );\n };\n}\n"],"mappings":";;;;AAwBA,SAAgB,kBAKd,WACA,WACA;AACA,SACE,aACG;EACH,MAAM,mBAAmB,OAAmC,KAAK;EAEjE,MAAM,oBAAoB;GAExB,MAAM,WAAW,SADE,WAAW,CACO;AAGrC,OAAI,iBAAiB,YAAY,MAAM;AACrC,qBAAiB,UAAU,EAAE,OAAO,UAAU;AAC9C,WAAO;;AAUT,OAAI,CANqB,KAAK,cAC5B,EAAE,OAAO,iBAAiB,QAAQ,OAAO,EACzC,CAAC,QAAQ,EACT,SACD,CAEqB,GACpB,kBAAiB,UAAU,EAAE,OAAO,UAAU;AAGhD,UAAO,iBAAiB,QAAQ;;AAGlC,SAAO,qBACL,iBACM,aAAa,QACb,aAAa,CACpB"}
|
package/dist/step-schema.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_field = require('./field.cjs');
|
|
2
|
-
const require_form_config = require('./form-config.cjs');
|
|
3
1
|
const require_use_selector = require('./hooks/use-selector.cjs');
|
|
4
2
|
const require_selector = require('./selector.cjs');
|
|
3
|
+
const require_field = require('./field.cjs');
|
|
4
|
+
const require_form_config = require('./form-config.cjs');
|
|
5
5
|
const require_utils = require('./utils.cjs');
|
|
6
6
|
let __jfdevelops_multi_step_form_core = require("@jfdevelops/multi-step-form-core");
|
|
7
7
|
let __jfdevelops_multi_step_form_core__internals = require("@jfdevelops/multi-step-form-core/_internals");
|
|
@@ -91,37 +91,46 @@ var MultiStepFormStepSchema = class extends __jfdevelops_multi_step_form_core.Mu
|
|
|
91
91
|
const current = this.value[step];
|
|
92
92
|
(0, __jfdevelops_multi_step_form_core.invariant)("fields" in current, `[${step}:createComponent]: unable to find the "fields" for the current step`);
|
|
93
93
|
(0, __jfdevelops_multi_step_form_core.invariant)(typeof current.fields === "object", `[${step}:createComponent]: the "fields" property must be an object, was ${typeof current.fields}`);
|
|
94
|
-
const Field = require_field.field.create(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
94
|
+
const Field = require_field.field.create({
|
|
95
|
+
propsCreator: (name) => {
|
|
96
|
+
const currentStep = this.value[step];
|
|
97
|
+
const currentFields = Object.keys(currentStep.fields);
|
|
98
|
+
(0, __jfdevelops_multi_step_form_core.invariant)(typeof name === "string", (formatter) => `[${step}:Field]: the "name" prop must be a string and a valid field for ${step}. Available fields include: "${formatter.format(currentFields)}"`);
|
|
99
|
+
(0, __jfdevelops_multi_step_form_core.invariant)(name in currentStep.fields, (formatter) => `[${step}:Field]: the field "${name}" doesn't exist for the current step. Available fields include: "${formatter.format(currentFields)}".`);
|
|
100
|
+
(0, __jfdevelops_multi_step_form_core.invariant)("update" in currentStep, `[${step}:Field]: No "update" function was found`);
|
|
101
|
+
const defaultValue = this.getValue(step, name);
|
|
102
|
+
const { label, nameTransformCasing, type } = currentStep.fields[name];
|
|
103
|
+
const targetFields = `fields.${name}.defaultValue`;
|
|
104
|
+
return {
|
|
105
|
+
defaultValue,
|
|
106
|
+
label,
|
|
107
|
+
nameTransformCasing,
|
|
108
|
+
type,
|
|
109
|
+
name,
|
|
110
|
+
onInputChange: (value) => {
|
|
111
|
+
let resolvedValue;
|
|
112
|
+
if (typeof value === "function") resolvedValue = value(this.getValue(step, name));
|
|
113
|
+
else resolvedValue = value;
|
|
114
|
+
this.update({
|
|
115
|
+
targetStep: step,
|
|
116
|
+
updater: resolvedValue,
|
|
117
|
+
fields: [targetFields]
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
reset: () => this.reset({
|
|
121
|
+
fields: [targetFields],
|
|
122
|
+
targetStep: step
|
|
123
|
+
})
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
subscribe: this.subscribe,
|
|
127
|
+
getValue: (name) => this.getValue(step, name),
|
|
128
|
+
selectorCtx: this.createResolvedCtx({
|
|
129
|
+
stepData,
|
|
130
|
+
ctxData,
|
|
131
|
+
logger
|
|
132
|
+
})
|
|
133
|
+
});
|
|
125
134
|
const useSelector = require_use_selector.createUseSelector(() => this.createResolvedCtx({
|
|
126
135
|
stepData,
|
|
127
136
|
ctxData,
|
package/dist/step-schema.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-schema.cjs","names":["MultiStepFormStepSchemaBase","#internal","MultiStepFormStepSchemaInternal","resolvedCtxCreator","MultiStepFormLogger","getValidatedCustomInputHooks","field","createUseSelector","selector","MultiStepFormSchemaConfig","createDefaultValues"],"sources":["../src/step-schema.ts"],"sourcesContent":["import {\n type AnyStepField,\n type CasingType,\n type Constrain,\n createCtx,\n type CreateHelperFunctionOptionsBase,\n createStep,\n type DefaultCasing,\n type DefaultStorageKey,\n type Expand,\n type GetCurrentStep,\n type GetFieldsForStep,\n type HelperFnChosenSteps,\n type HelperFnCtx,\n type HelperFnInputBase,\n invariant,\n MultiStepFormLogger,\n type MultiStepFormSchemaStepConfig as MultiStepFormSchemaStepBaseConfig,\n MultiStepFormStepSchema as MultiStepFormStepSchemaBase,\n type Relaxed,\n type ResetFn,\n type ResolvedStep as ResolvedCoreStep,\n type Step,\n type StepNumbers,\n type StrippedResolvedStep,\n type UpdateFn,\n type Updater,\n type ValidStepKey,\n} from '@jfdevelops/multi-step-form-core';\nimport { MultiStepFormStepSchemaInternal } from '@jfdevelops/multi-step-form-core/_internals';\nimport { type ComponentPropsWithRef, type ReactNode } from 'react';\nimport { field } from './field';\nimport { MultiStepFormSchemaConfig } from './form-config';\nimport { createUseSelector, type UseSelector } from './hooks/use-selector';\nimport { selector } from './selector';\nimport { getValidatedCustomInputHooks, resolvedCtxCreator } from './utils';\n\nexport interface MultiStepFormSchemaStepConfig<\n TStep extends Step<TCasing>,\n TCasing extends CasingType,\n TStorageKey extends string,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object,\n TResolvedStep extends ResolvedStep<TStep, TCasing> = ResolvedStep<\n TStep,\n TCasing\n >\n> extends MultiStepFormSchemaStepBaseConfig<TStep, TCasing, TStorageKey>,\n MultiStepFormSchemaConfig.Form<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n > {}\n\nexport type CreateFunction<TArgs extends any[], TReturn = void> = (\n ...args: TArgs\n) => TReturn;\nexport type CreateComponent<TInput, TProps> = CreateFunction<\n [input: TInput, props: TProps],\n ReactNode\n>;\n\nexport type CreateComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps\n> = CreateComponent<\n HelperFnInputBase<TResolvedStep, TSteps, TChosenSteps>,\n TProps\n>;\nexport type CreatedMultiStepFormComponent<TProps> = TProps extends undefined\n ? () => ReactNode\n : (props: TProps) => ReactNode;\nexport type CreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n // This is needed to make TS happy with all types\n TStepNumbers extends StepNumbers<TResolvedStep>\n> = <\n chosenSteps extends HelperFnChosenSteps<TResolvedStep, TStepNumbers>,\n props = undefined\n>(\n options: CreateHelperFunctionOptionsBase<\n TResolvedStep,\n TStepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<TResolvedStep, TStepNumbers, chosenSteps, props>\n) => CreatedMultiStepFormComponent<props>;\n\nexport namespace StepSpecificComponent {\n // The logic for getting the formCtx only works for step specific `createComponent`\n // (i.e: step1.createComponent(...)) as of now. Reason is because I can't think of a good API for integrating the form\n // ctx into the main `createComponent` since multiple steps can be chosen. In that case\n // how would the logic work for when the form component should be defined in the callback?\n // Ideas:\n // - Make the main `createComponent` return a function that accepts the current step\n export type formComponent<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n > = TFormEnabledFor extends MultiStepFormSchemaConfig.defaultEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : TFormEnabledFor extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TFormEnabledFor[number] extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends TFormEnabledFor[number]\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {}\n : keyof TFormEnabledFor extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends keyof TFormEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {};\n export type onInputChange<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>,\n TTargetStep extends TStepNumbers\n > = <\n CurrentStepData extends GetCurrentStep<TResolvedStep, TTargetStep>,\n Field extends keyof CurrentStepData\n >(\n field: Field,\n updater: Updater<CurrentStepData[Field], Relaxed<CurrentStepData[Field]>>\n ) => void;\n export type updateWrappers<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = TStepNumber extends TSteps\n ? {\n /**\n * A useful wrapper around `update` to update the specific field.\n */\n onInputChange: UpdateFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n /**\n * A useful wrapper for `update` to reset a specific field's value to its\n * original config value.\n * @resetFn\n */\n reset: ResetFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n }\n : {};\n export type input<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TAdditionalCtx extends Record<string, unknown>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n > = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = HelperFnInputBase<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n never,\n TAdditionalCtx\n > &\n updateWrappers<TResolvedStep, TSteps, TChosenSteps, TStepNumber> & {\n Field: field.component<\n TResolvedStep,\n ValidStepKey<\n HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n >\n >;\n /**\n * A hook for reactively selecting a value from the form context.\n * The selector function receives the contextual data for the currently rendered step, and returns any derived value.\n * `useSelector` will automatically provide the latest context data on updates, and will subscribe the caller for automatic re-renders when the underlying data changes.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @returns The derived value, which will re-render the component on change\n *\n * @example\n * const someValue = useSelector(ctx => ctx.fields.username.value);\n */\n useSelector: UseSelector<TResolvedStep, TSteps, TChosenSteps>;\n /**\n * A component for reactively displaying a value from the form context.\n * Unlike `useSelector`, this component only re-renders itself, not the parent component.\n * Use this when you want to display a reactive value without causing parent re-renders.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @param children - Optional render prop that receives the selected value\n *\n * @example\n * <Selector selector={(ctx) => ctx.step1.fields.firstName.defaultValue}>\n * {(value) => <p>First name: {value}</p>}\n * </Selector>\n */\n Selector: selector.component<TResolvedStep, TSteps, TChosenSteps>;\n };\n\n export type callback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object,\n TAdditionalCtx extends Record<string, unknown>\n > = CreateComponent<\n Expand<\n input<TResolvedStep, TSteps, TChosenSteps, TAdditionalCtx> &\n formComponent<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n > &\n TAdditionalInput\n >,\n TProps\n >;\n export const DEFAULT_FORM_INSTANCE_ALIAS = 'form';\n export type defaultFormInstanceAlias = typeof DEFAULT_FORM_INSTANCE_ALIAS;\n export type formInstanceOptions<\n TAlias extends string,\n TRenderInput,\n TReturn\n > = {\n /**\n * The name of the return value of the `render` method.\n */\n alias?: TAlias;\n /**\n * A function that renders/creates the form instance. This function will be called\n * at the top level of the component, ensuring hooks are called in a valid React context.\n *\n * @param input - The input object containing context and default values\n * @returns The form instance (typically from a hook like `useForm`)\n *\n * @example\n * ```tsx\n * useFormInstance: {\n * render({ defaultValues }) {\n * return useForm({\n * defaultValues,\n * });\n * },\n * }\n * ```\n *\n * **Verification**: The hook call is automatically verified:\n * - Errors are caught and reported with helpful messages\n * - In development, hook calls are logged to console.debug\n * - The hook must be called at the component top level (enforced by the framework)\n */\n render: CreateFunction<[input: TRenderInput], TReturn>;\n };\n\n export interface CtxSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TCtx\n > {\n /**\n * A function to select the data that will be available in the `fn`'s ctx.\n * @param input The available input to create the context with.\n * @returns The created ctx.\n */\n ctxData?: (\n input: HelperFnInputBase<\n TResolvedStep,\n TSteps,\n 'all',\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TTargetStep>\n >\n ) => TCtx;\n }\n\n export type options<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormInstanceAlias extends string,\n TFormInstance,\n TCtx\n > = CtxSelector<TResolvedStep, TSteps, TTargetStep, TCtx> & {\n /**\n * If set to `true`, you'll be able to open the {@linkcode console} to view logs.\n */\n debug?: boolean;\n useFormInstance?: formInstanceOptions<\n TFormInstanceAlias,\n Pick<HelperFnInputBase<TResolvedStep, TSteps, TTargetStep>, 'ctx'> & {\n /**\n * An object containing all the default values for the current step.\n */\n defaultValues: Expand<\n ExtractedDefaultValues<TResolvedStep, TSteps, TTargetStep>\n >;\n },\n TFormInstance\n >;\n };\n}\n\nexport type CreateStepSpecificComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object = {},\n TAdditionalCtx extends Record<string, unknown> = {}\n> = StepSpecificComponent.callback<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TProps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n TAdditionalInput,\n TAdditionalCtx\n>;\n\nexport type ExtractedDefaultValues<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TExtractedStepNumber extends number = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TTargetStep\n >,\n TFields extends GetFieldsForStep<\n TResolvedStep,\n ValidStepKey<TExtractedStepNumber>\n > = GetFieldsForStep<TResolvedStep, ValidStepKey<TExtractedStepNumber>>\n> = { [field in keyof TFields]: TFields[field]['defaultValue'] };\nexport interface StepSpecificCreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n> {\n /**\n * A utility function to easily create a component for the current step.\n * @param fn The callback function where the component is defined.\n */\n <props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n /**\n * A utility function to easily create a component for the current step.\n * @param options Specific config options for creating a component for the current step.\n * @param fn The callback function where the component is defined.\n * @returns The created component.\n */\n <\n formInstance,\n additionalCtx extends Record<string, unknown> = {},\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined\n >(\n options: StepSpecificComponent.options<\n TResolvedStep,\n TSteps,\n TTargetStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n { [_ in formInstanceAlias]: formInstance },\n additionalCtx\n >\n ): CreatedMultiStepFormComponent<props>;\n}\n\nexport type ResolvedStep<\n TStep extends Step<TDefaultCasing>,\n TDefaultCasing extends CasingType = DefaultCasing,\n TResolvedStep extends ResolvedCoreStep<\n TStep,\n TDefaultCasing\n > = ResolvedCoreStep<TStep, TDefaultCasing>,\n TFormAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n TFormProps extends object = ComponentPropsWithRef<'form'>\n> = {\n [stepKey in keyof TResolvedStep]: TResolvedStep[stepKey] &\n (stepKey extends ValidStepKey<StepNumbers<TResolvedStep>>\n ? {\n createComponent: StepSpecificCreateComponentFn<\n TResolvedStep,\n StepNumbers<TResolvedStep>,\n [stepKey],\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >;\n }\n : {});\n};\n\nexport type AnyResolvedStep = ResolvedStep<any, any, any>;\nexport interface HelperFunctions<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>\n> {\n createComponent: CreateComponentFn<TResolvedStep, TStepNumbers>;\n}\nnamespace CreateComponentImplConfig {\n export type stepSpecificConfig<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > = {\n isStepSpecific: true;\n defaultId: string;\n form?: MultiStepFormSchemaConfig.FormConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n };\n\n export type nonStepSpecific = {\n isStepSpecific: false;\n };\n\n export type config<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > =\n | nonStepSpecific\n | stepSpecificConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n}\n\n/**\n * Creates a default values object for the target step.\n * @param steps The steps schema.\n * @param targetStep The step to create the default values for.\n * @returns An object containing the field names and their default values.\n */\nexport function createDefaultValues<\n resolvedStep extends AnyResolvedStep,\n stepNumbers extends StepNumbers<resolvedStep>,\n targetStep extends ValidStepKey<stepNumbers>\n>(steps: resolvedStep, targetStep: targetStep) {\n invariant(\n targetStep in steps,\n `The target step ${targetStep} is not a valid step key`\n );\n\n const current = steps[targetStep as unknown as keyof resolvedStep];\n\n invariant('fields' in current, `No \"fields\" were found for ${targetStep}`);\n\n let defaultValues = {};\n\n for (const [fieldName, fieldValues] of Object.entries(\n current.fields as Record<string, Record<string, unknown>>\n )) {\n defaultValues = {\n ...defaultValues,\n [fieldName]: fieldValues.defaultValue,\n };\n }\n\n return defaultValues as Expand<\n ExtractedDefaultValues<resolvedStep, stepNumbers, [targetStep]>\n >;\n}\nexport class MultiStepFormStepSchema<\n step extends Step<casing>,\n casing extends CasingType = DefaultCasing,\n storageKey extends string = DefaultStorageKey,\n formAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n formEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<resolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n formProps extends object = ComponentPropsWithRef<'form'>,\n core extends ResolvedCoreStep<step, casing> = ResolvedCoreStep<\n step,\n casing\n >,\n resolvedStep extends ResolvedStep<\n step,\n casing,\n core,\n formAlias,\n formEnabledFor,\n formProps\n > = ResolvedStep<step, casing, core, formAlias, formEnabledFor, formProps>,\n stepNumbers extends StepNumbers<resolvedStep> = StepNumbers<resolvedStep>\n >\n extends MultiStepFormStepSchemaBase<step, casing>\n implements HelperFunctions<resolvedStep, stepNumbers>\n{\n // @ts-ignore type doesn't match `MultiStepFormSchemaBase.value`\n value: resolvedStep;\n readonly #internal: MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >;\n\n constructor(\n config: MultiStepFormSchemaStepConfig<\n step,\n Constrain<casing, CasingType>,\n storageKey,\n formAlias,\n formEnabledFor,\n formProps\n >\n ) {\n const { form, ...rest } = config;\n\n super(rest as never);\n\n this.value = createStep(this.original);\n\n this.#internal = new MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >({\n originalValue: this.original,\n getValue: () => this.value,\n setValue: (next) => this.handlePostUpdate(next as never),\n });\n\n // this.value = this.#internal.enrichValues(resolvedValues);\n this.sync();\n this.value = this.#internal.enrichValues(this.value, (step) => {\n const key = `step${step as stepNumbers}`;\n const stepData = [key] as HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >;\n const id = form?.id ?? key;\n\n return {\n createComponent: this.createStepSpecificComponentFactory(stepData, {\n isStepSpecific: true,\n defaultId: id,\n form: form as never,\n }),\n };\n });\n }\n\n private createFormComponent(\n form: Omit<\n MultiStepFormSchemaConfig.FormConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n 'alias'\n >,\n defaultId: string\n ) {\n const { render, enabledForSteps = 'all', id = defaultId } = form;\n\n const ctx = {\n id,\n steps: createCtx(this.value, enabledForSteps as never),\n };\n\n return (props: formProps) => render(ctx, props);\n }\n\n private createResolvedCtx<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx\n >(\n options: {\n stepData: chosenStep;\n logger: MultiStepFormLogger;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n const { logger, stepData, ctxData } = options;\n // Create ctx fresh each time to ensure it has the latest this.value\n const ctx = createCtx<resolvedStep, stepNumbers, chosenStep>(\n this.value,\n stepData\n );\n let resolvedCtx = ctx as Expand<\n HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n >;\n\n if (ctxData) {\n const [targetStep] = stepData;\n const { [targetStep]: _, ...values } = this.value;\n const createResolvedCtx = resolvedCtxCreator(logger, values);\n\n resolvedCtx = createResolvedCtx({ ctx: resolvedCtx, ctxData });\n }\n\n return resolvedCtx;\n }\n\n private createStepSpecificComponentImpl<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx = {}\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n extraConfig?: {\n logger?: MultiStepFormLogger;\n input?: (\n ctx: Expand<HelperFnCtx<resolvedStep, stepNumbers, chosenStep>>\n ) => Record<string, unknown>;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n return <props>(fn: Function) =>\n ((props: props) => {\n const ctxData = extraConfig?.ctxData;\n const logger = extraConfig?.logger ?? new MultiStepFormLogger();\n const resolvedCtx = this.createResolvedCtx({\n stepData,\n ctxData,\n logger,\n });\n const extraInput = extraConfig?.input?.(resolvedCtx) ?? {};\n // Call hook functions from extraInput at the top level of the component\n // This ensures hooks are called in a valid React context (before any conditionals)\n const hookResults = getValidatedCustomInputHooks(extraInput);\n\n const { defaultId, form } = config;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n invariant(\n this.steps.isValidStepKey(step),\n `[createComponent]: the target step ${step} is invalid. Note, this error shouldn't appear as the target step should always be valid. If you see this error, please open an issue.`\n );\n\n const stepNumber = Number.parseInt(step.replace('step', ''));\n\n invariant(\n !Number.isNaN(stepNumber),\n `[${step}:\"createComponent\"]: an error occurred while extracting the number`\n );\n const current = this.value[step as keyof resolvedStep];\n\n // These checks are mostly for type safety. `current` should _always_ be in the proper format.\n // On the off chance that it's not, we have the checks here to help, but these checks are basically\n // just for type safety.\n invariant(\n 'fields' in current,\n `[${step}:createComponent]: unable to find the \"fields\" for the current step`\n );\n invariant(\n typeof current.fields === 'object',\n `[${step}:createComponent]: the \"fields\" property must be an object, was ${typeof current.fields}`\n );\n\n // Memoize Field component to prevent remounting on every render\n // This ensures input focus is maintained when ctx changes\n const Field = field.create<\n resolvedStep,\n HelperFnChosenSteps.resolve<resolvedStep, stepNumbers, chosenStep>\n >(\n (name) => {\n // Access current step data directly to avoid stale closure\n const currentStep = this.value[\n step as keyof resolvedStep\n ] as typeof current;\n const currentFields = Object.keys(\n currentStep.fields as Record<string, unknown>\n );\n\n invariant(\n typeof name === 'string',\n (formatter) =>\n `[${step}:Field]: the \"name\" prop must be a string and a valid field for ${step}. Available fields include: \"${formatter.format(\n currentFields\n )}\"`\n );\n // TODO add support for deep keys (`name`)\n\n invariant(\n name in (currentStep.fields as object),\n (formatter) =>\n `[${step}:Field]: the field \"${name}\" doesn't exist for the current step. Available fields include: \"${formatter.format(\n currentFields\n )}\".`\n );\n\n invariant(\n 'update' in currentStep,\n `[${step}:Field]: No \"update\" function was found`\n );\n\n const defaultValue = this.getValue(step as never, name as never);\n\n const { label, nameTransformCasing, type } = (\n currentStep.fields as AnyStepField\n )[name];\n const targetFields = `fields.${name}.defaultValue`;\n\n return {\n defaultValue,\n label,\n nameTransformCasing,\n type,\n name,\n onInputChange: (value: unknown) => {\n // Handle Updater pattern: if value is a function, call it with the current field value\n let resolvedValue;\n\n if (typeof value === 'function') {\n const defaultValue = this.getValue(\n step as never,\n name as never\n );\n\n resolvedValue = value(defaultValue);\n } else {\n resolvedValue = value;\n }\n\n this.update({\n targetStep: step,\n updater: resolvedValue as never,\n fields: [targetFields] as never,\n });\n },\n reset: () =>\n this.reset({\n fields: [targetFields] as never,\n targetStep: step,\n }),\n } as never;\n },\n this.subscribe,\n (name) => this.getValue(step as never, name as never)\n );\n\n // Create useSelector hook for reactive value access via selector\n // This allows getting values from ctx reactively without causing re-renders\n // Pass a function that creates fresh ctx on each call to avoid stale closures\n const useSelector = createUseSelector(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n // Create Selector component that uses useSelector internally\n // This allows parts of the UI to subscribe to specific values without\n // causing the parent component to re-render\n const Selector = selector.create(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n let fnInput = {\n ctx: resolvedCtx,\n onInputChange: this.#internal.createStepUpdaterFn(step),\n reset: this.#internal.createStepResetterFn(step),\n Field,\n useSelector,\n Selector,\n ...hookResults,\n };\n\n if (form) {\n const {\n alias = MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS,\n ...rest\n } = form;\n const enabledFor = rest.enabledForSteps ?? 'all';\n\n if (\n MultiStepFormSchemaConfig.isFormAvailable(\n stepData as never,\n enabledFor as never\n )\n ) {\n fnInput = {\n ...fnInput,\n [alias]: this.createFormComponent(rest, defaultId),\n };\n }\n\n return fn(fnInput, props);\n }\n\n return fn(\n {\n ...fnInput,\n [MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS]:\n MultiStepFormSchemaConfig.createDefaultForm(defaultId),\n },\n props\n );\n }) as CreatedMultiStepFormComponent<props>;\n }\n\n private createStepSpecificComponentFactory<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >\n // ctx: HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n ): StepSpecificCreateComponentFn<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formAlias,\n formProps,\n formEnabledFor\n > {\n const createStepSpecificComponentImpl =\n this.createStepSpecificComponentImpl.bind(this);\n const createDefaultValues = this.createDefaultValues.bind(this);\n const [targetStep] = stepData;\n\n function impl<props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n options: StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n optionsOrFn:\n | StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >\n | CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >,\n fn?: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ) {\n function createStepSpecificComponent() {\n invariant(\n typeof optionsOrFn === 'function',\n 'The first argument must be a function'\n );\n\n return createStepSpecificComponentImpl(stepData, config)(optionsOrFn);\n }\n\n if (typeof optionsOrFn === 'object') {\n const { useFormInstance, ctxData, debug } = optionsOrFn;\n const logger = new MultiStepFormLogger({\n debug,\n prefix(prefix) {\n return `${prefix}-${targetStep}-createComponent`;\n },\n });\n\n logger.info('First argument is an object');\n\n invariant(\n typeof fn === 'function',\n 'The second argument must be a function'\n );\n\n if (useFormInstance) {\n const {\n render,\n alias = StepSpecificComponent.DEFAULT_FORM_INSTANCE_ALIAS,\n } = useFormInstance;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n input: (ctx) => {\n const defaultValues = createDefaultValues(step) as never;\n\n return {\n [alias]: () =>\n render({\n ctx,\n defaultValues,\n }),\n };\n },\n })(fn);\n }\n\n if (ctxData) {\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n })(fn);\n }\n\n // Empty options object. Can throw here 🤷♂️\n // Maybe add \"global\" - top level config - option to tune fine grained errors.\n return createStepSpecificComponent();\n }\n\n return createStepSpecificComponent();\n }\n\n return impl;\n }\n\n /**\n * A helper function to create a component for a specific step.\n * @param options The options for creating the step specific component.\n * @param fn A callback that is used for accessing the target step's data and defining\n * any props that the component should have. This function must return a valid `JSX` element.\n * @returns The created component for the step.\n */\n createComponent<\n chosenSteps extends HelperFnChosenSteps<resolvedStep, stepNumbers>,\n props = undefined\n >(\n options: CreateHelperFunctionOptionsBase<\n resolvedStep,\n stepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<resolvedStep, stepNumbers, chosenSteps, props>\n ) {\n const { stepData } = options;\n const ctx = createCtx<resolvedStep, stepNumbers, chosenSteps>(\n this.value,\n stepData\n ) as never;\n\n return ((props?: props) =>\n fn(ctx, props as any)) as CreatedMultiStepFormComponent<props>;\n }\n\n createDefaultValues<targetStep extends ValidStepKey<stepNumbers>>(\n targetStep: targetStep\n ) {\n return createDefaultValues(this.value, targetStep);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"step-schema.cjs","names":["MultiStepFormStepSchemaBase","#internal","MultiStepFormStepSchemaInternal","resolvedCtxCreator","MultiStepFormLogger","getValidatedCustomInputHooks","field","createUseSelector","selector","MultiStepFormSchemaConfig","createDefaultValues"],"sources":["../src/step-schema.ts"],"sourcesContent":["import {\n type AnyStepField,\n type CasingType,\n type Constrain,\n createCtx,\n type CreateHelperFunctionOptionsBase,\n createStep,\n type DefaultCasing,\n type DefaultStorageKey,\n type Expand,\n type GetCurrentStep,\n type GetFieldsForStep,\n type HelperFnChosenSteps,\n type HelperFnCtx,\n type HelperFnInputBase,\n invariant,\n MultiStepFormLogger,\n type MultiStepFormSchemaStepConfig as MultiStepFormSchemaStepBaseConfig,\n MultiStepFormStepSchema as MultiStepFormStepSchemaBase,\n type Relaxed,\n type ResetFn,\n type ResolvedStep as ResolvedCoreStep,\n type Step,\n type StepNumbers,\n type StrippedResolvedStep,\n type UpdateFn,\n type Updater,\n type ValidStepKey,\n} from '@jfdevelops/multi-step-form-core';\nimport { MultiStepFormStepSchemaInternal } from '@jfdevelops/multi-step-form-core/_internals';\nimport { type ComponentPropsWithRef, type ReactNode } from 'react';\nimport { field } from './field';\nimport { MultiStepFormSchemaConfig } from './form-config';\nimport { createUseSelector, type UseSelector } from './hooks/use-selector';\nimport { selector } from './selector';\nimport { getValidatedCustomInputHooks, resolvedCtxCreator } from './utils';\n\nexport interface MultiStepFormSchemaStepConfig<\n TStep extends Step<TCasing>,\n TCasing extends CasingType,\n TStorageKey extends string,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object,\n TResolvedStep extends ResolvedStep<TStep, TCasing> = ResolvedStep<\n TStep,\n TCasing\n >\n> extends MultiStepFormSchemaStepBaseConfig<TStep, TCasing, TStorageKey>,\n MultiStepFormSchemaConfig.Form<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n > {}\n\nexport type CreateFunction<TArgs extends any[], TReturn = void> = (\n ...args: TArgs\n) => TReturn;\nexport type CreateComponent<TInput, TProps> = CreateFunction<\n [input: TInput, props: TProps],\n ReactNode\n>;\n\nexport type CreateComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps\n> = CreateComponent<\n HelperFnInputBase<TResolvedStep, TSteps, TChosenSteps>,\n TProps\n>;\nexport type CreatedMultiStepFormComponent<TProps> = TProps extends undefined\n ? () => ReactNode\n : (props: TProps) => ReactNode;\nexport type CreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n // This is needed to make TS happy with all types\n TStepNumbers extends StepNumbers<TResolvedStep>\n> = <\n chosenSteps extends HelperFnChosenSteps<TResolvedStep, TStepNumbers>,\n props = undefined\n>(\n options: CreateHelperFunctionOptionsBase<\n TResolvedStep,\n TStepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<TResolvedStep, TStepNumbers, chosenSteps, props>\n) => CreatedMultiStepFormComponent<props>;\n\nexport namespace StepSpecificComponent {\n // The logic for getting the formCtx only works for step specific `createComponent`\n // (i.e: step1.createComponent(...)) as of now. Reason is because I can't think of a good API for integrating the form\n // ctx into the main `createComponent` since multiple steps can be chosen. In that case\n // how would the logic work for when the form component should be defined in the callback?\n // Ideas:\n // - Make the main `createComponent` return a function that accepts the current step\n export type formComponent<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n > = TFormEnabledFor extends MultiStepFormSchemaConfig.defaultEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : TFormEnabledFor extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TFormEnabledFor[number] extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends TFormEnabledFor[number]\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {}\n : keyof TFormEnabledFor extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends keyof TFormEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {};\n export type onInputChange<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>,\n TTargetStep extends TStepNumbers\n > = <\n CurrentStepData extends GetCurrentStep<TResolvedStep, TTargetStep>,\n Field extends keyof CurrentStepData\n >(\n field: Field,\n updater: Updater<CurrentStepData[Field], Relaxed<CurrentStepData[Field]>>\n ) => void;\n export type updateWrappers<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = TStepNumber extends TSteps\n ? {\n /**\n * A useful wrapper around `update` to update the specific field.\n */\n onInputChange: UpdateFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n /**\n * A useful wrapper for `update` to reset a specific field's value to its\n * original config value.\n * @resetFn\n */\n reset: ResetFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n }\n : {};\n export type input<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TAdditionalCtx extends Record<string, unknown>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n > = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = HelperFnInputBase<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n never,\n TAdditionalCtx\n > &\n updateWrappers<TResolvedStep, TSteps, TChosenSteps, TStepNumber> & {\n Field: field.component<TResolvedStep, TSteps, TChosenSteps>;\n /**\n * A hook for reactively selecting a value from the form context.\n * The selector function receives the contextual data for the currently rendered step, and returns any derived value.\n * `useSelector` will automatically provide the latest context data on updates, and will subscribe the caller for automatic re-renders when the underlying data changes.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @returns The derived value, which will re-render the component on change\n *\n * @example\n * const someValue = useSelector(ctx => ctx.fields.username.value);\n */\n useSelector: UseSelector<TResolvedStep, TSteps, TChosenSteps>;\n /**\n * A component for reactively displaying a value from the form context.\n * Unlike `useSelector`, this component only re-renders itself, not the parent component.\n * Use this when you want to display a reactive value without causing parent re-renders.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @param children - Optional render prop that receives the selected value\n *\n * @example\n * <Selector selector={(ctx) => ctx.step1.fields.firstName.defaultValue}>\n * {(value) => <p>First name: {value}</p>}\n * </Selector>\n */\n Selector: selector.component<TResolvedStep, TSteps, TChosenSteps>;\n };\n\n export type callback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object,\n TAdditionalCtx extends Record<string, unknown>\n > = CreateComponent<\n Expand<\n input<TResolvedStep, TSteps, TChosenSteps, TAdditionalCtx> &\n formComponent<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n > &\n TAdditionalInput\n >,\n TProps\n >;\n export const DEFAULT_FORM_INSTANCE_ALIAS = 'form';\n export type defaultFormInstanceAlias = typeof DEFAULT_FORM_INSTANCE_ALIAS;\n export type formInstanceOptions<\n TAlias extends string,\n TRenderInput,\n TReturn\n > = {\n /**\n * The name of the return value of the `render` method.\n */\n alias?: TAlias;\n /**\n * A function that renders/creates the form instance. This function will be called\n * at the top level of the component, ensuring hooks are called in a valid React context.\n *\n * @param input - The input object containing context and default values\n * @returns The form instance (typically from a hook like `useForm`)\n *\n * @example\n * ```tsx\n * useFormInstance: {\n * render({ defaultValues }) {\n * return useForm({\n * defaultValues,\n * });\n * },\n * }\n * ```\n *\n * **Verification**: The hook call is automatically verified:\n * - Errors are caught and reported with helpful messages\n * - In development, hook calls are logged to console.debug\n * - The hook must be called at the component top level (enforced by the framework)\n */\n render: CreateFunction<[input: TRenderInput], TReturn>;\n };\n\n export interface CtxSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TCtx\n > {\n /**\n * A function to select the data that will be available in the `fn`'s ctx.\n * @param input The available input to create the context with.\n * @returns The created ctx.\n */\n ctxData?: (\n input: HelperFnInputBase<\n TResolvedStep,\n TSteps,\n 'all',\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TTargetStep>\n >\n ) => TCtx;\n }\n\n export type options<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormInstanceAlias extends string,\n TFormInstance,\n TCtx\n > = CtxSelector<TResolvedStep, TSteps, TTargetStep, TCtx> & {\n /**\n * If set to `true`, you'll be able to open the {@linkcode console} to view logs.\n */\n debug?: boolean;\n useFormInstance?: formInstanceOptions<\n TFormInstanceAlias,\n Pick<HelperFnInputBase<TResolvedStep, TSteps, TTargetStep>, 'ctx'> & {\n /**\n * An object containing all the default values for the current step.\n */\n defaultValues: Expand<\n ExtractedDefaultValues<TResolvedStep, TSteps, TTargetStep>\n >;\n },\n TFormInstance\n >;\n };\n}\n\nexport type CreateStepSpecificComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object = {},\n TAdditionalCtx extends Record<string, unknown> = {}\n> = StepSpecificComponent.callback<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TProps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n TAdditionalInput,\n TAdditionalCtx\n>;\n\nexport type ExtractedDefaultValues<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TExtractedStepNumber extends number = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TTargetStep\n >,\n TFields extends GetFieldsForStep<\n TResolvedStep,\n ValidStepKey<TExtractedStepNumber>\n > = GetFieldsForStep<TResolvedStep, ValidStepKey<TExtractedStepNumber>>\n> = { [field in keyof TFields]: TFields[field]['defaultValue'] };\nexport interface StepSpecificCreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n> {\n /**\n * A utility function to easily create a component for the current step.\n * @param fn The callback function where the component is defined.\n */\n <props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n /**\n * A utility function to easily create a component for the current step.\n * @param options Specific config options for creating a component for the current step.\n * @param fn The callback function where the component is defined.\n * @returns The created component.\n */\n <\n formInstance,\n additionalCtx extends Record<string, unknown> = {},\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined\n >(\n options: StepSpecificComponent.options<\n TResolvedStep,\n TSteps,\n TTargetStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n { [_ in formInstanceAlias]: formInstance },\n additionalCtx\n >\n ): CreatedMultiStepFormComponent<props>;\n}\n\nexport type ResolvedStep<\n TStep extends Step<TDefaultCasing>,\n TDefaultCasing extends CasingType = DefaultCasing,\n TResolvedStep extends ResolvedCoreStep<\n TStep,\n TDefaultCasing\n > = ResolvedCoreStep<TStep, TDefaultCasing>,\n TFormAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n TFormProps extends object = ComponentPropsWithRef<'form'>\n> = {\n [stepKey in keyof TResolvedStep]: TResolvedStep[stepKey] &\n (stepKey extends ValidStepKey<StepNumbers<TResolvedStep>>\n ? {\n createComponent: StepSpecificCreateComponentFn<\n TResolvedStep,\n StepNumbers<TResolvedStep>,\n [stepKey],\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >;\n }\n : {});\n};\n\nexport type AnyResolvedStep = ResolvedStep<any, any, any>;\nexport interface HelperFunctions<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>\n> {\n createComponent: CreateComponentFn<TResolvedStep, TStepNumbers>;\n}\nnamespace CreateComponentImplConfig {\n export type stepSpecificConfig<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > = {\n isStepSpecific: true;\n defaultId: string;\n form?: MultiStepFormSchemaConfig.FormConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n };\n\n export type nonStepSpecific = {\n isStepSpecific: false;\n };\n\n export type config<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > =\n | nonStepSpecific\n | stepSpecificConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n}\n\n/**\n * Creates a default values object for the target step.\n * @param steps The steps schema.\n * @param targetStep The step to create the default values for.\n * @returns An object containing the field names and their default values.\n */\nexport function createDefaultValues<\n resolvedStep extends AnyResolvedStep,\n stepNumbers extends StepNumbers<resolvedStep>,\n targetStep extends ValidStepKey<stepNumbers>\n>(steps: resolvedStep, targetStep: targetStep) {\n invariant(\n targetStep in steps,\n `The target step ${targetStep} is not a valid step key`\n );\n\n const current = steps[targetStep as unknown as keyof resolvedStep];\n\n invariant('fields' in current, `No \"fields\" were found for ${targetStep}`);\n\n let defaultValues = {};\n\n for (const [fieldName, fieldValues] of Object.entries(\n current.fields as Record<string, Record<string, unknown>>\n )) {\n defaultValues = {\n ...defaultValues,\n [fieldName]: fieldValues.defaultValue,\n };\n }\n\n return defaultValues as Expand<\n ExtractedDefaultValues<resolvedStep, stepNumbers, [targetStep]>\n >;\n}\nexport class MultiStepFormStepSchema<\n step extends Step<casing>,\n casing extends CasingType = DefaultCasing,\n storageKey extends string = DefaultStorageKey,\n formAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n formEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<resolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n formProps extends object = ComponentPropsWithRef<'form'>,\n core extends ResolvedCoreStep<step, casing> = ResolvedCoreStep<\n step,\n casing\n >,\n resolvedStep extends ResolvedStep<\n step,\n casing,\n core,\n formAlias,\n formEnabledFor,\n formProps\n > = ResolvedStep<step, casing, core, formAlias, formEnabledFor, formProps>,\n stepNumbers extends StepNumbers<resolvedStep> = StepNumbers<resolvedStep>\n >\n extends MultiStepFormStepSchemaBase<step, casing>\n implements HelperFunctions<resolvedStep, stepNumbers>\n{\n // @ts-ignore type doesn't match `MultiStepFormSchemaBase.value`\n value: resolvedStep;\n readonly #internal: MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >;\n\n constructor(\n config: MultiStepFormSchemaStepConfig<\n step,\n Constrain<casing, CasingType>,\n storageKey,\n formAlias,\n formEnabledFor,\n formProps\n >\n ) {\n const { form, ...rest } = config;\n\n super(rest as never);\n\n this.value = createStep(this.original);\n\n this.#internal = new MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >({\n originalValue: this.original,\n getValue: () => this.value,\n setValue: (next) => this.handlePostUpdate(next as never),\n });\n\n // this.value = this.#internal.enrichValues(resolvedValues);\n this.sync();\n this.value = this.#internal.enrichValues(this.value, (step) => {\n const key = `step${step as stepNumbers}`;\n const stepData = [key] as HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >;\n const id = form?.id ?? key;\n\n return {\n createComponent: this.createStepSpecificComponentFactory(stepData, {\n isStepSpecific: true,\n defaultId: id,\n form: form as never,\n }),\n };\n });\n }\n\n private createFormComponent(\n form: Omit<\n MultiStepFormSchemaConfig.FormConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n 'alias'\n >,\n defaultId: string\n ) {\n const { render, enabledForSteps = 'all', id = defaultId } = form;\n\n const ctx = {\n id,\n steps: createCtx(this.value, enabledForSteps as never),\n };\n\n return (props: formProps) => render(ctx, props);\n }\n\n private createResolvedCtx<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx\n >(\n options: {\n stepData: chosenStep;\n logger: MultiStepFormLogger;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n const { logger, stepData, ctxData } = options;\n // Create ctx fresh each time to ensure it has the latest this.value\n const ctx = createCtx<resolvedStep, stepNumbers, chosenStep>(\n this.value,\n stepData\n );\n let resolvedCtx = ctx as Expand<\n HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n >;\n\n if (ctxData) {\n const [targetStep] = stepData;\n const { [targetStep]: _, ...values } = this.value;\n const createResolvedCtx = resolvedCtxCreator(logger, values);\n\n resolvedCtx = createResolvedCtx({ ctx: resolvedCtx, ctxData });\n }\n\n return resolvedCtx;\n }\n\n private createStepSpecificComponentImpl<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx = {}\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n extraConfig?: {\n logger?: MultiStepFormLogger;\n input?: (\n ctx: Expand<HelperFnCtx<resolvedStep, stepNumbers, chosenStep>>\n ) => Record<string, unknown>;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n return <props>(fn: Function) =>\n ((props: props) => {\n const ctxData = extraConfig?.ctxData;\n const logger = extraConfig?.logger ?? new MultiStepFormLogger();\n const resolvedCtx = this.createResolvedCtx({\n stepData,\n ctxData,\n logger,\n });\n const extraInput = extraConfig?.input?.(resolvedCtx) ?? {};\n // Call hook functions from extraInput at the top level of the component\n // This ensures hooks are called in a valid React context (before any conditionals)\n const hookResults = getValidatedCustomInputHooks(extraInput);\n\n const { defaultId, form } = config;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n invariant(\n this.steps.isValidStepKey(step),\n `[createComponent]: the target step ${step} is invalid. Note, this error shouldn't appear as the target step should always be valid. If you see this error, please open an issue.`\n );\n\n const stepNumber = Number.parseInt(step.replace('step', ''));\n\n invariant(\n !Number.isNaN(stepNumber),\n `[${step}:\"createComponent\"]: an error occurred while extracting the number`\n );\n const current = this.value[step as keyof resolvedStep];\n\n // These checks are mostly for type safety. `current` should _always_ be in the proper format.\n // On the off chance that it's not, we have the checks here to help, but these checks are basically\n // just for type safety.\n invariant(\n 'fields' in current,\n `[${step}:createComponent]: unable to find the \"fields\" for the current step`\n );\n invariant(\n typeof current.fields === 'object',\n `[${step}:createComponent]: the \"fields\" property must be an object, was ${typeof current.fields}`\n );\n\n // Memoize Field component to prevent remounting on every render\n // This ensures input focus is maintained when ctx changes\n const Field = field.create<resolvedStep, stepNumbers, chosenStep>({\n propsCreator: (name) => {\n // Access current step data directly to avoid stale closure\n const currentStep = this.value[\n step as keyof resolvedStep\n ] as typeof current;\n const currentFields = Object.keys(\n currentStep.fields as Record<string, unknown>\n );\n\n invariant(\n typeof name === 'string',\n (formatter) =>\n `[${step}:Field]: the \"name\" prop must be a string and a valid field for ${step}. Available fields include: \"${formatter.format(\n currentFields\n )}\"`\n );\n // TODO add support for deep keys (`name`)\n\n invariant(\n name in (currentStep.fields as object),\n (formatter) =>\n `[${step}:Field]: the field \"${name}\" doesn't exist for the current step. Available fields include: \"${formatter.format(\n currentFields\n )}\".`\n );\n\n invariant(\n 'update' in currentStep,\n `[${step}:Field]: No \"update\" function was found`\n );\n\n const defaultValue = this.getValue(step as never, name as never);\n\n const { label, nameTransformCasing, type } = (\n currentStep.fields as AnyStepField\n )[name];\n const targetFields = `fields.${name}.defaultValue`;\n\n return {\n defaultValue,\n label,\n nameTransformCasing,\n type,\n name,\n onInputChange: (value: unknown) => {\n // Handle Updater pattern: if value is a function, call it with the current field value\n let resolvedValue;\n\n if (typeof value === 'function') {\n const defaultValue = this.getValue(\n step as never,\n name as never\n );\n\n resolvedValue = value(defaultValue);\n } else {\n resolvedValue = value;\n }\n\n this.update({\n targetStep: step,\n updater: resolvedValue as never,\n fields: [targetFields] as never,\n });\n },\n reset: () =>\n this.reset({\n fields: [targetFields] as never,\n targetStep: step,\n }),\n } as never;\n },\n subscribe: this.subscribe,\n getValue: (name) => this.getValue(step as never, name as never),\n selectorCtx: this.createResolvedCtx({ stepData, ctxData, logger }),\n });\n\n // Create useSelector hook for reactive value access via selector\n // This allows getting values from ctx reactively without causing re-renders\n // Pass a function that creates fresh ctx on each call to avoid stale closures\n const useSelector = createUseSelector(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n // Create Selector component that uses useSelector internally\n // This allows parts of the UI to subscribe to specific values without\n // causing the parent component to re-render\n const Selector = selector.create(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n let fnInput = {\n ctx: resolvedCtx,\n onInputChange: this.#internal.createStepUpdaterFn(step),\n reset: this.#internal.createStepResetterFn(step),\n Field,\n useSelector,\n Selector,\n ...hookResults,\n };\n\n if (form) {\n const {\n alias = MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS,\n ...rest\n } = form;\n const enabledFor = rest.enabledForSteps ?? 'all';\n\n if (\n MultiStepFormSchemaConfig.isFormAvailable(\n stepData as never,\n enabledFor as never\n )\n ) {\n fnInput = {\n ...fnInput,\n [alias]: this.createFormComponent(rest, defaultId),\n };\n }\n\n return fn(fnInput, props);\n }\n\n return fn(\n {\n ...fnInput,\n [MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS]:\n MultiStepFormSchemaConfig.createDefaultForm(defaultId),\n },\n props\n );\n }) as CreatedMultiStepFormComponent<props>;\n }\n\n private createStepSpecificComponentFactory<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >\n // ctx: HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n ): StepSpecificCreateComponentFn<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formAlias,\n formProps,\n formEnabledFor\n > {\n const createStepSpecificComponentImpl =\n this.createStepSpecificComponentImpl.bind(this);\n const createDefaultValues = this.createDefaultValues.bind(this);\n const [targetStep] = stepData;\n\n function impl<props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n options: StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n optionsOrFn:\n | StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >\n | CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >,\n fn?: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ) {\n function createStepSpecificComponent() {\n invariant(\n typeof optionsOrFn === 'function',\n 'The first argument must be a function'\n );\n\n return createStepSpecificComponentImpl(stepData, config)(optionsOrFn);\n }\n\n if (typeof optionsOrFn === 'object') {\n const { useFormInstance, ctxData, debug } = optionsOrFn;\n const logger = new MultiStepFormLogger({\n debug,\n prefix(prefix) {\n return `${prefix}-${targetStep}-createComponent`;\n },\n });\n\n logger.info('First argument is an object');\n\n invariant(\n typeof fn === 'function',\n 'The second argument must be a function'\n );\n\n if (useFormInstance) {\n const {\n render,\n alias = StepSpecificComponent.DEFAULT_FORM_INSTANCE_ALIAS,\n } = useFormInstance;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n input: (ctx) => {\n const defaultValues = createDefaultValues(step) as never;\n\n return {\n [alias]: () =>\n render({\n ctx,\n defaultValues,\n }),\n };\n },\n })(fn);\n }\n\n if (ctxData) {\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n })(fn);\n }\n\n // Empty options object. Can throw here 🤷♂️\n // Maybe add \"global\" - top level config - option to tune fine grained errors.\n return createStepSpecificComponent();\n }\n\n return createStepSpecificComponent();\n }\n\n return impl;\n }\n\n /**\n * A helper function to create a component for a specific step.\n * @param options The options for creating the step specific component.\n * @param fn A callback that is used for accessing the target step's data and defining\n * any props that the component should have. This function must return a valid `JSX` element.\n * @returns The created component for the step.\n */\n createComponent<\n chosenSteps extends HelperFnChosenSteps<resolvedStep, stepNumbers>,\n props = undefined\n >(\n options: CreateHelperFunctionOptionsBase<\n resolvedStep,\n stepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<resolvedStep, stepNumbers, chosenSteps, props>\n ) {\n const { stepData } = options;\n const ctx = createCtx<resolvedStep, stepNumbers, chosenSteps>(\n this.value,\n stepData\n ) as never;\n\n return ((props?: props) =>\n fn(ctx, props as any)) as CreatedMultiStepFormComponent<props>;\n }\n\n createDefaultValues<targetStep extends ValidStepKey<stepNumbers>>(\n targetStep: targetStep\n ) {\n return createDefaultValues(this.value, targetStep);\n }\n}\n"],"mappings":"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"}
|
package/dist/step-schema.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { field } from "./field.cjs";
|
|
2
1
|
import { UseSelector } from "./hooks/use-selector.cjs";
|
|
2
|
+
import { field } from "./field.cjs";
|
|
3
3
|
import { selector } from "./selector.cjs";
|
|
4
4
|
import { MultiStepFormSchemaConfig } from "./form-config.cjs";
|
|
5
5
|
import * as _jfdevelops_multi_step_form_core0 from "@jfdevelops/multi-step-form-core";
|
|
@@ -29,7 +29,7 @@ declare namespace StepSpecificComponent {
|
|
|
29
29
|
reset: ResetFn.stepSpecific<TResolvedStep, TSteps, ValidStepKey<TStepNumber>>;
|
|
30
30
|
} : {};
|
|
31
31
|
type input<TResolvedStep extends StrippedResolvedStep<AnyResolvedStep$1>, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TAdditionalCtx extends Record<string, unknown>, TStepNumber extends HelperFnChosenSteps.extractStepNumber<TResolvedStep, TSteps, TChosenSteps> = HelperFnChosenSteps.extractStepNumber<TResolvedStep, TSteps, TChosenSteps>> = HelperFnInputBase<TResolvedStep, TSteps, TChosenSteps, never, TAdditionalCtx> & updateWrappers<TResolvedStep, TSteps, TChosenSteps, TStepNumber> & {
|
|
32
|
-
Field: field.component<TResolvedStep,
|
|
32
|
+
Field: field.component<TResolvedStep, TSteps, TChosenSteps>;
|
|
33
33
|
/**
|
|
34
34
|
* A hook for reactively selecting a value from the form context.
|
|
35
35
|
* The selector function receives the contextual data for the currently rendered step, and returns any derived value.
|
package/dist/step-schema.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { field } from "./field.mjs";
|
|
2
1
|
import { UseSelector } from "./hooks/use-selector.mjs";
|
|
2
|
+
import { field } from "./field.mjs";
|
|
3
3
|
import { selector } from "./selector.mjs";
|
|
4
4
|
import { MultiStepFormSchemaConfig } from "./form-config.mjs";
|
|
5
5
|
import * as _jfdevelops_multi_step_form_core0 from "@jfdevelops/multi-step-form-core";
|
|
@@ -29,7 +29,7 @@ declare namespace StepSpecificComponent {
|
|
|
29
29
|
reset: ResetFn.stepSpecific<TResolvedStep, TSteps, ValidStepKey<TStepNumber>>;
|
|
30
30
|
} : {};
|
|
31
31
|
type input<TResolvedStep extends StrippedResolvedStep<AnyResolvedStep$1>, TSteps extends StepNumbers<TResolvedStep>, TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>, TAdditionalCtx extends Record<string, unknown>, TStepNumber extends HelperFnChosenSteps.extractStepNumber<TResolvedStep, TSteps, TChosenSteps> = HelperFnChosenSteps.extractStepNumber<TResolvedStep, TSteps, TChosenSteps>> = HelperFnInputBase<TResolvedStep, TSteps, TChosenSteps, never, TAdditionalCtx> & updateWrappers<TResolvedStep, TSteps, TChosenSteps, TStepNumber> & {
|
|
32
|
-
Field: field.component<TResolvedStep,
|
|
32
|
+
Field: field.component<TResolvedStep, TSteps, TChosenSteps>;
|
|
33
33
|
/**
|
|
34
34
|
* A hook for reactively selecting a value from the form context.
|
|
35
35
|
* The selector function receives the contextual data for the currently rendered step, and returns any derived value.
|
package/dist/step-schema.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { field } from "./field.mjs";
|
|
2
|
-
import { MultiStepFormSchemaConfig } from "./form-config.mjs";
|
|
3
1
|
import { createUseSelector } from "./hooks/use-selector.mjs";
|
|
4
2
|
import { selector } from "./selector.mjs";
|
|
3
|
+
import { field } from "./field.mjs";
|
|
4
|
+
import { MultiStepFormSchemaConfig } from "./form-config.mjs";
|
|
5
5
|
import { getValidatedCustomInputHooks, resolvedCtxCreator } from "./utils.mjs";
|
|
6
6
|
import { MultiStepFormLogger, MultiStepFormStepSchema, createCtx, createStep, invariant } from "@jfdevelops/multi-step-form-core";
|
|
7
7
|
import { MultiStepFormStepSchemaInternal } from "@jfdevelops/multi-step-form-core/_internals";
|
|
@@ -91,37 +91,46 @@ var MultiStepFormStepSchema$1 = class extends MultiStepFormStepSchema {
|
|
|
91
91
|
const current = this.value[step];
|
|
92
92
|
invariant("fields" in current, `[${step}:createComponent]: unable to find the "fields" for the current step`);
|
|
93
93
|
invariant(typeof current.fields === "object", `[${step}:createComponent]: the "fields" property must be an object, was ${typeof current.fields}`);
|
|
94
|
-
const Field = field.create(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
94
|
+
const Field = field.create({
|
|
95
|
+
propsCreator: (name) => {
|
|
96
|
+
const currentStep = this.value[step];
|
|
97
|
+
const currentFields = Object.keys(currentStep.fields);
|
|
98
|
+
invariant(typeof name === "string", (formatter) => `[${step}:Field]: the "name" prop must be a string and a valid field for ${step}. Available fields include: "${formatter.format(currentFields)}"`);
|
|
99
|
+
invariant(name in currentStep.fields, (formatter) => `[${step}:Field]: the field "${name}" doesn't exist for the current step. Available fields include: "${formatter.format(currentFields)}".`);
|
|
100
|
+
invariant("update" in currentStep, `[${step}:Field]: No "update" function was found`);
|
|
101
|
+
const defaultValue = this.getValue(step, name);
|
|
102
|
+
const { label, nameTransformCasing, type } = currentStep.fields[name];
|
|
103
|
+
const targetFields = `fields.${name}.defaultValue`;
|
|
104
|
+
return {
|
|
105
|
+
defaultValue,
|
|
106
|
+
label,
|
|
107
|
+
nameTransformCasing,
|
|
108
|
+
type,
|
|
109
|
+
name,
|
|
110
|
+
onInputChange: (value) => {
|
|
111
|
+
let resolvedValue;
|
|
112
|
+
if (typeof value === "function") resolvedValue = value(this.getValue(step, name));
|
|
113
|
+
else resolvedValue = value;
|
|
114
|
+
this.update({
|
|
115
|
+
targetStep: step,
|
|
116
|
+
updater: resolvedValue,
|
|
117
|
+
fields: [targetFields]
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
reset: () => this.reset({
|
|
121
|
+
fields: [targetFields],
|
|
122
|
+
targetStep: step
|
|
123
|
+
})
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
subscribe: this.subscribe,
|
|
127
|
+
getValue: (name) => this.getValue(step, name),
|
|
128
|
+
selectorCtx: this.createResolvedCtx({
|
|
129
|
+
stepData,
|
|
130
|
+
ctxData,
|
|
131
|
+
logger
|
|
132
|
+
})
|
|
133
|
+
});
|
|
125
134
|
const useSelector = createUseSelector(() => this.createResolvedCtx({
|
|
126
135
|
stepData,
|
|
127
136
|
ctxData,
|
package/dist/step-schema.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"step-schema.mjs","names":["MultiStepFormStepSchema","MultiStepFormStepSchemaBase","#internal","createDefaultValues"],"sources":["../src/step-schema.ts"],"sourcesContent":["import {\n type AnyStepField,\n type CasingType,\n type Constrain,\n createCtx,\n type CreateHelperFunctionOptionsBase,\n createStep,\n type DefaultCasing,\n type DefaultStorageKey,\n type Expand,\n type GetCurrentStep,\n type GetFieldsForStep,\n type HelperFnChosenSteps,\n type HelperFnCtx,\n type HelperFnInputBase,\n invariant,\n MultiStepFormLogger,\n type MultiStepFormSchemaStepConfig as MultiStepFormSchemaStepBaseConfig,\n MultiStepFormStepSchema as MultiStepFormStepSchemaBase,\n type Relaxed,\n type ResetFn,\n type ResolvedStep as ResolvedCoreStep,\n type Step,\n type StepNumbers,\n type StrippedResolvedStep,\n type UpdateFn,\n type Updater,\n type ValidStepKey,\n} from '@jfdevelops/multi-step-form-core';\nimport { MultiStepFormStepSchemaInternal } from '@jfdevelops/multi-step-form-core/_internals';\nimport { type ComponentPropsWithRef, type ReactNode } from 'react';\nimport { field } from './field';\nimport { MultiStepFormSchemaConfig } from './form-config';\nimport { createUseSelector, type UseSelector } from './hooks/use-selector';\nimport { selector } from './selector';\nimport { getValidatedCustomInputHooks, resolvedCtxCreator } from './utils';\n\nexport interface MultiStepFormSchemaStepConfig<\n TStep extends Step<TCasing>,\n TCasing extends CasingType,\n TStorageKey extends string,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object,\n TResolvedStep extends ResolvedStep<TStep, TCasing> = ResolvedStep<\n TStep,\n TCasing\n >\n> extends MultiStepFormSchemaStepBaseConfig<TStep, TCasing, TStorageKey>,\n MultiStepFormSchemaConfig.Form<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n > {}\n\nexport type CreateFunction<TArgs extends any[], TReturn = void> = (\n ...args: TArgs\n) => TReturn;\nexport type CreateComponent<TInput, TProps> = CreateFunction<\n [input: TInput, props: TProps],\n ReactNode\n>;\n\nexport type CreateComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps\n> = CreateComponent<\n HelperFnInputBase<TResolvedStep, TSteps, TChosenSteps>,\n TProps\n>;\nexport type CreatedMultiStepFormComponent<TProps> = TProps extends undefined\n ? () => ReactNode\n : (props: TProps) => ReactNode;\nexport type CreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n // This is needed to make TS happy with all types\n TStepNumbers extends StepNumbers<TResolvedStep>\n> = <\n chosenSteps extends HelperFnChosenSteps<TResolvedStep, TStepNumbers>,\n props = undefined\n>(\n options: CreateHelperFunctionOptionsBase<\n TResolvedStep,\n TStepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<TResolvedStep, TStepNumbers, chosenSteps, props>\n) => CreatedMultiStepFormComponent<props>;\n\nexport namespace StepSpecificComponent {\n // The logic for getting the formCtx only works for step specific `createComponent`\n // (i.e: step1.createComponent(...)) as of now. Reason is because I can't think of a good API for integrating the form\n // ctx into the main `createComponent` since multiple steps can be chosen. In that case\n // how would the logic work for when the form component should be defined in the callback?\n // Ideas:\n // - Make the main `createComponent` return a function that accepts the current step\n export type formComponent<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n > = TFormEnabledFor extends MultiStepFormSchemaConfig.defaultEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : TFormEnabledFor extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TFormEnabledFor[number] extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends TFormEnabledFor[number]\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {}\n : keyof TFormEnabledFor extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends keyof TFormEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {};\n export type onInputChange<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>,\n TTargetStep extends TStepNumbers\n > = <\n CurrentStepData extends GetCurrentStep<TResolvedStep, TTargetStep>,\n Field extends keyof CurrentStepData\n >(\n field: Field,\n updater: Updater<CurrentStepData[Field], Relaxed<CurrentStepData[Field]>>\n ) => void;\n export type updateWrappers<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = TStepNumber extends TSteps\n ? {\n /**\n * A useful wrapper around `update` to update the specific field.\n */\n onInputChange: UpdateFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n /**\n * A useful wrapper for `update` to reset a specific field's value to its\n * original config value.\n * @resetFn\n */\n reset: ResetFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n }\n : {};\n export type input<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TAdditionalCtx extends Record<string, unknown>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n > = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = HelperFnInputBase<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n never,\n TAdditionalCtx\n > &\n updateWrappers<TResolvedStep, TSteps, TChosenSteps, TStepNumber> & {\n Field: field.component<\n TResolvedStep,\n ValidStepKey<\n HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n >\n >;\n /**\n * A hook for reactively selecting a value from the form context.\n * The selector function receives the contextual data for the currently rendered step, and returns any derived value.\n * `useSelector` will automatically provide the latest context data on updates, and will subscribe the caller for automatic re-renders when the underlying data changes.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @returns The derived value, which will re-render the component on change\n *\n * @example\n * const someValue = useSelector(ctx => ctx.fields.username.value);\n */\n useSelector: UseSelector<TResolvedStep, TSteps, TChosenSteps>;\n /**\n * A component for reactively displaying a value from the form context.\n * Unlike `useSelector`, this component only re-renders itself, not the parent component.\n * Use this when you want to display a reactive value without causing parent re-renders.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @param children - Optional render prop that receives the selected value\n *\n * @example\n * <Selector selector={(ctx) => ctx.step1.fields.firstName.defaultValue}>\n * {(value) => <p>First name: {value}</p>}\n * </Selector>\n */\n Selector: selector.component<TResolvedStep, TSteps, TChosenSteps>;\n };\n\n export type callback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object,\n TAdditionalCtx extends Record<string, unknown>\n > = CreateComponent<\n Expand<\n input<TResolvedStep, TSteps, TChosenSteps, TAdditionalCtx> &\n formComponent<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n > &\n TAdditionalInput\n >,\n TProps\n >;\n export const DEFAULT_FORM_INSTANCE_ALIAS = 'form';\n export type defaultFormInstanceAlias = typeof DEFAULT_FORM_INSTANCE_ALIAS;\n export type formInstanceOptions<\n TAlias extends string,\n TRenderInput,\n TReturn\n > = {\n /**\n * The name of the return value of the `render` method.\n */\n alias?: TAlias;\n /**\n * A function that renders/creates the form instance. This function will be called\n * at the top level of the component, ensuring hooks are called in a valid React context.\n *\n * @param input - The input object containing context and default values\n * @returns The form instance (typically from a hook like `useForm`)\n *\n * @example\n * ```tsx\n * useFormInstance: {\n * render({ defaultValues }) {\n * return useForm({\n * defaultValues,\n * });\n * },\n * }\n * ```\n *\n * **Verification**: The hook call is automatically verified:\n * - Errors are caught and reported with helpful messages\n * - In development, hook calls are logged to console.debug\n * - The hook must be called at the component top level (enforced by the framework)\n */\n render: CreateFunction<[input: TRenderInput], TReturn>;\n };\n\n export interface CtxSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TCtx\n > {\n /**\n * A function to select the data that will be available in the `fn`'s ctx.\n * @param input The available input to create the context with.\n * @returns The created ctx.\n */\n ctxData?: (\n input: HelperFnInputBase<\n TResolvedStep,\n TSteps,\n 'all',\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TTargetStep>\n >\n ) => TCtx;\n }\n\n export type options<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormInstanceAlias extends string,\n TFormInstance,\n TCtx\n > = CtxSelector<TResolvedStep, TSteps, TTargetStep, TCtx> & {\n /**\n * If set to `true`, you'll be able to open the {@linkcode console} to view logs.\n */\n debug?: boolean;\n useFormInstance?: formInstanceOptions<\n TFormInstanceAlias,\n Pick<HelperFnInputBase<TResolvedStep, TSteps, TTargetStep>, 'ctx'> & {\n /**\n * An object containing all the default values for the current step.\n */\n defaultValues: Expand<\n ExtractedDefaultValues<TResolvedStep, TSteps, TTargetStep>\n >;\n },\n TFormInstance\n >;\n };\n}\n\nexport type CreateStepSpecificComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object = {},\n TAdditionalCtx extends Record<string, unknown> = {}\n> = StepSpecificComponent.callback<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TProps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n TAdditionalInput,\n TAdditionalCtx\n>;\n\nexport type ExtractedDefaultValues<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TExtractedStepNumber extends number = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TTargetStep\n >,\n TFields extends GetFieldsForStep<\n TResolvedStep,\n ValidStepKey<TExtractedStepNumber>\n > = GetFieldsForStep<TResolvedStep, ValidStepKey<TExtractedStepNumber>>\n> = { [field in keyof TFields]: TFields[field]['defaultValue'] };\nexport interface StepSpecificCreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n> {\n /**\n * A utility function to easily create a component for the current step.\n * @param fn The callback function where the component is defined.\n */\n <props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n /**\n * A utility function to easily create a component for the current step.\n * @param options Specific config options for creating a component for the current step.\n * @param fn The callback function where the component is defined.\n * @returns The created component.\n */\n <\n formInstance,\n additionalCtx extends Record<string, unknown> = {},\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined\n >(\n options: StepSpecificComponent.options<\n TResolvedStep,\n TSteps,\n TTargetStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n { [_ in formInstanceAlias]: formInstance },\n additionalCtx\n >\n ): CreatedMultiStepFormComponent<props>;\n}\n\nexport type ResolvedStep<\n TStep extends Step<TDefaultCasing>,\n TDefaultCasing extends CasingType = DefaultCasing,\n TResolvedStep extends ResolvedCoreStep<\n TStep,\n TDefaultCasing\n > = ResolvedCoreStep<TStep, TDefaultCasing>,\n TFormAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n TFormProps extends object = ComponentPropsWithRef<'form'>\n> = {\n [stepKey in keyof TResolvedStep]: TResolvedStep[stepKey] &\n (stepKey extends ValidStepKey<StepNumbers<TResolvedStep>>\n ? {\n createComponent: StepSpecificCreateComponentFn<\n TResolvedStep,\n StepNumbers<TResolvedStep>,\n [stepKey],\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >;\n }\n : {});\n};\n\nexport type AnyResolvedStep = ResolvedStep<any, any, any>;\nexport interface HelperFunctions<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>\n> {\n createComponent: CreateComponentFn<TResolvedStep, TStepNumbers>;\n}\nnamespace CreateComponentImplConfig {\n export type stepSpecificConfig<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > = {\n isStepSpecific: true;\n defaultId: string;\n form?: MultiStepFormSchemaConfig.FormConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n };\n\n export type nonStepSpecific = {\n isStepSpecific: false;\n };\n\n export type config<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > =\n | nonStepSpecific\n | stepSpecificConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n}\n\n/**\n * Creates a default values object for the target step.\n * @param steps The steps schema.\n * @param targetStep The step to create the default values for.\n * @returns An object containing the field names and their default values.\n */\nexport function createDefaultValues<\n resolvedStep extends AnyResolvedStep,\n stepNumbers extends StepNumbers<resolvedStep>,\n targetStep extends ValidStepKey<stepNumbers>\n>(steps: resolvedStep, targetStep: targetStep) {\n invariant(\n targetStep in steps,\n `The target step ${targetStep} is not a valid step key`\n );\n\n const current = steps[targetStep as unknown as keyof resolvedStep];\n\n invariant('fields' in current, `No \"fields\" were found for ${targetStep}`);\n\n let defaultValues = {};\n\n for (const [fieldName, fieldValues] of Object.entries(\n current.fields as Record<string, Record<string, unknown>>\n )) {\n defaultValues = {\n ...defaultValues,\n [fieldName]: fieldValues.defaultValue,\n };\n }\n\n return defaultValues as Expand<\n ExtractedDefaultValues<resolvedStep, stepNumbers, [targetStep]>\n >;\n}\nexport class MultiStepFormStepSchema<\n step extends Step<casing>,\n casing extends CasingType = DefaultCasing,\n storageKey extends string = DefaultStorageKey,\n formAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n formEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<resolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n formProps extends object = ComponentPropsWithRef<'form'>,\n core extends ResolvedCoreStep<step, casing> = ResolvedCoreStep<\n step,\n casing\n >,\n resolvedStep extends ResolvedStep<\n step,\n casing,\n core,\n formAlias,\n formEnabledFor,\n formProps\n > = ResolvedStep<step, casing, core, formAlias, formEnabledFor, formProps>,\n stepNumbers extends StepNumbers<resolvedStep> = StepNumbers<resolvedStep>\n >\n extends MultiStepFormStepSchemaBase<step, casing>\n implements HelperFunctions<resolvedStep, stepNumbers>\n{\n // @ts-ignore type doesn't match `MultiStepFormSchemaBase.value`\n value: resolvedStep;\n readonly #internal: MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >;\n\n constructor(\n config: MultiStepFormSchemaStepConfig<\n step,\n Constrain<casing, CasingType>,\n storageKey,\n formAlias,\n formEnabledFor,\n formProps\n >\n ) {\n const { form, ...rest } = config;\n\n super(rest as never);\n\n this.value = createStep(this.original);\n\n this.#internal = new MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >({\n originalValue: this.original,\n getValue: () => this.value,\n setValue: (next) => this.handlePostUpdate(next as never),\n });\n\n // this.value = this.#internal.enrichValues(resolvedValues);\n this.sync();\n this.value = this.#internal.enrichValues(this.value, (step) => {\n const key = `step${step as stepNumbers}`;\n const stepData = [key] as HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >;\n const id = form?.id ?? key;\n\n return {\n createComponent: this.createStepSpecificComponentFactory(stepData, {\n isStepSpecific: true,\n defaultId: id,\n form: form as never,\n }),\n };\n });\n }\n\n private createFormComponent(\n form: Omit<\n MultiStepFormSchemaConfig.FormConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n 'alias'\n >,\n defaultId: string\n ) {\n const { render, enabledForSteps = 'all', id = defaultId } = form;\n\n const ctx = {\n id,\n steps: createCtx(this.value, enabledForSteps as never),\n };\n\n return (props: formProps) => render(ctx, props);\n }\n\n private createResolvedCtx<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx\n >(\n options: {\n stepData: chosenStep;\n logger: MultiStepFormLogger;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n const { logger, stepData, ctxData } = options;\n // Create ctx fresh each time to ensure it has the latest this.value\n const ctx = createCtx<resolvedStep, stepNumbers, chosenStep>(\n this.value,\n stepData\n );\n let resolvedCtx = ctx as Expand<\n HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n >;\n\n if (ctxData) {\n const [targetStep] = stepData;\n const { [targetStep]: _, ...values } = this.value;\n const createResolvedCtx = resolvedCtxCreator(logger, values);\n\n resolvedCtx = createResolvedCtx({ ctx: resolvedCtx, ctxData });\n }\n\n return resolvedCtx;\n }\n\n private createStepSpecificComponentImpl<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx = {}\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n extraConfig?: {\n logger?: MultiStepFormLogger;\n input?: (\n ctx: Expand<HelperFnCtx<resolvedStep, stepNumbers, chosenStep>>\n ) => Record<string, unknown>;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n return <props>(fn: Function) =>\n ((props: props) => {\n const ctxData = extraConfig?.ctxData;\n const logger = extraConfig?.logger ?? new MultiStepFormLogger();\n const resolvedCtx = this.createResolvedCtx({\n stepData,\n ctxData,\n logger,\n });\n const extraInput = extraConfig?.input?.(resolvedCtx) ?? {};\n // Call hook functions from extraInput at the top level of the component\n // This ensures hooks are called in a valid React context (before any conditionals)\n const hookResults = getValidatedCustomInputHooks(extraInput);\n\n const { defaultId, form } = config;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n invariant(\n this.steps.isValidStepKey(step),\n `[createComponent]: the target step ${step} is invalid. Note, this error shouldn't appear as the target step should always be valid. If you see this error, please open an issue.`\n );\n\n const stepNumber = Number.parseInt(step.replace('step', ''));\n\n invariant(\n !Number.isNaN(stepNumber),\n `[${step}:\"createComponent\"]: an error occurred while extracting the number`\n );\n const current = this.value[step as keyof resolvedStep];\n\n // These checks are mostly for type safety. `current` should _always_ be in the proper format.\n // On the off chance that it's not, we have the checks here to help, but these checks are basically\n // just for type safety.\n invariant(\n 'fields' in current,\n `[${step}:createComponent]: unable to find the \"fields\" for the current step`\n );\n invariant(\n typeof current.fields === 'object',\n `[${step}:createComponent]: the \"fields\" property must be an object, was ${typeof current.fields}`\n );\n\n // Memoize Field component to prevent remounting on every render\n // This ensures input focus is maintained when ctx changes\n const Field = field.create<\n resolvedStep,\n HelperFnChosenSteps.resolve<resolvedStep, stepNumbers, chosenStep>\n >(\n (name) => {\n // Access current step data directly to avoid stale closure\n const currentStep = this.value[\n step as keyof resolvedStep\n ] as typeof current;\n const currentFields = Object.keys(\n currentStep.fields as Record<string, unknown>\n );\n\n invariant(\n typeof name === 'string',\n (formatter) =>\n `[${step}:Field]: the \"name\" prop must be a string and a valid field for ${step}. Available fields include: \"${formatter.format(\n currentFields\n )}\"`\n );\n // TODO add support for deep keys (`name`)\n\n invariant(\n name in (currentStep.fields as object),\n (formatter) =>\n `[${step}:Field]: the field \"${name}\" doesn't exist for the current step. Available fields include: \"${formatter.format(\n currentFields\n )}\".`\n );\n\n invariant(\n 'update' in currentStep,\n `[${step}:Field]: No \"update\" function was found`\n );\n\n const defaultValue = this.getValue(step as never, name as never);\n\n const { label, nameTransformCasing, type } = (\n currentStep.fields as AnyStepField\n )[name];\n const targetFields = `fields.${name}.defaultValue`;\n\n return {\n defaultValue,\n label,\n nameTransformCasing,\n type,\n name,\n onInputChange: (value: unknown) => {\n // Handle Updater pattern: if value is a function, call it with the current field value\n let resolvedValue;\n\n if (typeof value === 'function') {\n const defaultValue = this.getValue(\n step as never,\n name as never\n );\n\n resolvedValue = value(defaultValue);\n } else {\n resolvedValue = value;\n }\n\n this.update({\n targetStep: step,\n updater: resolvedValue as never,\n fields: [targetFields] as never,\n });\n },\n reset: () =>\n this.reset({\n fields: [targetFields] as never,\n targetStep: step,\n }),\n } as never;\n },\n this.subscribe,\n (name) => this.getValue(step as never, name as never)\n );\n\n // Create useSelector hook for reactive value access via selector\n // This allows getting values from ctx reactively without causing re-renders\n // Pass a function that creates fresh ctx on each call to avoid stale closures\n const useSelector = createUseSelector(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n // Create Selector component that uses useSelector internally\n // This allows parts of the UI to subscribe to specific values without\n // causing the parent component to re-render\n const Selector = selector.create(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n let fnInput = {\n ctx: resolvedCtx,\n onInputChange: this.#internal.createStepUpdaterFn(step),\n reset: this.#internal.createStepResetterFn(step),\n Field,\n useSelector,\n Selector,\n ...hookResults,\n };\n\n if (form) {\n const {\n alias = MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS,\n ...rest\n } = form;\n const enabledFor = rest.enabledForSteps ?? 'all';\n\n if (\n MultiStepFormSchemaConfig.isFormAvailable(\n stepData as never,\n enabledFor as never\n )\n ) {\n fnInput = {\n ...fnInput,\n [alias]: this.createFormComponent(rest, defaultId),\n };\n }\n\n return fn(fnInput, props);\n }\n\n return fn(\n {\n ...fnInput,\n [MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS]:\n MultiStepFormSchemaConfig.createDefaultForm(defaultId),\n },\n props\n );\n }) as CreatedMultiStepFormComponent<props>;\n }\n\n private createStepSpecificComponentFactory<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >\n // ctx: HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n ): StepSpecificCreateComponentFn<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formAlias,\n formProps,\n formEnabledFor\n > {\n const createStepSpecificComponentImpl =\n this.createStepSpecificComponentImpl.bind(this);\n const createDefaultValues = this.createDefaultValues.bind(this);\n const [targetStep] = stepData;\n\n function impl<props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n options: StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n optionsOrFn:\n | StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >\n | CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >,\n fn?: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ) {\n function createStepSpecificComponent() {\n invariant(\n typeof optionsOrFn === 'function',\n 'The first argument must be a function'\n );\n\n return createStepSpecificComponentImpl(stepData, config)(optionsOrFn);\n }\n\n if (typeof optionsOrFn === 'object') {\n const { useFormInstance, ctxData, debug } = optionsOrFn;\n const logger = new MultiStepFormLogger({\n debug,\n prefix(prefix) {\n return `${prefix}-${targetStep}-createComponent`;\n },\n });\n\n logger.info('First argument is an object');\n\n invariant(\n typeof fn === 'function',\n 'The second argument must be a function'\n );\n\n if (useFormInstance) {\n const {\n render,\n alias = StepSpecificComponent.DEFAULT_FORM_INSTANCE_ALIAS,\n } = useFormInstance;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n input: (ctx) => {\n const defaultValues = createDefaultValues(step) as never;\n\n return {\n [alias]: () =>\n render({\n ctx,\n defaultValues,\n }),\n };\n },\n })(fn);\n }\n\n if (ctxData) {\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n })(fn);\n }\n\n // Empty options object. Can throw here 🤷♂️\n // Maybe add \"global\" - top level config - option to tune fine grained errors.\n return createStepSpecificComponent();\n }\n\n return createStepSpecificComponent();\n }\n\n return impl;\n }\n\n /**\n * A helper function to create a component for a specific step.\n * @param options The options for creating the step specific component.\n * @param fn A callback that is used for accessing the target step's data and defining\n * any props that the component should have. This function must return a valid `JSX` element.\n * @returns The created component for the step.\n */\n createComponent<\n chosenSteps extends HelperFnChosenSteps<resolvedStep, stepNumbers>,\n props = undefined\n >(\n options: CreateHelperFunctionOptionsBase<\n resolvedStep,\n stepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<resolvedStep, stepNumbers, chosenSteps, props>\n ) {\n const { stepData } = options;\n const ctx = createCtx<resolvedStep, stepNumbers, chosenSteps>(\n this.value,\n stepData\n ) as never;\n\n return ((props?: props) =>\n fn(ctx, props as any)) as CreatedMultiStepFormComponent<props>;\n }\n\n createDefaultValues<targetStep extends ValidStepKey<stepNumbers>>(\n targetStep: targetStep\n ) {\n return createDefaultValues(this.value, targetStep);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"step-schema.mjs","names":["MultiStepFormStepSchema","MultiStepFormStepSchemaBase","#internal","createDefaultValues"],"sources":["../src/step-schema.ts"],"sourcesContent":["import {\n type AnyStepField,\n type CasingType,\n type Constrain,\n createCtx,\n type CreateHelperFunctionOptionsBase,\n createStep,\n type DefaultCasing,\n type DefaultStorageKey,\n type Expand,\n type GetCurrentStep,\n type GetFieldsForStep,\n type HelperFnChosenSteps,\n type HelperFnCtx,\n type HelperFnInputBase,\n invariant,\n MultiStepFormLogger,\n type MultiStepFormSchemaStepConfig as MultiStepFormSchemaStepBaseConfig,\n MultiStepFormStepSchema as MultiStepFormStepSchemaBase,\n type Relaxed,\n type ResetFn,\n type ResolvedStep as ResolvedCoreStep,\n type Step,\n type StepNumbers,\n type StrippedResolvedStep,\n type UpdateFn,\n type Updater,\n type ValidStepKey,\n} from '@jfdevelops/multi-step-form-core';\nimport { MultiStepFormStepSchemaInternal } from '@jfdevelops/multi-step-form-core/_internals';\nimport { type ComponentPropsWithRef, type ReactNode } from 'react';\nimport { field } from './field';\nimport { MultiStepFormSchemaConfig } from './form-config';\nimport { createUseSelector, type UseSelector } from './hooks/use-selector';\nimport { selector } from './selector';\nimport { getValidatedCustomInputHooks, resolvedCtxCreator } from './utils';\n\nexport interface MultiStepFormSchemaStepConfig<\n TStep extends Step<TCasing>,\n TCasing extends CasingType,\n TStorageKey extends string,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object,\n TResolvedStep extends ResolvedStep<TStep, TCasing> = ResolvedStep<\n TStep,\n TCasing\n >\n> extends MultiStepFormSchemaStepBaseConfig<TStep, TCasing, TStorageKey>,\n MultiStepFormSchemaConfig.Form<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n > {}\n\nexport type CreateFunction<TArgs extends any[], TReturn = void> = (\n ...args: TArgs\n) => TReturn;\nexport type CreateComponent<TInput, TProps> = CreateFunction<\n [input: TInput, props: TProps],\n ReactNode\n>;\n\nexport type CreateComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps\n> = CreateComponent<\n HelperFnInputBase<TResolvedStep, TSteps, TChosenSteps>,\n TProps\n>;\nexport type CreatedMultiStepFormComponent<TProps> = TProps extends undefined\n ? () => ReactNode\n : (props: TProps) => ReactNode;\nexport type CreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n // This is needed to make TS happy with all types\n TStepNumbers extends StepNumbers<TResolvedStep>\n> = <\n chosenSteps extends HelperFnChosenSteps<TResolvedStep, TStepNumbers>,\n props = undefined\n>(\n options: CreateHelperFunctionOptionsBase<\n TResolvedStep,\n TStepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<TResolvedStep, TStepNumbers, chosenSteps, props>\n) => CreatedMultiStepFormComponent<props>;\n\nexport namespace StepSpecificComponent {\n // The logic for getting the formCtx only works for step specific `createComponent`\n // (i.e: step1.createComponent(...)) as of now. Reason is because I can't think of a good API for integrating the form\n // ctx into the main `createComponent` since multiple steps can be chosen. In that case\n // how would the logic work for when the form component should be defined in the callback?\n // Ideas:\n // - Make the main `createComponent` return a function that accepts the current step\n export type formComponent<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n > = TFormEnabledFor extends MultiStepFormSchemaConfig.defaultEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : TFormEnabledFor extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TFormEnabledFor[number] extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends TFormEnabledFor[number]\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {}\n : keyof TFormEnabledFor extends keyof TResolvedStep\n ? TChosenSteps extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<TSteps>\n >\n ? TChosenSteps[number] extends keyof TResolvedStep\n ? TChosenSteps[number] extends keyof TFormEnabledFor\n ? MultiStepFormSchemaConfig.formCtx<TFormAlias, TFormProps>\n : {}\n : {}\n : {}\n : {};\n export type onInputChange<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>,\n TTargetStep extends TStepNumbers\n > = <\n CurrentStepData extends GetCurrentStep<TResolvedStep, TTargetStep>,\n Field extends keyof CurrentStepData\n >(\n field: Field,\n updater: Updater<CurrentStepData[Field], Relaxed<CurrentStepData[Field]>>\n ) => void;\n export type updateWrappers<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = TStepNumber extends TSteps\n ? {\n /**\n * A useful wrapper around `update` to update the specific field.\n */\n onInputChange: UpdateFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n /**\n * A useful wrapper for `update` to reset a specific field's value to its\n * original config value.\n * @resetFn\n */\n reset: ResetFn.stepSpecific<\n TResolvedStep,\n TSteps,\n ValidStepKey<TStepNumber>\n >;\n }\n : {};\n export type input<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TAdditionalCtx extends Record<string, unknown>,\n TStepNumber extends HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n > = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TChosenSteps\n >\n > = HelperFnInputBase<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n never,\n TAdditionalCtx\n > &\n updateWrappers<TResolvedStep, TSteps, TChosenSteps, TStepNumber> & {\n Field: field.component<TResolvedStep, TSteps, TChosenSteps>;\n /**\n * A hook for reactively selecting a value from the form context.\n * The selector function receives the contextual data for the currently rendered step, and returns any derived value.\n * `useSelector` will automatically provide the latest context data on updates, and will subscribe the caller for automatic re-renders when the underlying data changes.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @returns The derived value, which will re-render the component on change\n *\n * @example\n * const someValue = useSelector(ctx => ctx.fields.username.value);\n */\n useSelector: UseSelector<TResolvedStep, TSteps, TChosenSteps>;\n /**\n * A component for reactively displaying a value from the form context.\n * Unlike `useSelector`, this component only re-renders itself, not the parent component.\n * Use this when you want to display a reactive value without causing parent re-renders.\n *\n * @param selector - A function that receives the current step's context and returns the selected value\n * @param children - Optional render prop that receives the selected value\n *\n * @example\n * <Selector selector={(ctx) => ctx.step1.fields.firstName.defaultValue}>\n * {(value) => <p>First name: {value}</p>}\n * </Selector>\n */\n Selector: selector.component<TResolvedStep, TSteps, TChosenSteps>;\n };\n\n export type callback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object,\n TAdditionalCtx extends Record<string, unknown>\n > = CreateComponent<\n Expand<\n input<TResolvedStep, TSteps, TChosenSteps, TAdditionalCtx> &\n formComponent<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n > &\n TAdditionalInput\n >,\n TProps\n >;\n export const DEFAULT_FORM_INSTANCE_ALIAS = 'form';\n export type defaultFormInstanceAlias = typeof DEFAULT_FORM_INSTANCE_ALIAS;\n export type formInstanceOptions<\n TAlias extends string,\n TRenderInput,\n TReturn\n > = {\n /**\n * The name of the return value of the `render` method.\n */\n alias?: TAlias;\n /**\n * A function that renders/creates the form instance. This function will be called\n * at the top level of the component, ensuring hooks are called in a valid React context.\n *\n * @param input - The input object containing context and default values\n * @returns The form instance (typically from a hook like `useForm`)\n *\n * @example\n * ```tsx\n * useFormInstance: {\n * render({ defaultValues }) {\n * return useForm({\n * defaultValues,\n * });\n * },\n * }\n * ```\n *\n * **Verification**: The hook call is automatically verified:\n * - Errors are caught and reported with helpful messages\n * - In development, hook calls are logged to console.debug\n * - The hook must be called at the component top level (enforced by the framework)\n */\n render: CreateFunction<[input: TRenderInput], TReturn>;\n };\n\n export interface CtxSelector<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TCtx\n > {\n /**\n * A function to select the data that will be available in the `fn`'s ctx.\n * @param input The available input to create the context with.\n * @returns The created ctx.\n */\n ctxData?: (\n input: HelperFnInputBase<\n TResolvedStep,\n TSteps,\n 'all',\n HelperFnChosenSteps.resolve<TResolvedStep, TSteps, TTargetStep>\n >\n ) => TCtx;\n }\n\n export type options<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormInstanceAlias extends string,\n TFormInstance,\n TCtx\n > = CtxSelector<TResolvedStep, TSteps, TTargetStep, TCtx> & {\n /**\n * If set to `true`, you'll be able to open the {@linkcode console} to view logs.\n */\n debug?: boolean;\n useFormInstance?: formInstanceOptions<\n TFormInstanceAlias,\n Pick<HelperFnInputBase<TResolvedStep, TSteps, TTargetStep>, 'ctx'> & {\n /**\n * An object containing all the default values for the current step.\n */\n defaultValues: Expand<\n ExtractedDefaultValues<TResolvedStep, TSteps, TTargetStep>\n >;\n },\n TFormInstance\n >;\n };\n}\n\nexport type CreateStepSpecificComponentCallback<\n TResolvedStep extends StrippedResolvedStep<AnyResolvedStep>,\n TSteps extends StepNumbers<TResolvedStep>,\n TChosenSteps extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TProps,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TAdditionalInput extends object = {},\n TAdditionalCtx extends Record<string, unknown> = {}\n> = StepSpecificComponent.callback<\n TResolvedStep,\n TSteps,\n TChosenSteps,\n TProps,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n TAdditionalInput,\n TAdditionalCtx\n>;\n\nexport type ExtractedDefaultValues<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TExtractedStepNumber extends number = HelperFnChosenSteps.extractStepNumber<\n TResolvedStep,\n TSteps,\n TTargetStep\n >,\n TFields extends GetFieldsForStep<\n TResolvedStep,\n ValidStepKey<TExtractedStepNumber>\n > = GetFieldsForStep<TResolvedStep, ValidStepKey<TExtractedStepNumber>>\n> = { [field in keyof TFields]: TFields[field]['defaultValue'] };\nexport interface StepSpecificCreateComponentFn<\n TResolvedStep extends AnyResolvedStep,\n TSteps extends StepNumbers<TResolvedStep>,\n TTargetStep extends HelperFnChosenSteps<TResolvedStep, TSteps>,\n TFormAlias extends string,\n TFormProps extends object,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>\n> {\n /**\n * A utility function to easily create a component for the current step.\n * @param fn The callback function where the component is defined.\n */\n <props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n /**\n * A utility function to easily create a component for the current step.\n * @param options Specific config options for creating a component for the current step.\n * @param fn The callback function where the component is defined.\n * @returns The created component.\n */\n <\n formInstance,\n additionalCtx extends Record<string, unknown> = {},\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined\n >(\n options: StepSpecificComponent.options<\n TResolvedStep,\n TSteps,\n TTargetStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n TResolvedStep,\n TSteps,\n TTargetStep,\n props,\n TFormAlias,\n TFormProps,\n TFormEnabledFor,\n { [_ in formInstanceAlias]: formInstance },\n additionalCtx\n >\n ): CreatedMultiStepFormComponent<props>;\n}\n\nexport type ResolvedStep<\n TStep extends Step<TDefaultCasing>,\n TDefaultCasing extends CasingType = DefaultCasing,\n TResolvedStep extends ResolvedCoreStep<\n TStep,\n TDefaultCasing\n > = ResolvedCoreStep<TStep, TDefaultCasing>,\n TFormAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n TFormProps extends object = ComponentPropsWithRef<'form'>\n> = {\n [stepKey in keyof TResolvedStep]: TResolvedStep[stepKey] &\n (stepKey extends ValidStepKey<StepNumbers<TResolvedStep>>\n ? {\n createComponent: StepSpecificCreateComponentFn<\n TResolvedStep,\n StepNumbers<TResolvedStep>,\n [stepKey],\n TFormAlias,\n TFormProps,\n TFormEnabledFor\n >;\n }\n : {});\n};\n\nexport type AnyResolvedStep = ResolvedStep<any, any, any>;\nexport interface HelperFunctions<\n TResolvedStep extends AnyResolvedStep,\n TStepNumbers extends StepNumbers<TResolvedStep>\n> {\n createComponent: CreateComponentFn<TResolvedStep, TStepNumbers>;\n}\nnamespace CreateComponentImplConfig {\n export type stepSpecificConfig<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > = {\n isStepSpecific: true;\n defaultId: string;\n form?: MultiStepFormSchemaConfig.FormConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n };\n\n export type nonStepSpecific = {\n isStepSpecific: false;\n };\n\n export type config<\n TResolvedStep extends AnyResolvedStep,\n TFormAlias extends string,\n TFormEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<TResolvedStep>,\n TFormProps extends object\n > =\n | nonStepSpecific\n | stepSpecificConfig<\n TResolvedStep,\n TFormAlias,\n TFormEnabledFor,\n TFormProps\n >;\n}\n\n/**\n * Creates a default values object for the target step.\n * @param steps The steps schema.\n * @param targetStep The step to create the default values for.\n * @returns An object containing the field names and their default values.\n */\nexport function createDefaultValues<\n resolvedStep extends AnyResolvedStep,\n stepNumbers extends StepNumbers<resolvedStep>,\n targetStep extends ValidStepKey<stepNumbers>\n>(steps: resolvedStep, targetStep: targetStep) {\n invariant(\n targetStep in steps,\n `The target step ${targetStep} is not a valid step key`\n );\n\n const current = steps[targetStep as unknown as keyof resolvedStep];\n\n invariant('fields' in current, `No \"fields\" were found for ${targetStep}`);\n\n let defaultValues = {};\n\n for (const [fieldName, fieldValues] of Object.entries(\n current.fields as Record<string, Record<string, unknown>>\n )) {\n defaultValues = {\n ...defaultValues,\n [fieldName]: fieldValues.defaultValue,\n };\n }\n\n return defaultValues as Expand<\n ExtractedDefaultValues<resolvedStep, stepNumbers, [targetStep]>\n >;\n}\nexport class MultiStepFormStepSchema<\n step extends Step<casing>,\n casing extends CasingType = DefaultCasing,\n storageKey extends string = DefaultStorageKey,\n formAlias extends string = MultiStepFormSchemaConfig.defaultFormAlias,\n formEnabledFor extends MultiStepFormSchemaConfig.formEnabledFor<resolvedStep> = MultiStepFormSchemaConfig.defaultEnabledFor,\n formProps extends object = ComponentPropsWithRef<'form'>,\n core extends ResolvedCoreStep<step, casing> = ResolvedCoreStep<\n step,\n casing\n >,\n resolvedStep extends ResolvedStep<\n step,\n casing,\n core,\n formAlias,\n formEnabledFor,\n formProps\n > = ResolvedStep<step, casing, core, formAlias, formEnabledFor, formProps>,\n stepNumbers extends StepNumbers<resolvedStep> = StepNumbers<resolvedStep>\n >\n extends MultiStepFormStepSchemaBase<step, casing>\n implements HelperFunctions<resolvedStep, stepNumbers>\n{\n // @ts-ignore type doesn't match `MultiStepFormSchemaBase.value`\n value: resolvedStep;\n readonly #internal: MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >;\n\n constructor(\n config: MultiStepFormSchemaStepConfig<\n step,\n Constrain<casing, CasingType>,\n storageKey,\n formAlias,\n formEnabledFor,\n formProps\n >\n ) {\n const { form, ...rest } = config;\n\n super(rest as never);\n\n this.value = createStep(this.original);\n\n this.#internal = new MultiStepFormStepSchemaInternal<\n step,\n casing,\n resolvedStep,\n stepNumbers\n >({\n originalValue: this.original,\n getValue: () => this.value,\n setValue: (next) => this.handlePostUpdate(next as never),\n });\n\n // this.value = this.#internal.enrichValues(resolvedValues);\n this.sync();\n this.value = this.#internal.enrichValues(this.value, (step) => {\n const key = `step${step as stepNumbers}`;\n const stepData = [key] as HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >;\n const id = form?.id ?? key;\n\n return {\n createComponent: this.createStepSpecificComponentFactory(stepData, {\n isStepSpecific: true,\n defaultId: id,\n form: form as never,\n }),\n };\n });\n }\n\n private createFormComponent(\n form: Omit<\n MultiStepFormSchemaConfig.FormConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n 'alias'\n >,\n defaultId: string\n ) {\n const { render, enabledForSteps = 'all', id = defaultId } = form;\n\n const ctx = {\n id,\n steps: createCtx(this.value, enabledForSteps as never),\n };\n\n return (props: formProps) => render(ctx, props);\n }\n\n private createResolvedCtx<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx\n >(\n options: {\n stepData: chosenStep;\n logger: MultiStepFormLogger;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n const { logger, stepData, ctxData } = options;\n // Create ctx fresh each time to ensure it has the latest this.value\n const ctx = createCtx<resolvedStep, stepNumbers, chosenStep>(\n this.value,\n stepData\n );\n let resolvedCtx = ctx as Expand<\n HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n >;\n\n if (ctxData) {\n const [targetStep] = stepData;\n const { [targetStep]: _, ...values } = this.value;\n const createResolvedCtx = resolvedCtxCreator(logger, values);\n\n resolvedCtx = createResolvedCtx({ ctx: resolvedCtx, ctxData });\n }\n\n return resolvedCtx;\n }\n\n private createStepSpecificComponentImpl<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >,\n additionalCtx = {}\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >,\n extraConfig?: {\n logger?: MultiStepFormLogger;\n input?: (\n ctx: Expand<HelperFnCtx<resolvedStep, stepNumbers, chosenStep>>\n ) => Record<string, unknown>;\n } & StepSpecificComponent.CtxSelector<\n resolvedStep,\n stepNumbers,\n chosenStep,\n additionalCtx\n >\n ) {\n return <props>(fn: Function) =>\n ((props: props) => {\n const ctxData = extraConfig?.ctxData;\n const logger = extraConfig?.logger ?? new MultiStepFormLogger();\n const resolvedCtx = this.createResolvedCtx({\n stepData,\n ctxData,\n logger,\n });\n const extraInput = extraConfig?.input?.(resolvedCtx) ?? {};\n // Call hook functions from extraInput at the top level of the component\n // This ensures hooks are called in a valid React context (before any conditionals)\n const hookResults = getValidatedCustomInputHooks(extraInput);\n\n const { defaultId, form } = config;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n invariant(\n this.steps.isValidStepKey(step),\n `[createComponent]: the target step ${step} is invalid. Note, this error shouldn't appear as the target step should always be valid. If you see this error, please open an issue.`\n );\n\n const stepNumber = Number.parseInt(step.replace('step', ''));\n\n invariant(\n !Number.isNaN(stepNumber),\n `[${step}:\"createComponent\"]: an error occurred while extracting the number`\n );\n const current = this.value[step as keyof resolvedStep];\n\n // These checks are mostly for type safety. `current` should _always_ be in the proper format.\n // On the off chance that it's not, we have the checks here to help, but these checks are basically\n // just for type safety.\n invariant(\n 'fields' in current,\n `[${step}:createComponent]: unable to find the \"fields\" for the current step`\n );\n invariant(\n typeof current.fields === 'object',\n `[${step}:createComponent]: the \"fields\" property must be an object, was ${typeof current.fields}`\n );\n\n // Memoize Field component to prevent remounting on every render\n // This ensures input focus is maintained when ctx changes\n const Field = field.create<resolvedStep, stepNumbers, chosenStep>({\n propsCreator: (name) => {\n // Access current step data directly to avoid stale closure\n const currentStep = this.value[\n step as keyof resolvedStep\n ] as typeof current;\n const currentFields = Object.keys(\n currentStep.fields as Record<string, unknown>\n );\n\n invariant(\n typeof name === 'string',\n (formatter) =>\n `[${step}:Field]: the \"name\" prop must be a string and a valid field for ${step}. Available fields include: \"${formatter.format(\n currentFields\n )}\"`\n );\n // TODO add support for deep keys (`name`)\n\n invariant(\n name in (currentStep.fields as object),\n (formatter) =>\n `[${step}:Field]: the field \"${name}\" doesn't exist for the current step. Available fields include: \"${formatter.format(\n currentFields\n )}\".`\n );\n\n invariant(\n 'update' in currentStep,\n `[${step}:Field]: No \"update\" function was found`\n );\n\n const defaultValue = this.getValue(step as never, name as never);\n\n const { label, nameTransformCasing, type } = (\n currentStep.fields as AnyStepField\n )[name];\n const targetFields = `fields.${name}.defaultValue`;\n\n return {\n defaultValue,\n label,\n nameTransformCasing,\n type,\n name,\n onInputChange: (value: unknown) => {\n // Handle Updater pattern: if value is a function, call it with the current field value\n let resolvedValue;\n\n if (typeof value === 'function') {\n const defaultValue = this.getValue(\n step as never,\n name as never\n );\n\n resolvedValue = value(defaultValue);\n } else {\n resolvedValue = value;\n }\n\n this.update({\n targetStep: step,\n updater: resolvedValue as never,\n fields: [targetFields] as never,\n });\n },\n reset: () =>\n this.reset({\n fields: [targetFields] as never,\n targetStep: step,\n }),\n } as never;\n },\n subscribe: this.subscribe,\n getValue: (name) => this.getValue(step as never, name as never),\n selectorCtx: this.createResolvedCtx({ stepData, ctxData, logger }),\n });\n\n // Create useSelector hook for reactive value access via selector\n // This allows getting values from ctx reactively without causing re-renders\n // Pass a function that creates fresh ctx on each call to avoid stale closures\n const useSelector = createUseSelector(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n // Create Selector component that uses useSelector internally\n // This allows parts of the UI to subscribe to specific values without\n // causing the parent component to re-render\n const Selector = selector.create(\n () => this.createResolvedCtx({ stepData, ctxData, logger }),\n this.subscribe\n );\n\n let fnInput = {\n ctx: resolvedCtx,\n onInputChange: this.#internal.createStepUpdaterFn(step),\n reset: this.#internal.createStepResetterFn(step),\n Field,\n useSelector,\n Selector,\n ...hookResults,\n };\n\n if (form) {\n const {\n alias = MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS,\n ...rest\n } = form;\n const enabledFor = rest.enabledForSteps ?? 'all';\n\n if (\n MultiStepFormSchemaConfig.isFormAvailable(\n stepData as never,\n enabledFor as never\n )\n ) {\n fnInput = {\n ...fnInput,\n [alias]: this.createFormComponent(rest, defaultId),\n };\n }\n\n return fn(fnInput, props);\n }\n\n return fn(\n {\n ...fnInput,\n [MultiStepFormSchemaConfig.DEFAULT_FORM_ALIAS]:\n MultiStepFormSchemaConfig.createDefaultForm(defaultId),\n },\n props\n );\n }) as CreatedMultiStepFormComponent<props>;\n }\n\n private createStepSpecificComponentFactory<\n chosenStep extends HelperFnChosenSteps.tupleNotation<\n ValidStepKey<stepNumbers>\n >\n >(\n stepData: chosenStep,\n config: CreateComponentImplConfig.stepSpecificConfig<\n resolvedStep,\n formAlias,\n formEnabledFor,\n formProps\n >\n // ctx: HelperFnCtx<resolvedStep, stepNumbers, chosenStep>\n ): StepSpecificCreateComponentFn<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formAlias,\n formProps,\n formEnabledFor\n > {\n const createStepSpecificComponentImpl =\n this.createStepSpecificComponentImpl.bind(this);\n const createDefaultValues = this.createDefaultValues.bind(this);\n const [targetStep] = stepData;\n\n function impl<props = undefined>(\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n options: StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >,\n fn: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ): CreatedMultiStepFormComponent<props>;\n function impl<\n formInstance,\n formInstanceAlias extends string = StepSpecificComponent.defaultFormInstanceAlias,\n props = undefined,\n additionalCtx = {}\n >(\n optionsOrFn:\n | StepSpecificComponent.options<\n resolvedStep,\n stepNumbers,\n chosenStep,\n formInstanceAlias,\n formInstance,\n additionalCtx\n >\n | CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor\n >,\n fn?: CreateStepSpecificComponentCallback<\n resolvedStep,\n stepNumbers,\n chosenStep,\n props,\n formAlias,\n formProps,\n formEnabledFor,\n { [_ in formInstanceAlias]: formInstance }\n >\n ) {\n function createStepSpecificComponent() {\n invariant(\n typeof optionsOrFn === 'function',\n 'The first argument must be a function'\n );\n\n return createStepSpecificComponentImpl(stepData, config)(optionsOrFn);\n }\n\n if (typeof optionsOrFn === 'object') {\n const { useFormInstance, ctxData, debug } = optionsOrFn;\n const logger = new MultiStepFormLogger({\n debug,\n prefix(prefix) {\n return `${prefix}-${targetStep}-createComponent`;\n },\n });\n\n logger.info('First argument is an object');\n\n invariant(\n typeof fn === 'function',\n 'The second argument must be a function'\n );\n\n if (useFormInstance) {\n const {\n render,\n alias = StepSpecificComponent.DEFAULT_FORM_INSTANCE_ALIAS,\n } = useFormInstance;\n\n // Safe cast here since the step specific `createComponent` will always have\n // `stepData` as a tuple\n const [step] =\n stepData as HelperFnChosenSteps.tupleNotation<`step${stepNumbers}`>;\n\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n input: (ctx) => {\n const defaultValues = createDefaultValues(step) as never;\n\n return {\n [alias]: () =>\n render({\n ctx,\n defaultValues,\n }),\n };\n },\n })(fn);\n }\n\n if (ctxData) {\n return createStepSpecificComponentImpl(stepData, config, {\n logger,\n ctxData,\n })(fn);\n }\n\n // Empty options object. Can throw here 🤷♂️\n // Maybe add \"global\" - top level config - option to tune fine grained errors.\n return createStepSpecificComponent();\n }\n\n return createStepSpecificComponent();\n }\n\n return impl;\n }\n\n /**\n * A helper function to create a component for a specific step.\n * @param options The options for creating the step specific component.\n * @param fn A callback that is used for accessing the target step's data and defining\n * any props that the component should have. This function must return a valid `JSX` element.\n * @returns The created component for the step.\n */\n createComponent<\n chosenSteps extends HelperFnChosenSteps<resolvedStep, stepNumbers>,\n props = undefined\n >(\n options: CreateHelperFunctionOptionsBase<\n resolvedStep,\n stepNumbers,\n chosenSteps\n >,\n fn: CreateComponentCallback<resolvedStep, stepNumbers, chosenSteps, props>\n ) {\n const { stepData } = options;\n const ctx = createCtx<resolvedStep, stepNumbers, chosenSteps>(\n this.value,\n stepData\n ) as never;\n\n return ((props?: props) =>\n fn(ctx, props as any)) as CreatedMultiStepFormComponent<props>;\n }\n\n createDefaultValues<targetStep extends ValidStepKey<stepNumbers>>(\n targetStep: targetStep\n ) {\n return createDefaultValues(this.value, targetStep);\n }\n}\n"],"mappings":";;;;;;;;;;;sDA2P6C;;;;;;;;AA6P7C,SAAgB,oBAId,OAAqB,YAAwB;AAC7C,WACE,cAAc,OACd,mBAAmB,WAAW,0BAC/B;CAED,MAAM,UAAU,MAAM;AAEtB,WAAU,YAAY,SAAS,8BAA8B,aAAa;CAE1E,IAAI,gBAAgB,EAAE;AAEtB,MAAK,MAAM,CAAC,WAAW,gBAAgB,OAAO,QAC5C,QAAQ,OACT,CACC,iBAAgB;EACd,GAAG;GACF,YAAY,YAAY;EAC1B;AAGH,QAAO;;AAIT,IAAaA,4BAAb,cAqBUC,wBAEV;CAEE;CACA,CAASC;CAOT,YACE,QAQA;EACA,MAAM,EAAE,MAAM,GAAG,SAAS;AAE1B,QAAM,KAAc;AAEpB,OAAK,QAAQ,WAAW,KAAK,SAAS;AAEtC,QAAKA,WAAY,IAAI,gCAKnB;GACA,eAAe,KAAK;GACpB,gBAAgB,KAAK;GACrB,WAAW,SAAS,KAAK,iBAAiB,KAAc;GACzD,CAAC;AAGF,OAAK,MAAM;AACX,OAAK,QAAQ,MAAKA,SAAU,aAAa,KAAK,QAAQ,SAAS;GAC7D,MAAM,MAAM,OAAO;GACnB,MAAM,WAAW,CAAC,IAAI;GAGtB,MAAM,KAAK,MAAM,MAAM;AAEvB,UAAO,EACL,iBAAiB,KAAK,mCAAmC,UAAU;IACjE,gBAAgB;IAChB,WAAW;IACL;IACP,CAAC,EACH;IACD;;CAGJ,AAAQ,oBACN,MASA,WACA;EACA,MAAM,EAAE,QAAQ,kBAAkB,OAAO,KAAK,cAAc;EAE5D,MAAM,MAAM;GACV;GACA,OAAO,UAAU,KAAK,OAAO,gBAAyB;GACvD;AAED,UAAQ,UAAqB,OAAO,KAAK,MAAM;;CAGjD,AAAQ,kBAMN,SASA;EACA,MAAM,EAAE,QAAQ,UAAU,YAAY;EAMtC,IAAI,cAJQ,UACV,KAAK,OACL,SACD;AAKD,MAAI,SAAS;GACX,MAAM,CAAC,cAAc;GACrB,MAAM,GAAG,aAAa,GAAG,GAAG,WAAW,KAAK;AAG5C,iBAF0B,mBAAmB,QAAQ,OAAO,CAE5B;IAAE,KAAK;IAAa;IAAS,CAAC;;AAGhE,SAAO;;CAGT,AAAQ,gCAMN,UACA,QAMA,aAWA;AACA,UAAe,SACX,UAAiB;GACjB,MAAM,UAAU,aAAa;GAC7B,MAAM,SAAS,aAAa,UAAU,IAAI,qBAAqB;GAC/D,MAAM,cAAc,KAAK,kBAAkB;IACzC;IACA;IACA;IACD,CAAC;GAIF,MAAM,cAAc,6BAHD,aAAa,QAAQ,YAAY,IAAI,EAAE,CAGE;GAE5D,MAAM,EAAE,WAAW,SAAS;GAI5B,MAAM,CAAC,QACL;AAEF,aACE,KAAK,MAAM,eAAe,KAAK,EAC/B,sCAAsC,KAAK,wIAC5C;GAED,MAAM,aAAa,OAAO,SAAS,KAAK,QAAQ,QAAQ,GAAG,CAAC;AAE5D,aACE,CAAC,OAAO,MAAM,WAAW,EACzB,IAAI,KAAK,oEACV;GACD,MAAM,UAAU,KAAK,MAAM;AAK3B,aACE,YAAY,SACZ,IAAI,KAAK,qEACV;AACD,aACE,OAAO,QAAQ,WAAW,UAC1B,IAAI,KAAK,kEAAkE,OAAO,QAAQ,SAC3F;GAID,MAAM,QAAQ,MAAM,OAA8C;IAChE,eAAe,SAAS;KAEtB,MAAM,cAAc,KAAK,MACvB;KAEF,MAAM,gBAAgB,OAAO,KAC3B,YAAY,OACb;AAED,eACE,OAAO,SAAS,WACf,cACC,IAAI,KAAK,kEAAkE,KAAK,+BAA+B,UAAU,OACvH,cACD,CAAC,GACL;AAGD,eACE,QAAS,YAAY,SACpB,cACC,IAAI,KAAK,sBAAsB,KAAK,mEAAmE,UAAU,OAC/G,cACD,CAAC,IACL;AAED,eACE,YAAY,aACZ,IAAI,KAAK,yCACV;KAED,MAAM,eAAe,KAAK,SAAS,MAAe,KAAc;KAEhE,MAAM,EAAE,OAAO,qBAAqB,SAClC,YAAY,OACZ;KACF,MAAM,eAAe,UAAU,KAAK;AAEpC,YAAO;MACL;MACA;MACA;MACA;MACA;MACA,gBAAgB,UAAmB;OAEjC,IAAI;AAEJ,WAAI,OAAO,UAAU,WAMnB,iBAAgB,MALK,KAAK,SACxB,MACA,KACD,CAEkC;WAEnC,iBAAgB;AAGlB,YAAK,OAAO;QACV,YAAY;QACZ,SAAS;QACT,QAAQ,CAAC,aAAa;QACvB,CAAC;;MAEJ,aACE,KAAK,MAAM;OACT,QAAQ,CAAC,aAAa;OACtB,YAAY;OACb,CAAC;MACL;;IAEH,WAAW,KAAK;IAChB,WAAW,SAAS,KAAK,SAAS,MAAe,KAAc;IAC/D,aAAa,KAAK,kBAAkB;KAAE;KAAU;KAAS;KAAQ,CAAC;IACnE,CAAC;GAKF,MAAM,cAAc,wBACZ,KAAK,kBAAkB;IAAE;IAAU;IAAS;IAAQ,CAAC,EAC3D,KAAK,UACN;GAKD,MAAM,WAAW,SAAS,aAClB,KAAK,kBAAkB;IAAE;IAAU;IAAS;IAAQ,CAAC,EAC3D,KAAK,UACN;GAED,IAAI,UAAU;IACZ,KAAK;IACL,eAAe,MAAKA,SAAU,oBAAoB,KAAK;IACvD,OAAO,MAAKA,SAAU,qBAAqB,KAAK;IAChD;IACA;IACA;IACA,GAAG;IACJ;AAED,OAAI,MAAM;IACR,MAAM,EACJ,QAAQ,0BAA0B,oBAClC,GAAG,SACD;IACJ,MAAM,aAAa,KAAK,mBAAmB;AAE3C,QACE,0BAA0B,gBACxB,UACA,WACD,CAED,WAAU;KACR,GAAG;MACF,QAAQ,KAAK,oBAAoB,MAAM,UAAU;KACnD;AAGH,WAAO,GAAG,SAAS,MAAM;;AAG3B,UAAO,GACL;IACE,GAAG;KACF,0BAA0B,qBACzB,0BAA0B,kBAAkB,UAAU;IACzD,EACD,MACD;;;CAIP,AAAQ,mCAKN,UACA,QAcA;EACA,MAAM,kCACJ,KAAK,gCAAgC,KAAK,KAAK;EACjD,MAAMC,wBAAsB,KAAK,oBAAoB,KAAK,KAAK;EAC/D,MAAM,CAAC,cAAc;EAsCrB,SAAS,KAMP,aAkBA,IAUA;GACA,SAAS,8BAA8B;AACrC,cACE,OAAO,gBAAgB,YACvB,wCACD;AAED,WAAO,gCAAgC,UAAU,OAAO,CAAC,YAAY;;AAGvE,OAAI,OAAO,gBAAgB,UAAU;IACnC,MAAM,EAAE,iBAAiB,SAAS,UAAU;IAC5C,MAAM,SAAS,IAAI,oBAAoB;KACrC;KACA,OAAO,QAAQ;AACb,aAAO,GAAG,OAAO,GAAG,WAAW;;KAElC,CAAC;AAEF,WAAO,KAAK,8BAA8B;AAE1C,cACE,OAAO,OAAO,YACd,yCACD;AAED,QAAI,iBAAiB;KACnB,MAAM,EACJ,QACA,QAAQ,sBAAsB,gCAC5B;KAIJ,MAAM,CAAC,QACL;AAEF,YAAO,gCAAgC,UAAU,QAAQ;MACvD;MACA;MACA,QAAQ,QAAQ;OACd,MAAM,gBAAgBA,sBAAoB,KAAK;AAE/C,cAAO,GACJ,cACC,OAAO;QACL;QACA;QACD,CAAC,EACL;;MAEJ,CAAC,CAAC,GAAG;;AAGR,QAAI,QACF,QAAO,gCAAgC,UAAU,QAAQ;KACvD;KACA;KACD,CAAC,CAAC,GAAG;AAKR,WAAO,6BAA6B;;AAGtC,UAAO,6BAA6B;;AAGtC,SAAO;;;;;;;;;CAUT,gBAIE,SAKA,IACA;EACA,MAAM,EAAE,aAAa;EACrB,MAAM,MAAM,UACV,KAAK,OACL,SACD;AAED,WAAS,UACP,GAAG,KAAK,MAAa;;CAGzB,oBACE,YACA;AACA,SAAO,oBAAoB,KAAK,OAAO,WAAW"}
|