@picked/react 0.0.1-dev.1776324257073 → 0.0.1-dev.1776409551160

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.
@@ -1,39 +1,24 @@
1
- import { FormEvent } from 'react';
2
- import { Store } from 'effector';
3
- import { FormInstance as CoreFormInstance, ErrorCallback, SubmitCallback, SuccessCallback } from '@picked/client/form';
4
- import { ReactFormField } from '../utils/map-field-to-react';
1
+ import { ReactFormInstance } from './use-react-form';
5
2
  interface UseFormOptions {
6
3
  formId: string;
7
4
  title: string;
8
5
  fieldKeys: string[];
9
6
  }
10
- /**
11
- * React FormInstance — identical to core but with React-compatible form props
12
- * and callback registration that returns void (cleanup is automatic via useEffect).
13
- */
14
- interface FormInstance<TFieldKeys extends string = string> extends Omit<CoreFormInstance<TFieldKeys>, 'form' | 'fields'> {
15
- form: Omit<CoreFormInstance<TFieldKeys>['form'], 'onBeforeSubmit' | 'onSuccess' | 'onError' | 'props'> & {
16
- props: {
17
- onSubmit: (e: FormEvent<HTMLFormElement>) => void;
18
- };
19
- onBeforeSubmit: (callback: SubmitCallback<TFieldKeys>) => void;
20
- onSuccess: (callback: SuccessCallback<TFieldKeys>) => void;
21
- onError: (callback: ErrorCallback) => void;
22
- };
23
- fields: Store<ReactFormField[]>;
24
- }
7
+ export type FormInstance<TFieldKeys extends string = string> = ReactFormInstance<TFieldKeys>;
25
8
  /**
26
9
  * React hook wrapping the framework-agnostic createForm from `@picked/client/form`.
27
10
  *
28
- * Injects client and experienceInstance from React context, collects unsubscribe
29
- * functions from callback registration, and cleans them up on unmount.
11
+ * Creates the underlying Effector graph once per hook lifetime: `title` and
12
+ * `fieldKeys` prop changes flow through events into stable stores, so the core
13
+ * form is not rebuilt on every render when callers pass inline values.
14
+ * Callback registration returns void — cleanup runs automatically on unmount.
30
15
  *
31
- * @param {UseFormOptions} root0 - Form configuration options.
32
- * @param {string} root0.formId - Unique identifier for this form instance.
33
- * @param {string} root0.title - The form/step title.
34
- * @param {string[]} root0.fieldKeys - Field keys that belong to this form.
35
- * @returns {FormInstance} A form instance with reactive field stores and callback registration.
36
- * @example useForm({ formId: 'lead-capture', title: 'Contact', fieldKeys: ['email', 'name'] })
16
+ * @param {UseFormOptions} options - Form configuration.
17
+ * @param {string} options.formId - Stable identifier for the form.
18
+ * @param {string} options.title - Human-readable form title.
19
+ * @param {string[]} options.fieldKeys - Field keys the form submits.
20
+ * @returns {FormInstance} Form with React submit handler, mapped fields, and auto-cleanup callbacks.
21
+ * @example useForm({ formId: 'f1', title: 'Feedback', fieldKeys: ['rating'] })
37
22
  */
38
23
  export declare function useForm({ formId, title, fieldKeys }: UseFormOptions): FormInstance;
39
24
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/form/index.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAClE,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,UAAU,CAAA;AAClD,OAAO,EAEL,KAAK,YAAY,IAAI,gBAAgB,EACrC,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAGlF,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED;;;GAGG;AACH,UAAU,YAAY,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,IAAI,CACrE,gBAAgB,CAAC,UAAU,CAAC,EAC5B,MAAM,GAAG,QAAQ,CAClB;IACC,IAAI,EAAE,IAAI,CACR,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EACpC,gBAAgB,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CACrD,GAAG;QACF,KAAK,EAAE;YACL,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;SAClD,CAAA;QACD,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;QAC9D,SAAS,EAAE,CAAC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;QAC1D,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;KAC3C,CAAA;IACD,MAAM,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;CAChC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,cAAc,GAAG,YAAY,CAqDlF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/form/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEvE,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,MAAM,YAAY,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,IAAI,iBAAiB,CAAC,UAAU,CAAC,CAAA;AAE5F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,cAAc,GAAG,YAAY,CAgClF"}
@@ -1 +1 @@
1
- import{prepareNativeEvent as e}from"../utils/prepare-native-event.js";import{mapFieldToReact as t}from"../utils/map-field-to-react.js";import{useExperience as n,usePicked as r}from"../hooks/client.js";import"../hooks/index.js";import{useEffect as i,useMemo as a,useRef as o}from"react";import{createStore as s}from"effector";import{createForm as c}from"@picked/client/form";function l({formId:l,title:u,fieldKeys:d}){let f=r(),p=n(),m=a(()=>s(u),[u]),h=a(()=>s(d),[d]),g=a(()=>c({client:f,experienceInstance:p},l,m,h),[f,p,l,m,h]),_=o([]);return i(()=>()=>{_.current.forEach(e=>e()),_.current=[]},[]),{form:a(()=>({...g.form,props:{onSubmit:t=>{t.preventDefault(),e(t.nativeEvent,t.currentTarget)&&g.form.props.onsubmit(t.nativeEvent)}},onBeforeSubmit:e=>{_.current.push(g.form.onBeforeSubmit(e))},onSuccess:e=>{_.current.push(g.form.onSuccess(e))},onError:e=>{_.current.push(g.form.onError(e))}}),[g]),fields:a(()=>g.fields.map(e=>e.map(t),{skipVoid:!1}),[g.fields])}}export{l as useForm};
1
+ import{useExperience as e,usePicked as t}from"../hooks/client.js";import{useReactForm as n}from"./use-react-form.js";import"../hooks/index.js";import{useEffect as r,useMemo as i}from"react";import{createEvent as a,createStore as o}from"effector";import{createForm as s}from"@picked/client/form";function c({formId:c,title:l,fieldKeys:u}){let d=t(),f=e(),[p,m]=i(()=>{let e=a();return[o(l).on(e,(e,t)=>t),e]},[]),[h,g]=i(()=>{let e=a();return[o(u).on(e,(e,t)=>t),e]},[]);return r(()=>{m(l)},[m,l]),r(()=>{g(u)},[g,u.join(`\0`),u]),n(i(()=>s({client:d,experienceInstance:f},c,p,h),[d,f,c,p,h]))}export{c as useForm};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../src/form/index.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,33 @@
1
+ import { FormEvent } from 'react';
2
+ import { Store } from 'effector';
3
+ import { ErrorCallback, FormInstance as CoreFormInstance, SubmitCallback, SuccessCallback } from '@picked/client/form';
4
+ import { ReactFormField } from '../utils/map-field-to-react';
5
+ export interface ReactFormInstance<TFieldKeys extends string = string> {
6
+ form: {
7
+ props: {
8
+ onSubmit: (e: FormEvent<HTMLFormElement>) => void;
9
+ };
10
+ errors: CoreFormInstance<TFieldKeys>['form']['errors'];
11
+ submitting: CoreFormInstance<TFieldKeys>['form']['submitting'];
12
+ onBeforeSubmit: (callback: SubmitCallback<TFieldKeys>) => void;
13
+ onSuccess: (callback: SuccessCallback<TFieldKeys>) => void;
14
+ onError: (callback: ErrorCallback) => void;
15
+ };
16
+ fields: Store<ReactFormField[]>;
17
+ }
18
+ /**
19
+ * Wraps a core FormInstance for React consumption.
20
+ *
21
+ * - `form.props.onSubmit` accepts a React FormEvent and forwards the native
22
+ * event to core after restoring currentTarget.
23
+ * - `fields` exposes camelCase React handlers via mapFieldToReact.
24
+ * - onBeforeSubmit/onSuccess/onError collect unsubscribes scoped to the
25
+ * current core; cleanup runs on core change and on unmount so subscriptions
26
+ * on a previous core do not leak.
27
+ *
28
+ * @param {CoreFormInstance} core - Framework-agnostic form instance to adapt.
29
+ * @returns {ReactFormInstance} React-adapted form with camelCase fields and auto-cleanup.
30
+ * @example const { form, fields } = useReactForm(core)
31
+ */
32
+ export declare function useReactForm<TFieldKeys extends string = string>(core: CoreFormInstance<TFieldKeys>): ReactFormInstance<TFieldKeys>;
33
+ //# sourceMappingURL=use-react-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-react-form.d.ts","sourceRoot":"","sources":["../../src/form/use-react-form.ts"],"names":[],"mappings":"AAAA,yGAAyG;AACzG,OAAO,EAAE,KAAK,SAAS,EAA8B,MAAM,OAAO,CAAA;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EACV,aAAa,EACb,YAAY,IAAI,gBAAgB,EAChC,cAAc,EACd,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAGlF,MAAM,WAAW,iBAAiB,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM;IACnE,IAAI,EAAE;QACJ,KAAK,EAAE;YACL,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;SAClD,CAAA;QACD,MAAM,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAA;QACtD,UAAU,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAA;QAC9D,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;QAC9D,SAAS,EAAE,CAAC,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;QAC1D,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;KAC3C,CAAA;IACD,MAAM,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;CAChC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,UAAU,SAAS,MAAM,GAAG,MAAM,EAC7D,IAAI,EAAE,gBAAgB,CAAC,UAAU,CAAC,GACjC,iBAAiB,CAAC,UAAU,CAAC,CAsC/B"}
@@ -0,0 +1 @@
1
+ import{mapFieldToReact as e}from"../utils/map-field-to-react.js";import{prepareNativeEvent as t}from"../utils/prepare-native-event.js";import{useEffect as n,useMemo as r,useRef as i}from"react";function a(a){let o=i([]);n(()=>()=>{let e=o.current;o.current=[];for(let t of e)t()},[a]);let s=r(()=>a.fields.map(t=>t.map(e)),[a]);return{form:r(()=>({errors:a.form.errors,submitting:a.form.submitting,props:{onSubmit:e=>{t(e.nativeEvent,e.currentTarget),e.preventDefault(),a.form.props.onsubmit(e.nativeEvent)}},onBeforeSubmit:e=>{o.current.push(a.form.onBeforeSubmit(e))},onSuccess:e=>{o.current.push(a.form.onSuccess(e))},onError:e=>{o.current.push(a.form.onError(e))}}),[a]),fields:s}}export{a as useReactForm};
@@ -5,7 +5,6 @@ export { ClientContext, ClientProvider, ExperienceContext, ExperienceProvider }
5
5
  export { usePicked, useExperience } from './client';
6
6
  export { useStep, useSetStepContext } from './step';
7
7
  export type { StepContext } from './step';
8
- export type { ReactFormField, ReactFormFieldProps } from '../utils/map-field-to-react';
9
8
  export { useSessionStorage, useLocalStorage } from './storage';
10
9
  export type { UseStorageOptions } from './storage';
11
10
  export * from './field';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACjG,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACzC,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AACtF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACjG,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAA;AACzC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC9D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,cAAc,SAAS,CAAA;AACvB,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA"}
@@ -1,31 +1,15 @@
1
- import { FormEvent } from 'react';
2
1
  import { Store } from 'effector';
3
- import { ExperienceStep, ValidationError } from '@picked/client';
4
- import { ErrorCallback, SubmitCallback, SuccessCallback } from '@picked/client/form';
2
+ import { ExperienceStep } from '@picked/client';
3
+ import { ReactFormInstance } from '../form/use-react-form';
5
4
  import { ReactFormField } from '../utils/map-field-to-react';
6
5
  export interface StepContext {
7
6
  step: Store<ExperienceStep>;
8
- /** Reactive store of fields with React-compatible camelCase event handlers. */
7
+ /** Reactive store of fields with React-style event handlers and current state. */
9
8
  fields: Store<ReactFormField[]>;
10
9
  isActive: boolean;
11
10
  /** @deprecated Use `isActive` instead. */
12
11
  isActiveStep: boolean;
13
- form: {
14
- /** React-compatible attributes to spread onto a <form> element. */
15
- props: {
16
- onSubmit: (e: FormEvent<HTMLFormElement>) => void;
17
- };
18
- /** Flat list of all current validation errors. */
19
- errors: Store<ValidationError[]>;
20
- /** Whether the form is currently submitting. */
21
- submitting: Store<boolean>;
22
- /** Register a callback to transform data before submission. Cleanup is automatic. */
23
- onBeforeSubmit: (callback: SubmitCallback) => void;
24
- /** Register a callback to run on successful submission. Cleanup is automatic. */
25
- onSuccess: (callback: SuccessCallback) => void;
26
- /** Register a callback to run on validation errors. Cleanup is automatic. */
27
- onError: (callback: ErrorCallback) => void;
28
- };
12
+ form: ReactFormInstance['form'];
29
13
  }
30
14
  export declare const StepContextProvider: import('react').Context<StepContext | null>;
31
15
  /**
@@ -38,8 +22,11 @@ export declare function useStep(): StepContext;
38
22
  /**
39
23
  * Creates and provides step context for the given step key.
40
24
  *
41
- * @param {string} stepKey - The step key.
42
- * @returns {StepContext} The step context with form, fields, and active state.
25
+ * Throws if the step key is not present in the experience tree — loud failure
26
+ * surfaces misconfiguration instead of rendering an empty form.
27
+ *
28
+ * @param {string} stepKey - The step key to look up in the experience tree.
29
+ * @returns {StepContext} Step context with form, fields, and active state.
43
30
  * @example useSetStepContext('step-1')
44
31
  */
45
32
  export declare function useSetStepContext(stepKey: string): StepContext;
@@ -1 +1 @@
1
- {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/hooks/step.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAC7F,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAIlF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAC3B,+EAA+E;IAC/E,MAAM,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;IACjB,0CAA0C;IAC1C,YAAY,EAAE,OAAO,CAAA;IACrB,IAAI,EAAE;QACJ,mEAAmE;QACnE,KAAK,EAAE;YACL,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAA;SAClD,CAAA;QACD,kDAAkD;QAClD,MAAM,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAA;QAChC,gDAAgD;QAChD,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QAC1B,qFAAqF;QACrF,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAA;QAClD,iFAAiF;QACjF,SAAS,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAA;QAC9C,6EAA6E;QAC7E,OAAO,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAA;KAC3C,CAAA;CACF;AAED,eAAO,MAAM,mBAAmB,6CAA0C,CAAA;AAE1E;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,WAAW,CAOrC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CA0F9D"}
1
+ {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/hooks/step.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,OAAO,EAAgB,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAGjE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAC3B,kFAAkF;IAClF,MAAM,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;IACjB,0CAA0C;IAC1C,YAAY,EAAE,OAAO,CAAA;IACrB,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;CAChC;AAED,eAAO,MAAM,mBAAmB,6CAA0C,CAAA;AAE1E;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,WAAW,CAOrC;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAuC9D"}
@@ -1 +1 @@
1
- import{prepareNativeEvent as e}from"../utils/prepare-native-event.js";import{mapFieldToReact as t}from"../utils/map-field-to-react.js";import{useExperience as n,usePicked as r}from"./client.js";import{useStepRouter as i}from"../router/context.js";import{createContext as a,useContext as o,useEffect as s,useMemo as c,useRef as l}from"react";import{createForm as u}from"@picked/client/form";var d=a(null);function f(){let e=o(d);if(!e)throw Error(`useStep must be used within a StepContextProvider`);return e}function p(a){let o=n(),d=r(),{activeStep:f}=i(),p=c(()=>f?.key===a,[f?.key,a]),m=c(()=>o.treeStore.map(e=>e.steps.find(e=>e.key===a)??{id:a,key:a,name:``,fieldKeys:[]},{skipVoid:!1}),[o,a]),h=c(()=>m.map(e=>e.name,{skipVoid:!1}),[m]),g=c(()=>m.map(e=>e.fieldKeys,{skipVoid:!1}),[m]),_=c(()=>u({client:d,experienceInstance:o},a,h,g),[d,o,a,h,g]),v=l([]);s(()=>()=>{v.current.forEach(e=>e()),v.current=[]},[]);let y=c(()=>({..._.form,props:{onSubmit:t=>{t.preventDefault(),e(t.nativeEvent,t.currentTarget)&&_.form.props.onsubmit(t.nativeEvent)}},onBeforeSubmit:e=>{v.current.push(_.form.onBeforeSubmit(e))},onSuccess:e=>{v.current.push(_.form.onSuccess(e))},onError:e=>{v.current.push(_.form.onError(e))}}),[_]);return{step:m,fields:c(()=>_.fields.map(e=>e.map(t),{skipVoid:!1}),[_.fields]),isActive:p,isActiveStep:p,form:y}}export{d as StepContextProvider,p as useSetStepContext,f as useStep};
1
+ import{useExperience as e,usePicked as t}from"./client.js";import{useReactForm as n}from"../form/use-react-form.js";import{useStepRouter as r}from"../router/context.js";import{createContext as i,useContext as a,useMemo as o}from"react";import{createForm as s}from"@picked/client/form";var c=i(null);function l(){let e=a(c);if(!e)throw Error(`useStep must be used within a StepContextProvider`);return e}function u(i){let a=e(),c=t(),{activeStep:l}=r(),u=o(()=>l?.key===i,[l?.key,i]),d=o(()=>a.treeStore.map(e=>{let t=e.steps.find(e=>e.key===i);if(!t)throw Error(`Step with key "${i}" not found in the experience tree.`);return t}),[a,i]),f=o(()=>d.map(e=>e.name),[d]),p=o(()=>d.map(e=>e.fieldKeys),[d]),{form:m,fields:h}=n(o(()=>s({client:c,experienceInstance:a},i,f,p),[c,a,i,f,p]));return{step:d,fields:h,isActive:u,isActiveStep:u,form:m}}export{c as StepContextProvider,u as useSetStepContext,l as useStep};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=step.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step.test.d.ts","sourceRoot":"","sources":["../../src/hooks/step.test.tsx"],"names":[],"mappings":""}
@@ -1,5 +1,6 @@
1
1
  import { FormField } from '@picked/client/form';
2
2
  import { ChangeEvent, FocusEvent, FormEvent } from 'react';
3
+ type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
3
4
  export interface ReactFormFieldProps {
4
5
  id: string;
5
6
  name: string;
@@ -8,9 +9,9 @@ export interface ReactFormFieldProps {
8
9
  type: FormField['props']['type'];
9
10
  required: boolean;
10
11
  placeholder: string | undefined;
11
- onInput: (e: FormEvent<HTMLElement>) => void;
12
- onChange: (e: ChangeEvent<HTMLElement>) => void;
13
- onBlur: (e: FocusEvent<HTMLElement>) => void;
12
+ onInput: (e: FormEvent<FieldElement>) => void;
13
+ onChange: (e: ChangeEvent<FieldElement>) => void;
14
+ onBlur: (e: FocusEvent<FieldElement>) => void;
14
15
  }
15
16
  export type ReactFormField = Omit<FormField, 'props'> & {
16
17
  props: ReactFormFieldProps;
@@ -27,4 +28,5 @@ export type ReactFormField = Omit<FormField, 'props'> & {
27
28
  * @example mapFieldToReact(coreField)
28
29
  */
29
30
  export declare function mapFieldToReact(field: FormField): ReactFormField;
31
+ export {};
30
32
  //# sourceMappingURL=map-field-to-react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"map-field-to-react.d.ts","sourceRoot":"","sources":["../../src/utils/map-field-to-react.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAkB,MAAM,OAAO,CAAA;AAE/E,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAA;IAClC,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;IAChC,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;IAC5C,QAAQ,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;IAC/C,MAAM,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;CAC7C;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG;IACtD,KAAK,EAAE,mBAAmB,CAAA;CAC3B,CAAA;AAwBD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAYhE"}
1
+ {"version":3,"file":"map-field-to-react.d.ts","sourceRoot":"","sources":["../../src/utils/map-field-to-react.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAkB,MAAM,OAAO,CAAA;AAG/E,KAAK,YAAY,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,mBAAmB,CAAA;AAE9E,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAA;IAClC,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;IAChC,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,KAAK,IAAI,CAAA;IAC7C,QAAQ,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,KAAK,IAAI,CAAA;IAChD,MAAM,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAA;CAC9C;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG;IACtD,KAAK,EAAE,mBAAmB,CAAA;CAC3B,CAAA;AAiBD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAYhE"}
@@ -1 +1 @@
1
- function e(e){return t=>{Object.defineProperty(t.nativeEvent,`currentTarget`,{value:t.currentTarget,configurable:!0}),e(t.nativeEvent)}}function t(t){let{oninput:n,onchange:r,onblur:i,...a}=t.props;return{...t,props:{...a,onInput:e(n),onChange:e(r),onBlur:e(i)}}}export{t as mapFieldToReact};
1
+ import{restoreCurrentTarget as e}from"./restore-current-target.js";function t(t){return n=>{e(n.nativeEvent,n.currentTarget),t(n.nativeEvent)}}function n(e){let{oninput:n,onchange:r,onblur:i,...a}=e.props;return{...e,props:{...a,onInput:t(n),onChange:t(r),onBlur:t(i)}}}export{n as mapFieldToReact};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=map-field-to-react.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-field-to-react.test.d.ts","sourceRoot":"","sources":["../../src/utils/map-field-to-react.test.tsx"],"names":[],"mappings":""}
@@ -1,16 +1,16 @@
1
1
  import { SubmitEventWithCurrentTarget } from '@picked/client/form';
2
2
  /**
3
- * Restores currentTarget on a native event and narrows to SubmitEventWithCurrentTarget.
3
+ * Narrows a native form submit event to SubmitEventWithCurrentTarget, restoring
4
+ * currentTarget as a side effect so the core SDK can build FormData.
4
5
  *
5
- * React's synthetic events preserve currentTarget, but the DOM resets currentTarget to
6
- * null on the native event after dispatch completes. The core SDK's submit pipeline needs
7
- * currentTarget to construct FormData, so this bridges the gap by writing the React-preserved
8
- * currentTarget back onto the native event.
6
+ * Always runs unconditionally. Testing-library's `fireEvent.submit` dispatches
7
+ * a plain Event (not SubmitEvent), and some legacy programmatic submits do the
8
+ * same. The core consumer only reads currentTarget, so the narrowed type is a
9
+ * TypeScript assertion, not a runtime gate.
9
10
  *
10
- * @param {Event} nativeEvent - The native DOM event from a React form submission.
11
- * @param {HTMLFormElement} currentTarget - The form element from React's synthetic event.
12
- * @returns {boolean} Whether the event is a valid SubmitEvent with currentTarget restored.
11
+ * @param {Event} nativeEvent - Native DOM event from a React form submission.
12
+ * @param {HTMLFormElement} currentTarget - Form element from React's synthetic event.
13
13
  * @example prepareNativeEvent(e.nativeEvent, e.currentTarget)
14
14
  */
15
- export declare function prepareNativeEvent(nativeEvent: Event, currentTarget: HTMLFormElement): nativeEvent is SubmitEventWithCurrentTarget;
15
+ export declare function prepareNativeEvent(nativeEvent: Event, currentTarget: HTMLFormElement): asserts nativeEvent is SubmitEventWithCurrentTarget;
16
16
  //# sourceMappingURL=prepare-native-event.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare-native-event.d.ts","sourceRoot":"","sources":["../../src/utils/prepare-native-event.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAA;AAEvE;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,KAAK,EAClB,aAAa,EAAE,eAAe,GAC7B,WAAW,IAAI,4BAA4B,CAO7C"}
1
+ {"version":3,"file":"prepare-native-event.d.ts","sourceRoot":"","sources":["../../src/utils/prepare-native-event.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAA;AAGvE;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,KAAK,EAClB,aAAa,EAAE,eAAe,GAC7B,OAAO,CAAC,WAAW,IAAI,4BAA4B,CAErD"}
@@ -1 +1 @@
1
- function e(e,t){return`submitter`in e?(Object.defineProperty(e,`currentTarget`,{value:t,configurable:!0}),!0):!1}export{e as prepareNativeEvent};
1
+ import{restoreCurrentTarget as e}from"./restore-current-target.js";function t(t,n){e(t,n)}export{t as prepareNativeEvent};
@@ -0,0 +1,17 @@
1
+ /** @file Writes currentTarget onto a native event to bridge React's synthetic events to DOM handlers. */
2
+ /**
3
+ * Writes currentTarget onto a native DOM event.
4
+ *
5
+ * React delegates events at the root and preserves currentTarget only on its
6
+ * synthetic wrapper — the underlying native event has currentTarget set to the
7
+ * delegation root during dispatch and reset to null afterwards. The core SDK's
8
+ * handlers read currentTarget directly, so this restores the element that React
9
+ * routed the event to. `writable: true` lets the property be reassigned if the
10
+ * same event bubbles through multiple bridged handlers.
11
+ *
12
+ * @param {Event} event - The native DOM event from a React synthetic event.
13
+ * @param {EventTarget} currentTarget - The element from React's synthetic event.
14
+ * @example restoreCurrentTarget(e.nativeEvent, e.currentTarget)
15
+ */
16
+ export declare function restoreCurrentTarget(event: Event, currentTarget: EventTarget): void;
17
+ //# sourceMappingURL=restore-current-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore-current-target.d.ts","sourceRoot":"","sources":["../../src/utils/restore-current-target.ts"],"names":[],"mappings":"AAAA,yGAAyG;AAEzG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,GAAG,IAAI,CAMnF"}
@@ -0,0 +1 @@
1
+ function e(e,t){Object.defineProperty(e,`currentTarget`,{value:t,configurable:!0,writable:!0})}export{e as restoreCurrentTarget};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picked/react",
3
- "version": "0.0.1-dev.1776324257073",
3
+ "version": "0.0.1-dev.1776409551160",
4
4
  "devDependencies": {
5
5
  "@picked/client": "workspace:*",
6
6
  "@repo/eslint-config": "workspace:*",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "module": "./dist/index.js",
87
87
  "peerDependencies": {
88
- "@picked/client": "0.0.1-dev.1776324257073",
88
+ "@picked/client": "0.0.1-dev.1776409551160",
89
89
  "effector": "^23.3.0",
90
90
  "effector-react": "^23.3.0",
91
91
  "react": "19.2.2",