@embeddables/forms 0.2.0 → 0.3.0

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 +1 @@
1
- {"version":3,"file":"react.cjs","names":["useRef","useCallback","useSyncExternalStore","useEmbeddablesModule","useState","useCallback","initForms","FormsError"],"sources":["../src/react/use-form-store.ts","../src/react/forms-registry.ts","../src/react/use-forms.ts","../src/react/use-form.ts","../src/react/use-form-errors.ts","../src/react/use-form-field.ts","../src/react/resolve-core-analytics.ts","../src/react/register-forms-client.ts","../src/react/forms-module.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from 'react'\n\nimport type { FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport type FormSnapshot<TSchema extends FormSchema> = Readonly<{\n values: Partial<FormValues<TSchema>>\n errors: FieldErrors<TSchema>\n}>\n\nconst EMPTY_SNAPSHOT: FormSnapshot<FormSchema> = Object.freeze({\n values: {},\n errors: {},\n})\n\nfunction createSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema>,\n): FormSnapshot<TSchema> {\n return Object.freeze({\n values: form.getAll(),\n errors: form.errors(),\n })\n}\n\ninterface CachedSnapshot<TSchema extends FormSchema> {\n readonly form: FormInstance<TSchema>\n readonly snapshot: FormSnapshot<TSchema>\n}\n\nexport function useFormSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FormSnapshot<TSchema> {\n const cachedRef = useRef<CachedSnapshot<TSchema> | null>(null)\n const emptyRef = useRef<FormSnapshot<TSchema>>(EMPTY_SNAPSHOT as FormSnapshot<TSchema>)\n\n const subscribe = useCallback(\n (listener: () => void) => {\n if (form === null) return () => undefined\n return form.subscribe(() => {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n listener()\n })\n },\n [form],\n )\n\n const getSnapshot = useCallback((): FormSnapshot<TSchema> => {\n if (form === null) {\n // * Otherwise a later A -> null -> mutate A -> A sequence would resurrect\n // * a snapshot cached before the detach, missing the mutation in between.\n cachedRef.current = null\n return emptyRef.current\n }\n // * A cached snapshot from a previous form instance must not survive a\n // * form change — recompute so switching forms without a mutation still\n // * returns the new form's values and errors.\n if (cachedRef.current === null || cachedRef.current.form !== form) {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n }\n return cachedRef.current.snapshot\n }, [form])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import type { FormSchemaMap, FormsClient } from '../core/form.js'\n\nexport const FORMS_MODULE_KEY = 'forms'\n\n/**\n * Idempotence guard for `registerFormsClient` only — React reads the client\n * from provider context, not from here.\n */\nexport const formsByCore = new WeakMap<object, FormsClient<FormSchemaMap>>()\n\nexport function getRegisteredFormsClient(core: object): FormsClient<FormSchemaMap> | undefined {\n return formsByCore.get(core)\n}\n","import { useEmbeddablesModule } from '@embeddables/core/react'\n\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\n\nimport type { FormSchemaMap, FormsClient, InitFormsOptions } from '../core/form.js'\n\nexport type FormsReactOptions<TSchemas extends FormSchemaMap = FormSchemaMap> = Omit<\n InitFormsOptions<TSchemas>,\n 'core'\n>\n\n/** @internal Product hooks read the module client from provider context. */\nexport function useRegisteredFormsClient<\n TSchemas extends FormSchemaMap = FormSchemaMap,\n>(): FormsClient<TSchemas> | null {\n return useEmbeddablesModule<FormsClient<TSchemas>>({ key: FORMS_MODULE_KEY })\n}\n","import { useFormSnapshot } from './use-form-store.js'\nimport { useRegisteredFormsClient } from './use-forms.js'\n\nimport type { FormInstance, FormSchemaMap } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\n/**\n * Reactive binding for one declared form.\n *\n * Takes no type arguments: `TFormId` is inferred from `formId`, and the schema\n * map comes from the registry `em build` augments. Pass both explicitly\n * (`useForm<'signup', OtherSchemas>`) only to work against a map other than the\n * registered one.\n */\nexport function useForm<\n TFormId extends keyof TSchemas & string,\n TSchemas extends FormSchemaMap = RegisteredSchemas,\n>({\n formId,\n}: {\n formId: TFormId\n}): {\n form: FormInstance<TSchemas[TFormId]> | null\n values: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['values']\n errors: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['errors']\n} {\n const client = useRegisteredFormsClient<TSchemas>()\n\n // * Safe to call on every render: the client returns one instance per form id.\n const form = client === null ? null : client.getForm({ formId })\n const { values, errors } = useFormSnapshot(form)\n\n return { form, values, errors }\n}\n","import { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormSchema } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport function useFormErrors<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FieldErrors<TSchema> {\n const { errors } = useFormSnapshot(form)\n return errors\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nimport { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormFieldKey, FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance, SetResult } from '../core/form.js'\n\nconst noopSetValue = async (): Promise<SetResult<FormSchema>> => ({\n ok: false,\n errors: {},\n})\n\nexport function useFormField<const TSchema extends FormSchema, K extends FormFieldKey<TSchema>>({\n form,\n key,\n}: {\n form: FormInstance<TSchema> | null\n key: K\n}): {\n value: FormValues<TSchema>[K] | undefined\n error: readonly string[] | undefined\n setValue: (value: FormValues<TSchema>[K] | undefined) => void\n commit: (value: FormValues<TSchema>[K] | undefined) => Promise<SetResult<TSchema>>\n onBlur: () => Promise<SetResult<TSchema>>\n} {\n const { values, errors } = useFormSnapshot(form)\n const committed = values[key]\n const [draft, setDraft] = useState<FormValues<TSchema>[K] | undefined>(committed)\n\n useEffect(() => {\n setDraft(committed)\n }, [form, key, committed])\n\n const setValue = useCallback((value: FormValues<TSchema>[K] | undefined) => {\n setDraft(value)\n }, [])\n\n // * Takes the value as an argument rather than reading `draft`, so it is\n // * correct when called in the same tick as the change that produced it.\n // * `onBlur` cannot be: it compares the `draft`/`committed` pair captured in\n // * the current render, which a same-tick `setValue` has not updated yet.\n const commit = useCallback(\n (value: FormValues<TSchema>[K] | undefined): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n // * Keeps the control responsive while `set` runs, and keeps a rejected\n // * value on screen next to its error instead of snapping back.\n setDraft(value)\n return form.set({ [key]: value } as Partial<FormValues<TSchema>>)\n },\n [form, key],\n )\n\n const onBlur = useCallback(async (): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n if (draft === committed) {\n return { ok: true, errors: {} as FieldErrors<TSchema> }\n }\n return form.set({ [key]: draft } as Partial<FormValues<TSchema>>)\n }, [committed, draft, form, key])\n\n if (form === null) {\n return {\n value: undefined,\n error: undefined,\n setValue: () => undefined,\n commit: async () => noopSetValue(),\n onBlur: async () => noopSetValue(),\n }\n }\n\n return {\n value: draft,\n error: errors[key],\n setValue,\n commit,\n onBlur,\n }\n}\n","import type { AnalyticsInstance } from '@embeddables/core'\nimport type { EmbeddablesInstance } from '@embeddables/core'\n\nexport function resolveCoreAnalyticsInstance(\n core: EmbeddablesInstance,\n): AnalyticsInstance | undefined {\n if (typeof core.getAnalyticsInstance !== 'function') return undefined\n return core.getAnalyticsInstance() ?? undefined\n}\n","import { initForms } from '../core/form.js'\nimport { formsByCore } from './forms-registry.js'\nimport { resolveCoreAnalyticsInstance } from './resolve-core-analytics.js'\n\nimport type { FormsClient, InitFormsOptions } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\ninterface RegisterFormsModuleClientOptions extends InitFormsOptions<RegisteredSchemas> {\n /**\n * Set when `excludeAnalyticsInModules` names Forms. The exclusion is absolute:\n * it suppresses the Core-instance fallback as well as the injected client.\n */\n disableAnalyticsFallback?: boolean\n}\n\nfunction register({\n disableAnalyticsFallback,\n ...options\n}: RegisterFormsModuleClientOptions): FormsClient<RegisteredSchemas> {\n const { core } = options\n const existing = formsByCore.get(core)\n if (existing !== undefined) return existing\n\n const analyticsInstance = disableAnalyticsFallback\n ? undefined\n : (options.analyticsInstance ?? resolveCoreAnalyticsInstance(core))\n\n const client = initForms<RegisteredSchemas>({ ...options, core, analyticsInstance })\n formsByCore.set(core, client)\n return client\n}\n\nexport function registerFormsClient(\n options: InitFormsOptions<RegisteredSchemas>,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n\nexport function registerFormsModuleClient(\n options: RegisterFormsModuleClientOptions,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n","import type { EmbeddablesReactModule } from '@embeddables/core/react'\n\nimport { FormsError } from '../errors.js'\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\nimport { registerFormsModuleClient } from './register-forms-client.js'\n\nimport type { AnalyticsInstance } from '../core/analytics.js'\nimport type { FormsClient } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\nimport type { FormsReactOptions } from './use-forms.js'\n\nexport type { FormsReactOptions } from './use-forms.js'\n\n/**\n * What `EmbeddablesProvider` accepts under its top-level `forms` prop.\n *\n * `analyticsInstance` is deliberately absent: the provider injects the\n * Analytics module client through module dependencies, so an app never wires\n * that instance by hand.\n */\nexport type FormsProviderOptions = Omit<FormsReactOptions<RegisteredSchemas>, 'analyticsInstance'>\n\ndeclare module '@embeddables/core/react' {\n interface EmbeddablesReactModuleParameters {\n readonly forms: FormsProviderOptions\n }\n}\n\nconst ANALYTICS_MODULE_KEY = 'analytics'\n\nfunction resolveInjectedAnalytics(value: unknown): AnalyticsInstance | undefined {\n if (value === undefined) return undefined\n if (typeof value !== 'object' || value === null) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n const candidate = value as Partial<AnalyticsInstance>\n if (\n typeof candidate.trackEvent !== 'function' ||\n typeof candidate.getAppUserId !== 'function' ||\n typeof candidate.getProjectId !== 'function'\n ) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n return candidate as AnalyticsInstance\n}\n\nexport function forms(\n options: FormsReactOptions<RegisteredSchemas> = {},\n): EmbeddablesReactModule<FormsClient<RegisteredSchemas>, FormsProviderOptions> {\n return {\n key: FORMS_MODULE_KEY,\n dependencies: [{ key: ANALYTICS_MODULE_KEY, optional: true }],\n init: (core, context) => {\n const analyticsInstance = context?.analyticsExcluded\n ? undefined\n : (options.analyticsInstance ??\n resolveInjectedAnalytics(context?.dependencies.get(ANALYTICS_MODULE_KEY)))\n\n return registerFormsModuleClient({\n core,\n customValidations: context?.parameters?.customValidations ?? options.customValidations,\n serverFormData: context?.parameters?.serverFormData ?? options.serverFormData,\n analyticsInstance,\n disableAnalyticsFallback: context?.analyticsExcluded,\n })\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.cjs","names":["useRef","useCallback","useSyncExternalStore","useEmbeddablesModule","useState","useCallback","useState","useRef","useCallback","FormsError","initForms","FormsError"],"sources":["../src/react/use-form-store.ts","../src/react/forms-registry.ts","../src/react/use-forms.ts","../src/react/use-form.ts","../src/react/use-form-errors.ts","../src/react/use-form-field.ts","../src/react/use-form-file-upload.ts","../src/react/resolve-core-analytics.ts","../src/react/register-forms-client.ts","../src/react/forms-module.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from 'react'\n\nimport type { FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport type FormSnapshot<TSchema extends FormSchema> = Readonly<{\n values: Partial<FormValues<TSchema>>\n errors: FieldErrors<TSchema>\n}>\n\nconst EMPTY_SNAPSHOT: FormSnapshot<FormSchema> = Object.freeze({\n values: {},\n errors: {},\n})\n\nfunction createSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema>,\n): FormSnapshot<TSchema> {\n return Object.freeze({\n values: form.getAll(),\n errors: form.errors(),\n })\n}\n\ninterface CachedSnapshot<TSchema extends FormSchema> {\n readonly form: FormInstance<TSchema>\n readonly snapshot: FormSnapshot<TSchema>\n}\n\nexport function useFormSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FormSnapshot<TSchema> {\n const cachedRef = useRef<CachedSnapshot<TSchema> | null>(null)\n const emptyRef = useRef<FormSnapshot<TSchema>>(EMPTY_SNAPSHOT as FormSnapshot<TSchema>)\n\n const subscribe = useCallback(\n (listener: () => void) => {\n if (form === null) return () => undefined\n return form.subscribe(() => {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n listener()\n })\n },\n [form],\n )\n\n const getSnapshot = useCallback((): FormSnapshot<TSchema> => {\n if (form === null) {\n // * Otherwise a later A -> null -> mutate A -> A sequence would resurrect\n // * a snapshot cached before the detach, missing the mutation in between.\n cachedRef.current = null\n return emptyRef.current\n }\n // * A cached snapshot from a previous form instance must not survive a\n // * form change — recompute so switching forms without a mutation still\n // * returns the new form's values and errors.\n if (cachedRef.current === null || cachedRef.current.form !== form) {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n }\n return cachedRef.current.snapshot\n }, [form])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import type { FormSchemaMap, FormsClient } from '../core/form.js'\n\nexport const FORMS_MODULE_KEY = 'forms'\n\n/**\n * Idempotence guard for `registerFormsClient` only — React reads the client\n * from provider context, not from here.\n */\nexport const formsByCore = new WeakMap<object, FormsClient<FormSchemaMap>>()\n\nexport function getRegisteredFormsClient(core: object): FormsClient<FormSchemaMap> | undefined {\n return formsByCore.get(core)\n}\n","import { useEmbeddablesModule } from '@embeddables/core/react'\n\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\n\nimport type { FormSchemaMap, FormsClient, InitFormsOptions } from '../core/form.js'\n\nexport type FormsReactOptions<TSchemas extends FormSchemaMap = FormSchemaMap> = Omit<\n InitFormsOptions<TSchemas>,\n 'core'\n>\n\n/** @internal Product hooks read the module client from provider context. */\nexport function useRegisteredFormsClient<\n TSchemas extends FormSchemaMap = FormSchemaMap,\n>(): FormsClient<TSchemas> | null {\n return useEmbeddablesModule<FormsClient<TSchemas>>({ key: FORMS_MODULE_KEY })\n}\n","import { useFormSnapshot } from './use-form-store.js'\nimport { useRegisteredFormsClient } from './use-forms.js'\n\nimport type { FormInstance, FormSchemaMap } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\n/**\n * Reactive binding for one declared form.\n *\n * Takes no type arguments: `TFormId` is inferred from `formId`, and the schema\n * map comes from the registry `em build` augments. Pass both explicitly\n * (`useForm<'signup', OtherSchemas>`) only to work against a map other than the\n * registered one.\n */\nexport function useForm<\n TFormId extends keyof TSchemas & string,\n TSchemas extends FormSchemaMap = RegisteredSchemas,\n>({\n formId,\n}: {\n formId: TFormId\n}): {\n form: FormInstance<TSchemas[TFormId]> | null\n values: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['values']\n errors: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['errors']\n} {\n const client = useRegisteredFormsClient<TSchemas>()\n\n // * Safe to call on every render: the client returns one instance per form id.\n const form = client === null ? null : client.getForm({ formId })\n const { values, errors } = useFormSnapshot(form)\n\n return { form, values, errors }\n}\n","import { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormSchema } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport function useFormErrors<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FieldErrors<TSchema> {\n const { errors } = useFormSnapshot(form)\n return errors\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nimport { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormFieldKey, FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance, SetResult } from '../core/form.js'\n\nconst noopSetValue = async (): Promise<SetResult<FormSchema>> => ({\n ok: false,\n errors: {},\n})\n\nexport function useFormField<const TSchema extends FormSchema, K extends FormFieldKey<TSchema>>({\n form,\n key,\n}: {\n form: FormInstance<TSchema> | null\n key: K\n}): {\n value: FormValues<TSchema>[K] | undefined\n error: readonly string[] | undefined\n setValue: (value: FormValues<TSchema>[K] | undefined) => void\n commit: (value: FormValues<TSchema>[K] | undefined) => Promise<SetResult<TSchema>>\n onBlur: () => Promise<SetResult<TSchema>>\n} {\n const { values, errors } = useFormSnapshot(form)\n const committed = values[key]\n const [draft, setDraft] = useState<FormValues<TSchema>[K] | undefined>(committed)\n\n useEffect(() => {\n setDraft(committed)\n }, [form, key, committed])\n\n const setValue = useCallback((value: FormValues<TSchema>[K] | undefined) => {\n setDraft(value)\n }, [])\n\n // * Takes the value as an argument rather than reading `draft`, so it is\n // * correct when called in the same tick as the change that produced it.\n // * `onBlur` cannot be: it compares the `draft`/`committed` pair captured in\n // * the current render, which a same-tick `setValue` has not updated yet.\n const commit = useCallback(\n (value: FormValues<TSchema>[K] | undefined): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n // * Keeps the control responsive while `set` runs, and keeps a rejected\n // * value on screen next to its error instead of snapping back.\n setDraft(value)\n return form.set({ [key]: value } as Partial<FormValues<TSchema>>)\n },\n [form, key],\n )\n\n const onBlur = useCallback(async (): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n if (draft === committed) {\n return { ok: true, errors: {} as FieldErrors<TSchema> }\n }\n return form.set({ [key]: draft } as Partial<FormValues<TSchema>>)\n }, [committed, draft, form, key])\n\n if (form === null) {\n return {\n value: undefined,\n error: undefined,\n setValue: () => undefined,\n commit: async () => noopSetValue(),\n onBlur: async () => noopSetValue(),\n }\n }\n\n return {\n value: draft,\n error: errors[key],\n setValue,\n commit,\n onBlur,\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { FormsError } from '../errors.js'\nimport { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance, SetResult } from '../core/form.js'\nimport type { ChangeEvent } from 'react'\n\n/** Keys declared with `value_type: file` on a schema. */\nexport type FormFileFieldKey<TSchema extends FormSchema> = Extract<\n TSchema['fields'][number],\n { value_type: 'file' }\n>['key']\n\nconst noopSetResult = async <TSchema extends FormSchema>(): Promise<SetResult<TSchema>> => ({\n ok: false,\n errors: {} as FieldErrors<TSchema>,\n})\n\n/**\n * Reactive binding for a `type: file` field: uploads through the public API,\n * commits the returned `FormFileRef`, and exposes a native `<input type=\"file\">`\n * handler.\n */\nexport function useFormFileUpload<\n const TSchema extends FormSchema,\n K extends FormFileFieldKey<TSchema>,\n>({\n form,\n key,\n}: {\n form: FormInstance<TSchema> | null\n key: K\n}): {\n value: FormValues<TSchema>[K] | undefined\n error: readonly string[] | undefined\n isLoading: boolean\n uploadError: string | undefined\n upload: (file: File) => Promise<SetResult<TSchema>>\n clear: () => Promise<SetResult<TSchema>>\n inputProps: {\n type: 'file'\n disabled: boolean\n onChange: (event: ChangeEvent<HTMLInputElement>) => void\n }\n} {\n const { values, errors } = useFormSnapshot(form)\n const [isLoading, setIsLoading] = useState(false)\n const [uploadError, setUploadError] = useState<string | undefined>(undefined)\n const uploadGenerationRef = useRef(0)\n\n useEffect(() => {\n return () => {\n uploadGenerationRef.current += 1\n setIsLoading(false)\n setUploadError(undefined)\n }\n }, [form, key])\n\n const upload = useCallback(\n async (file: File): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetResult<TSchema>()\n\n const generation = ++uploadGenerationRef.current\n setIsLoading(true)\n setUploadError(undefined)\n try {\n const ref = await form.uploadFile({ key, file })\n if (generation !== uploadGenerationRef.current) {\n return { ok: false, errors: {} as FieldErrors<TSchema> }\n }\n return await form.set({ [key]: ref } as Partial<FormValues<TSchema>>)\n } catch (error) {\n if (generation !== uploadGenerationRef.current) {\n return { ok: false, errors: {} as FieldErrors<TSchema> }\n }\n const message = error instanceof FormsError ? error.message : 'File upload failed.'\n setUploadError(message)\n return { ok: false, errors: {} as FieldErrors<TSchema> }\n } finally {\n if (generation === uploadGenerationRef.current) {\n setIsLoading(false)\n }\n }\n },\n [form, key],\n )\n\n const clear = useCallback(async (): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetResult<TSchema>()\n uploadGenerationRef.current += 1\n setIsLoading(false)\n setUploadError(undefined)\n return form.set({ [key]: null } as Partial<FormValues<TSchema>>)\n }, [form, key])\n\n const onChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0]\n if (file === undefined) return\n void upload(file)\n // * Lets the user pick the same file again after a failed upload.\n event.target.value = ''\n },\n [upload],\n )\n\n if (form === null) {\n return {\n value: undefined,\n error: undefined,\n isLoading: false,\n uploadError: undefined,\n upload: async () => noopSetResult<TSchema>(),\n clear: async () => noopSetResult<TSchema>(),\n inputProps: {\n type: 'file',\n disabled: true,\n onChange: () => undefined,\n },\n }\n }\n\n return {\n value: values[key],\n error: errors[key],\n isLoading,\n uploadError,\n upload,\n clear,\n inputProps: {\n type: 'file',\n disabled: isLoading,\n onChange,\n },\n }\n}\n","import type { AnalyticsInstance } from '@embeddables/core'\nimport type { EmbeddablesInstance } from '@embeddables/core'\n\nexport function resolveCoreAnalyticsInstance(\n core: EmbeddablesInstance,\n): AnalyticsInstance | undefined {\n if (typeof core.getAnalyticsInstance !== 'function') return undefined\n return core.getAnalyticsInstance() ?? undefined\n}\n","import { initForms } from '../core/form.js'\nimport { formsByCore } from './forms-registry.js'\nimport { resolveCoreAnalyticsInstance } from './resolve-core-analytics.js'\n\nimport type { FormsClient, InitFormsOptions } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\ninterface RegisterFormsModuleClientOptions extends InitFormsOptions<RegisteredSchemas> {\n /**\n * Set when `excludeAnalyticsInModules` names Forms. The exclusion is absolute:\n * it suppresses the Core-instance fallback as well as the injected client.\n */\n disableAnalyticsFallback?: boolean\n}\n\nfunction register({\n disableAnalyticsFallback,\n ...options\n}: RegisterFormsModuleClientOptions): FormsClient<RegisteredSchemas> {\n const { core } = options\n const existing = formsByCore.get(core)\n if (existing !== undefined) return existing\n\n const analyticsInstance = disableAnalyticsFallback\n ? undefined\n : (options.analyticsInstance ?? resolveCoreAnalyticsInstance(core))\n\n const client = initForms<RegisteredSchemas>({ ...options, core, analyticsInstance })\n formsByCore.set(core, client)\n return client\n}\n\nexport function registerFormsClient(\n options: InitFormsOptions<RegisteredSchemas>,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n\nexport function registerFormsModuleClient(\n options: RegisterFormsModuleClientOptions,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n","import type { EmbeddablesReactModule } from '@embeddables/core/react'\n\nimport { FormsError } from '../errors.js'\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\nimport { registerFormsModuleClient } from './register-forms-client.js'\n\nimport type { AnalyticsInstance } from '../core/analytics.js'\nimport type { FormsClient } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\nimport type { FormsReactOptions } from './use-forms.js'\n\nexport type { FormsReactOptions } from './use-forms.js'\n\n/**\n * What `EmbeddablesProvider` accepts under its top-level `forms` prop.\n *\n * `analyticsInstance` is deliberately absent: the provider injects the\n * Analytics module client through module dependencies, so an app never wires\n * that instance by hand.\n */\nexport type FormsProviderOptions = Omit<FormsReactOptions<RegisteredSchemas>, 'analyticsInstance'>\n\ndeclare module '@embeddables/core/react' {\n interface EmbeddablesReactModuleParameters {\n readonly forms: FormsProviderOptions\n }\n}\n\nconst ANALYTICS_MODULE_KEY = 'analytics'\n\nfunction resolveInjectedAnalytics(value: unknown): AnalyticsInstance | undefined {\n if (value === undefined) return undefined\n if (typeof value !== 'object' || value === null) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n const candidate = value as Partial<AnalyticsInstance>\n if (\n typeof candidate.trackEvent !== 'function' ||\n typeof candidate.getAppUserId !== 'function' ||\n typeof candidate.getProjectId !== 'function'\n ) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n return candidate as AnalyticsInstance\n}\n\nexport function forms(\n options: FormsReactOptions<RegisteredSchemas> = {},\n): EmbeddablesReactModule<FormsClient<RegisteredSchemas>, FormsProviderOptions> {\n return {\n key: FORMS_MODULE_KEY,\n dependencies: [{ key: ANALYTICS_MODULE_KEY, optional: true }],\n init: (core, context) => {\n const analyticsInstance = context?.analyticsExcluded\n ? undefined\n : (options.analyticsInstance ??\n resolveInjectedAnalytics(context?.dependencies.get(ANALYTICS_MODULE_KEY)))\n\n return registerFormsModuleClient({\n core,\n customValidations: context?.parameters?.customValidations ?? options.customValidations,\n serverFormData: context?.parameters?.serverFormData ?? options.serverFormData,\n analyticsInstance,\n disableAnalyticsFallback: context?.analyticsExcluded,\n })\n },\n }\n}\n"],"mappings":"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"}
package/dist/react.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import "./index-BB698udY.js";
2
- import { E as FormValues, T as FormSchema, a as FormSchemaMap, f as SetResult, i as FormInstance, l as InitFormsOptions, n as FieldErrors, s as FormsClient, w as FormFieldKey } from "./form-Br23yPDS.js";
1
+ import "./index-FePzwfQE.js";
2
+ import { C as FormSchema, S as FormFieldKey, a as FormSchemaMap, f as SetResult, i as FormInstance, l as InitFormsOptions, n as FieldErrors, s as FormsClient, w as FormValues } from "./form-DKPfOrTG.js";
3
+ import { ChangeEvent } from "react";
3
4
  import { EmbeddablesReactModule } from "@embeddables/core/react";
4
5
  //#region src/react/use-form-store.d.ts
5
6
  type FormSnapshot<TSchema extends FormSchema> = Readonly<{
@@ -68,6 +69,33 @@ declare function useFormField<const TSchema extends FormSchema, K extends FormFi
68
69
  onBlur: () => Promise<SetResult<TSchema>>;
69
70
  };
70
71
  //#endregion
72
+ //#region src/react/use-form-file-upload.d.ts
73
+ /** Keys declared with `value_type: file` on a schema. */
74
+ type FormFileFieldKey<TSchema extends FormSchema> = Extract<TSchema['fields'][number], {
75
+ value_type: 'file';
76
+ }>['key'];
77
+ /**
78
+ * Reactive binding for a `type: file` field: uploads through the public API,
79
+ * commits the returned `FormFileRef`, and exposes a native `<input type="file">`
80
+ * handler.
81
+ */
82
+ declare function useFormFileUpload<const TSchema extends FormSchema, K extends FormFileFieldKey<TSchema>>({ form, key }: {
83
+ form: FormInstance<TSchema> | null;
84
+ key: K;
85
+ }): {
86
+ value: FormValues<TSchema>[K] | undefined;
87
+ error: readonly string[] | undefined;
88
+ isLoading: boolean;
89
+ uploadError: string | undefined;
90
+ upload: (file: File) => Promise<SetResult<TSchema>>;
91
+ clear: () => Promise<SetResult<TSchema>>;
92
+ inputProps: {
93
+ type: 'file';
94
+ disabled: boolean;
95
+ onChange: (event: ChangeEvent<HTMLInputElement>) => void;
96
+ };
97
+ };
98
+ //#endregion
71
99
  //#region src/react/use-forms.d.ts
72
100
  type FormsReactOptions<TSchemas extends FormSchemaMap = FormSchemaMap> = Omit<InitFormsOptions<TSchemas>, 'core'>;
73
101
  //#endregion
@@ -93,5 +121,5 @@ declare function registerFormsClient(options: InitFormsOptions<RegisteredSchemas
93
121
  //#region src/react/forms-registry.d.ts
94
122
  declare function getRegisteredFormsClient(core: object): FormsClient<FormSchemaMap> | undefined;
95
123
  //#endregion
96
- export { type EmbeddablesSchemaRegistry, type FormsProviderOptions, type FormsReactOptions, type RegisteredSchemas, forms, getRegisteredFormsClient, registerFormsClient, useForm, useFormErrors, useFormField };
124
+ export { type EmbeddablesSchemaRegistry, type FormFileFieldKey, type FormsProviderOptions, type FormsReactOptions, type RegisteredSchemas, forms, getRegisteredFormsClient, registerFormsClient, useForm, useFormErrors, useFormField, useFormFileUpload };
97
125
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","names":[],"sources":["../src/react/use-form-store.ts","../src/react/schema-registry.ts","../src/react/use-form.ts","../src/react/use-form-errors.ts","../src/react/use-form-field.ts","../src/react/use-forms.ts","../src/react/forms-module.ts","../src/react/register-forms-client.ts","../src/react/forms-registry.ts"],"mappings":";;;;KAKY,aAAa,gBAAgB,cAAc;EACrD,QAAQ,QAAQ,WAAW;EAC3B,QAAQ,YAAY;;iBAsBN,gBAAgB,gBAAgB,YAC9C,MAAM,aAAa,kBAClB,aAAa;;;;;;;;;;;;;;;;;;;;UCXC;;;;;;KAOL,oBAAoB;EAC9B,aAAa,iBAAiB;IAE5B,WACA;;;;;;;;;;;iBCjBY,QACd,sBAAsB,mBACtB,iBAAiB,gBAAgB,qBAEjC;EAEA,QAAQ;;EAER,MAAM,aAAa,SAAS;EAC5B,QAAQ,kBAAkB,gBAAgB,SAAS;EACnD,QAAQ,kBAAkB,gBAAgB,SAAS;;;;iBCnBrC,cAAc,gBAAgB,YAC5C,MAAM,aAAa,kBAClB,YAAY;;;iBCKC,mBAAmB,gBAAgB,YAAY,UAAU,aAAa,YACpF,MACA;EAEA,MAAM,aAAa;EACnB,KAAK;;EAEL,OAAO,WAAW,SAAS;EAC3B;EACA,WAAW,OAAO,WAAW,SAAS;EACtC,SAAS,OAAO,WAAW,SAAS,mBAAmB,QAAQ,UAAU;EACzE,cAAc,QAAQ,UAAU;;;;KCjBtB,kBAAkB,iBAAiB,gBAAgB,iBAAiB,KAC9E,iBAAiB;;;;;;;;;;KCaP,uBAAuB,KAAK,kBAAkB;;YAG9C;aACC,OAAO;;;iBAsBJ,MACd,UAAS,kBAAkB,qBAC1B,uBAAuB,YAAY,oBAAoB;;;iBChB1C,oBACd,SAAS,iBAAiB,qBACzB,YAAY;;;iBCxBC,yBAAyB,eAAe,YAAY"}
1
+ {"version":3,"file":"react.d.ts","names":[],"sources":["../src/react/use-form-store.ts","../src/react/schema-registry.ts","../src/react/use-form.ts","../src/react/use-form-errors.ts","../src/react/use-form-field.ts","../src/react/use-form-file-upload.ts","../src/react/use-forms.ts","../src/react/forms-module.ts","../src/react/register-forms-client.ts","../src/react/forms-registry.ts"],"mappings":";;;;;KAKY,aAAa,gBAAgB,cAAc;EACrD,QAAQ,QAAQ,WAAW;EAC3B,QAAQ,YAAY;;iBAsBN,gBAAgB,gBAAgB,YAC9C,MAAM,aAAa,kBAClB,aAAa;;;;;;;;;;;;;;;;;;;;UCXC;;;;;;KAOL,oBAAoB;EAC9B,aAAa,iBAAiB;IAE5B,WACA;;;;;;;;;;;iBCjBY,QACd,sBAAsB,mBACtB,iBAAiB,gBAAgB,qBAEjC;EAEA,QAAQ;;EAER,MAAM,aAAa,SAAS;EAC5B,QAAQ,kBAAkB,gBAAgB,SAAS;EACnD,QAAQ,kBAAkB,gBAAgB,SAAS;;;;iBCnBrC,cAAc,gBAAgB,YAC5C,MAAM,aAAa,kBAClB,YAAY;;;iBCKC,mBAAmB,gBAAgB,YAAY,UAAU,aAAa,YACpF,MACA;EAEA,MAAM,aAAa;EACnB,KAAK;;EAEL,OAAO,WAAW,SAAS;EAC3B;EACA,WAAW,OAAO,WAAW,SAAS;EACtC,SAAS,OAAO,WAAW,SAAS,mBAAmB,QAAQ,UAAU;EACzE,cAAc,QAAQ,UAAU;;;;;KCbtB,iBAAiB,gBAAgB,cAAc,QACzD;EACE;;;;;;;iBAaY,wBACR,gBAAgB,YACtB,UAAU,iBAAiB,YAE3B,MACA;EAEA,MAAM,aAAa;EACnB,KAAK;;EAEL,OAAO,WAAW,SAAS;EAC3B;EACA;EACA;EACA,SAAS,MAAM,SAAS,QAAQ,UAAU;EAC1C,aAAa,QAAQ,UAAU;EAC/B;IACE;IACA;IACA,WAAW,OAAO,YAAY;;;;;KCtCtB,kBAAkB,iBAAiB,gBAAgB,iBAAiB,KAC9E,iBAAiB;;;;;;;;;;KCaP,uBAAuB,KAAK,kBAAkB;;YAG9C;aACC,OAAO;;;iBAsBJ,MACd,UAAS,kBAAkB,qBAC1B,uBAAuB,YAAY,oBAAoB;;;iBChB1C,oBACd,SAAS,iBAAiB,qBACzB,YAAY;;;iBCxBC,yBAAyB,eAAe,YAAY"}
package/dist/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as initForms, s as FormsError } from "./form-Bt5pwVP6.js";
1
+ import { n as initForms, s as FormsError } from "./form-CR5xJ_nQ.js";
2
2
  import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
3
3
  import { useEmbeddablesModule } from "@embeddables/core/react";
4
4
  //#region src/react/use-form-store.ts
@@ -135,6 +135,99 @@ function useFormField({ form, key }) {
135
135
  };
136
136
  }
137
137
  //#endregion
138
+ //#region src/react/use-form-file-upload.ts
139
+ const noopSetResult = async () => ({
140
+ ok: false,
141
+ errors: {}
142
+ });
143
+ /**
144
+ * Reactive binding for a `type: file` field: uploads through the public API,
145
+ * commits the returned `FormFileRef`, and exposes a native `<input type="file">`
146
+ * handler.
147
+ */
148
+ function useFormFileUpload({ form, key }) {
149
+ const { values, errors } = useFormSnapshot(form);
150
+ const [isLoading, setIsLoading] = useState(false);
151
+ const [uploadError, setUploadError] = useState(void 0);
152
+ const uploadGenerationRef = useRef(0);
153
+ useEffect(() => {
154
+ return () => {
155
+ uploadGenerationRef.current += 1;
156
+ setIsLoading(false);
157
+ setUploadError(void 0);
158
+ };
159
+ }, [form, key]);
160
+ const upload = useCallback(async (file) => {
161
+ if (form === null) return noopSetResult();
162
+ const generation = ++uploadGenerationRef.current;
163
+ setIsLoading(true);
164
+ setUploadError(void 0);
165
+ try {
166
+ const ref = await form.uploadFile({
167
+ key,
168
+ file
169
+ });
170
+ if (generation !== uploadGenerationRef.current) return {
171
+ ok: false,
172
+ errors: {}
173
+ };
174
+ return await form.set({ [key]: ref });
175
+ } catch (error) {
176
+ if (generation !== uploadGenerationRef.current) return {
177
+ ok: false,
178
+ errors: {}
179
+ };
180
+ const message = error instanceof FormsError ? error.message : "File upload failed.";
181
+ setUploadError(message);
182
+ return {
183
+ ok: false,
184
+ errors: {}
185
+ };
186
+ } finally {
187
+ if (generation === uploadGenerationRef.current) setIsLoading(false);
188
+ }
189
+ }, [form, key]);
190
+ const clear = useCallback(async () => {
191
+ if (form === null) return noopSetResult();
192
+ uploadGenerationRef.current += 1;
193
+ setIsLoading(false);
194
+ setUploadError(void 0);
195
+ return form.set({ [key]: null });
196
+ }, [form, key]);
197
+ const onChange = useCallback((event) => {
198
+ const file = event.target.files?.[0];
199
+ if (file === void 0) return;
200
+ upload(file);
201
+ event.target.value = "";
202
+ }, [upload]);
203
+ if (form === null) return {
204
+ value: void 0,
205
+ error: void 0,
206
+ isLoading: false,
207
+ uploadError: void 0,
208
+ upload: async () => noopSetResult(),
209
+ clear: async () => noopSetResult(),
210
+ inputProps: {
211
+ type: "file",
212
+ disabled: true,
213
+ onChange: () => void 0
214
+ }
215
+ };
216
+ return {
217
+ value: values[key],
218
+ error: errors[key],
219
+ isLoading,
220
+ uploadError,
221
+ upload,
222
+ clear,
223
+ inputProps: {
224
+ type: "file",
225
+ disabled: isLoading,
226
+ onChange
227
+ }
228
+ };
229
+ }
230
+ //#endregion
138
231
  //#region src/react/resolve-core-analytics.ts
139
232
  function resolveCoreAnalyticsInstance(core) {
140
233
  if (typeof core.getAnalyticsInstance !== "function") return void 0;
@@ -191,6 +284,6 @@ function forms(options = {}) {
191
284
  };
192
285
  }
193
286
  //#endregion
194
- export { forms, getRegisteredFormsClient, registerFormsClient, useForm, useFormErrors, useFormField };
287
+ export { forms, getRegisteredFormsClient, registerFormsClient, useForm, useFormErrors, useFormField, useFormFileUpload };
195
288
 
196
289
  //# sourceMappingURL=react.js.map
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../src/react/use-form-store.ts","../src/react/forms-registry.ts","../src/react/use-forms.ts","../src/react/use-form.ts","../src/react/use-form-errors.ts","../src/react/use-form-field.ts","../src/react/resolve-core-analytics.ts","../src/react/register-forms-client.ts","../src/react/forms-module.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from 'react'\n\nimport type { FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport type FormSnapshot<TSchema extends FormSchema> = Readonly<{\n values: Partial<FormValues<TSchema>>\n errors: FieldErrors<TSchema>\n}>\n\nconst EMPTY_SNAPSHOT: FormSnapshot<FormSchema> = Object.freeze({\n values: {},\n errors: {},\n})\n\nfunction createSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema>,\n): FormSnapshot<TSchema> {\n return Object.freeze({\n values: form.getAll(),\n errors: form.errors(),\n })\n}\n\ninterface CachedSnapshot<TSchema extends FormSchema> {\n readonly form: FormInstance<TSchema>\n readonly snapshot: FormSnapshot<TSchema>\n}\n\nexport function useFormSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FormSnapshot<TSchema> {\n const cachedRef = useRef<CachedSnapshot<TSchema> | null>(null)\n const emptyRef = useRef<FormSnapshot<TSchema>>(EMPTY_SNAPSHOT as FormSnapshot<TSchema>)\n\n const subscribe = useCallback(\n (listener: () => void) => {\n if (form === null) return () => undefined\n return form.subscribe(() => {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n listener()\n })\n },\n [form],\n )\n\n const getSnapshot = useCallback((): FormSnapshot<TSchema> => {\n if (form === null) {\n // * Otherwise a later A -> null -> mutate A -> A sequence would resurrect\n // * a snapshot cached before the detach, missing the mutation in between.\n cachedRef.current = null\n return emptyRef.current\n }\n // * A cached snapshot from a previous form instance must not survive a\n // * form change — recompute so switching forms without a mutation still\n // * returns the new form's values and errors.\n if (cachedRef.current === null || cachedRef.current.form !== form) {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n }\n return cachedRef.current.snapshot\n }, [form])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import type { FormSchemaMap, FormsClient } from '../core/form.js'\n\nexport const FORMS_MODULE_KEY = 'forms'\n\n/**\n * Idempotence guard for `registerFormsClient` only — React reads the client\n * from provider context, not from here.\n */\nexport const formsByCore = new WeakMap<object, FormsClient<FormSchemaMap>>()\n\nexport function getRegisteredFormsClient(core: object): FormsClient<FormSchemaMap> | undefined {\n return formsByCore.get(core)\n}\n","import { useEmbeddablesModule } from '@embeddables/core/react'\n\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\n\nimport type { FormSchemaMap, FormsClient, InitFormsOptions } from '../core/form.js'\n\nexport type FormsReactOptions<TSchemas extends FormSchemaMap = FormSchemaMap> = Omit<\n InitFormsOptions<TSchemas>,\n 'core'\n>\n\n/** @internal Product hooks read the module client from provider context. */\nexport function useRegisteredFormsClient<\n TSchemas extends FormSchemaMap = FormSchemaMap,\n>(): FormsClient<TSchemas> | null {\n return useEmbeddablesModule<FormsClient<TSchemas>>({ key: FORMS_MODULE_KEY })\n}\n","import { useFormSnapshot } from './use-form-store.js'\nimport { useRegisteredFormsClient } from './use-forms.js'\n\nimport type { FormInstance, FormSchemaMap } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\n/**\n * Reactive binding for one declared form.\n *\n * Takes no type arguments: `TFormId` is inferred from `formId`, and the schema\n * map comes from the registry `em build` augments. Pass both explicitly\n * (`useForm<'signup', OtherSchemas>`) only to work against a map other than the\n * registered one.\n */\nexport function useForm<\n TFormId extends keyof TSchemas & string,\n TSchemas extends FormSchemaMap = RegisteredSchemas,\n>({\n formId,\n}: {\n formId: TFormId\n}): {\n form: FormInstance<TSchemas[TFormId]> | null\n values: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['values']\n errors: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['errors']\n} {\n const client = useRegisteredFormsClient<TSchemas>()\n\n // * Safe to call on every render: the client returns one instance per form id.\n const form = client === null ? null : client.getForm({ formId })\n const { values, errors } = useFormSnapshot(form)\n\n return { form, values, errors }\n}\n","import { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormSchema } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport function useFormErrors<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FieldErrors<TSchema> {\n const { errors } = useFormSnapshot(form)\n return errors\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nimport { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormFieldKey, FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance, SetResult } from '../core/form.js'\n\nconst noopSetValue = async (): Promise<SetResult<FormSchema>> => ({\n ok: false,\n errors: {},\n})\n\nexport function useFormField<const TSchema extends FormSchema, K extends FormFieldKey<TSchema>>({\n form,\n key,\n}: {\n form: FormInstance<TSchema> | null\n key: K\n}): {\n value: FormValues<TSchema>[K] | undefined\n error: readonly string[] | undefined\n setValue: (value: FormValues<TSchema>[K] | undefined) => void\n commit: (value: FormValues<TSchema>[K] | undefined) => Promise<SetResult<TSchema>>\n onBlur: () => Promise<SetResult<TSchema>>\n} {\n const { values, errors } = useFormSnapshot(form)\n const committed = values[key]\n const [draft, setDraft] = useState<FormValues<TSchema>[K] | undefined>(committed)\n\n useEffect(() => {\n setDraft(committed)\n }, [form, key, committed])\n\n const setValue = useCallback((value: FormValues<TSchema>[K] | undefined) => {\n setDraft(value)\n }, [])\n\n // * Takes the value as an argument rather than reading `draft`, so it is\n // * correct when called in the same tick as the change that produced it.\n // * `onBlur` cannot be: it compares the `draft`/`committed` pair captured in\n // * the current render, which a same-tick `setValue` has not updated yet.\n const commit = useCallback(\n (value: FormValues<TSchema>[K] | undefined): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n // * Keeps the control responsive while `set` runs, and keeps a rejected\n // * value on screen next to its error instead of snapping back.\n setDraft(value)\n return form.set({ [key]: value } as Partial<FormValues<TSchema>>)\n },\n [form, key],\n )\n\n const onBlur = useCallback(async (): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n if (draft === committed) {\n return { ok: true, errors: {} as FieldErrors<TSchema> }\n }\n return form.set({ [key]: draft } as Partial<FormValues<TSchema>>)\n }, [committed, draft, form, key])\n\n if (form === null) {\n return {\n value: undefined,\n error: undefined,\n setValue: () => undefined,\n commit: async () => noopSetValue(),\n onBlur: async () => noopSetValue(),\n }\n }\n\n return {\n value: draft,\n error: errors[key],\n setValue,\n commit,\n onBlur,\n }\n}\n","import type { AnalyticsInstance } from '@embeddables/core'\nimport type { EmbeddablesInstance } from '@embeddables/core'\n\nexport function resolveCoreAnalyticsInstance(\n core: EmbeddablesInstance,\n): AnalyticsInstance | undefined {\n if (typeof core.getAnalyticsInstance !== 'function') return undefined\n return core.getAnalyticsInstance() ?? undefined\n}\n","import { initForms } from '../core/form.js'\nimport { formsByCore } from './forms-registry.js'\nimport { resolveCoreAnalyticsInstance } from './resolve-core-analytics.js'\n\nimport type { FormsClient, InitFormsOptions } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\ninterface RegisterFormsModuleClientOptions extends InitFormsOptions<RegisteredSchemas> {\n /**\n * Set when `excludeAnalyticsInModules` names Forms. The exclusion is absolute:\n * it suppresses the Core-instance fallback as well as the injected client.\n */\n disableAnalyticsFallback?: boolean\n}\n\nfunction register({\n disableAnalyticsFallback,\n ...options\n}: RegisterFormsModuleClientOptions): FormsClient<RegisteredSchemas> {\n const { core } = options\n const existing = formsByCore.get(core)\n if (existing !== undefined) return existing\n\n const analyticsInstance = disableAnalyticsFallback\n ? undefined\n : (options.analyticsInstance ?? resolveCoreAnalyticsInstance(core))\n\n const client = initForms<RegisteredSchemas>({ ...options, core, analyticsInstance })\n formsByCore.set(core, client)\n return client\n}\n\nexport function registerFormsClient(\n options: InitFormsOptions<RegisteredSchemas>,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n\nexport function registerFormsModuleClient(\n options: RegisterFormsModuleClientOptions,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n","import type { EmbeddablesReactModule } from '@embeddables/core/react'\n\nimport { FormsError } from '../errors.js'\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\nimport { registerFormsModuleClient } from './register-forms-client.js'\n\nimport type { AnalyticsInstance } from '../core/analytics.js'\nimport type { FormsClient } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\nimport type { FormsReactOptions } from './use-forms.js'\n\nexport type { FormsReactOptions } from './use-forms.js'\n\n/**\n * What `EmbeddablesProvider` accepts under its top-level `forms` prop.\n *\n * `analyticsInstance` is deliberately absent: the provider injects the\n * Analytics module client through module dependencies, so an app never wires\n * that instance by hand.\n */\nexport type FormsProviderOptions = Omit<FormsReactOptions<RegisteredSchemas>, 'analyticsInstance'>\n\ndeclare module '@embeddables/core/react' {\n interface EmbeddablesReactModuleParameters {\n readonly forms: FormsProviderOptions\n }\n}\n\nconst ANALYTICS_MODULE_KEY = 'analytics'\n\nfunction resolveInjectedAnalytics(value: unknown): AnalyticsInstance | undefined {\n if (value === undefined) return undefined\n if (typeof value !== 'object' || value === null) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n const candidate = value as Partial<AnalyticsInstance>\n if (\n typeof candidate.trackEvent !== 'function' ||\n typeof candidate.getAppUserId !== 'function' ||\n typeof candidate.getProjectId !== 'function'\n ) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n return candidate as AnalyticsInstance\n}\n\nexport function forms(\n options: FormsReactOptions<RegisteredSchemas> = {},\n): EmbeddablesReactModule<FormsClient<RegisteredSchemas>, FormsProviderOptions> {\n return {\n key: FORMS_MODULE_KEY,\n dependencies: [{ key: ANALYTICS_MODULE_KEY, optional: true }],\n init: (core, context) => {\n const analyticsInstance = context?.analyticsExcluded\n ? undefined\n : (options.analyticsInstance ??\n resolveInjectedAnalytics(context?.dependencies.get(ANALYTICS_MODULE_KEY)))\n\n return registerFormsModuleClient({\n core,\n customValidations: context?.parameters?.customValidations ?? options.customValidations,\n serverFormData: context?.parameters?.serverFormData ?? options.serverFormData,\n analyticsInstance,\n disableAnalyticsFallback: context?.analyticsExcluded,\n })\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/react/use-form-store.ts","../src/react/forms-registry.ts","../src/react/use-forms.ts","../src/react/use-form.ts","../src/react/use-form-errors.ts","../src/react/use-form-field.ts","../src/react/use-form-file-upload.ts","../src/react/resolve-core-analytics.ts","../src/react/register-forms-client.ts","../src/react/forms-module.ts"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from 'react'\n\nimport type { FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport type FormSnapshot<TSchema extends FormSchema> = Readonly<{\n values: Partial<FormValues<TSchema>>\n errors: FieldErrors<TSchema>\n}>\n\nconst EMPTY_SNAPSHOT: FormSnapshot<FormSchema> = Object.freeze({\n values: {},\n errors: {},\n})\n\nfunction createSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema>,\n): FormSnapshot<TSchema> {\n return Object.freeze({\n values: form.getAll(),\n errors: form.errors(),\n })\n}\n\ninterface CachedSnapshot<TSchema extends FormSchema> {\n readonly form: FormInstance<TSchema>\n readonly snapshot: FormSnapshot<TSchema>\n}\n\nexport function useFormSnapshot<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FormSnapshot<TSchema> {\n const cachedRef = useRef<CachedSnapshot<TSchema> | null>(null)\n const emptyRef = useRef<FormSnapshot<TSchema>>(EMPTY_SNAPSHOT as FormSnapshot<TSchema>)\n\n const subscribe = useCallback(\n (listener: () => void) => {\n if (form === null) return () => undefined\n return form.subscribe(() => {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n listener()\n })\n },\n [form],\n )\n\n const getSnapshot = useCallback((): FormSnapshot<TSchema> => {\n if (form === null) {\n // * Otherwise a later A -> null -> mutate A -> A sequence would resurrect\n // * a snapshot cached before the detach, missing the mutation in between.\n cachedRef.current = null\n return emptyRef.current\n }\n // * A cached snapshot from a previous form instance must not survive a\n // * form change — recompute so switching forms without a mutation still\n // * returns the new form's values and errors.\n if (cachedRef.current === null || cachedRef.current.form !== form) {\n cachedRef.current = { form, snapshot: createSnapshot(form) }\n }\n return cachedRef.current.snapshot\n }, [form])\n\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot)\n}\n","import type { FormSchemaMap, FormsClient } from '../core/form.js'\n\nexport const FORMS_MODULE_KEY = 'forms'\n\n/**\n * Idempotence guard for `registerFormsClient` only — React reads the client\n * from provider context, not from here.\n */\nexport const formsByCore = new WeakMap<object, FormsClient<FormSchemaMap>>()\n\nexport function getRegisteredFormsClient(core: object): FormsClient<FormSchemaMap> | undefined {\n return formsByCore.get(core)\n}\n","import { useEmbeddablesModule } from '@embeddables/core/react'\n\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\n\nimport type { FormSchemaMap, FormsClient, InitFormsOptions } from '../core/form.js'\n\nexport type FormsReactOptions<TSchemas extends FormSchemaMap = FormSchemaMap> = Omit<\n InitFormsOptions<TSchemas>,\n 'core'\n>\n\n/** @internal Product hooks read the module client from provider context. */\nexport function useRegisteredFormsClient<\n TSchemas extends FormSchemaMap = FormSchemaMap,\n>(): FormsClient<TSchemas> | null {\n return useEmbeddablesModule<FormsClient<TSchemas>>({ key: FORMS_MODULE_KEY })\n}\n","import { useFormSnapshot } from './use-form-store.js'\nimport { useRegisteredFormsClient } from './use-forms.js'\n\nimport type { FormInstance, FormSchemaMap } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\n/**\n * Reactive binding for one declared form.\n *\n * Takes no type arguments: `TFormId` is inferred from `formId`, and the schema\n * map comes from the registry `em build` augments. Pass both explicitly\n * (`useForm<'signup', OtherSchemas>`) only to work against a map other than the\n * registered one.\n */\nexport function useForm<\n TFormId extends keyof TSchemas & string,\n TSchemas extends FormSchemaMap = RegisteredSchemas,\n>({\n formId,\n}: {\n formId: TFormId\n}): {\n form: FormInstance<TSchemas[TFormId]> | null\n values: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['values']\n errors: ReturnType<typeof useFormSnapshot<TSchemas[TFormId]>>['errors']\n} {\n const client = useRegisteredFormsClient<TSchemas>()\n\n // * Safe to call on every render: the client returns one instance per form id.\n const form = client === null ? null : client.getForm({ formId })\n const { values, errors } = useFormSnapshot(form)\n\n return { form, values, errors }\n}\n","import { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormSchema } from '../core/config.js'\nimport type { FieldErrors, FormInstance } from '../core/form.js'\n\nexport function useFormErrors<TSchema extends FormSchema>(\n form: FormInstance<TSchema> | null,\n): FieldErrors<TSchema> {\n const { errors } = useFormSnapshot(form)\n return errors\n}\n","import { useCallback, useEffect, useState } from 'react'\n\nimport { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormFieldKey, FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance, SetResult } from '../core/form.js'\n\nconst noopSetValue = async (): Promise<SetResult<FormSchema>> => ({\n ok: false,\n errors: {},\n})\n\nexport function useFormField<const TSchema extends FormSchema, K extends FormFieldKey<TSchema>>({\n form,\n key,\n}: {\n form: FormInstance<TSchema> | null\n key: K\n}): {\n value: FormValues<TSchema>[K] | undefined\n error: readonly string[] | undefined\n setValue: (value: FormValues<TSchema>[K] | undefined) => void\n commit: (value: FormValues<TSchema>[K] | undefined) => Promise<SetResult<TSchema>>\n onBlur: () => Promise<SetResult<TSchema>>\n} {\n const { values, errors } = useFormSnapshot(form)\n const committed = values[key]\n const [draft, setDraft] = useState<FormValues<TSchema>[K] | undefined>(committed)\n\n useEffect(() => {\n setDraft(committed)\n }, [form, key, committed])\n\n const setValue = useCallback((value: FormValues<TSchema>[K] | undefined) => {\n setDraft(value)\n }, [])\n\n // * Takes the value as an argument rather than reading `draft`, so it is\n // * correct when called in the same tick as the change that produced it.\n // * `onBlur` cannot be: it compares the `draft`/`committed` pair captured in\n // * the current render, which a same-tick `setValue` has not updated yet.\n const commit = useCallback(\n (value: FormValues<TSchema>[K] | undefined): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n // * Keeps the control responsive while `set` runs, and keeps a rejected\n // * value on screen next to its error instead of snapping back.\n setDraft(value)\n return form.set({ [key]: value } as Partial<FormValues<TSchema>>)\n },\n [form, key],\n )\n\n const onBlur = useCallback(async (): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetValue()\n if (draft === committed) {\n return { ok: true, errors: {} as FieldErrors<TSchema> }\n }\n return form.set({ [key]: draft } as Partial<FormValues<TSchema>>)\n }, [committed, draft, form, key])\n\n if (form === null) {\n return {\n value: undefined,\n error: undefined,\n setValue: () => undefined,\n commit: async () => noopSetValue(),\n onBlur: async () => noopSetValue(),\n }\n }\n\n return {\n value: draft,\n error: errors[key],\n setValue,\n commit,\n onBlur,\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\n\nimport { FormsError } from '../errors.js'\nimport { useFormSnapshot } from './use-form-store.js'\n\nimport type { FormSchema, FormValues } from '../core/config.js'\nimport type { FieldErrors, FormInstance, SetResult } from '../core/form.js'\nimport type { ChangeEvent } from 'react'\n\n/** Keys declared with `value_type: file` on a schema. */\nexport type FormFileFieldKey<TSchema extends FormSchema> = Extract<\n TSchema['fields'][number],\n { value_type: 'file' }\n>['key']\n\nconst noopSetResult = async <TSchema extends FormSchema>(): Promise<SetResult<TSchema>> => ({\n ok: false,\n errors: {} as FieldErrors<TSchema>,\n})\n\n/**\n * Reactive binding for a `type: file` field: uploads through the public API,\n * commits the returned `FormFileRef`, and exposes a native `<input type=\"file\">`\n * handler.\n */\nexport function useFormFileUpload<\n const TSchema extends FormSchema,\n K extends FormFileFieldKey<TSchema>,\n>({\n form,\n key,\n}: {\n form: FormInstance<TSchema> | null\n key: K\n}): {\n value: FormValues<TSchema>[K] | undefined\n error: readonly string[] | undefined\n isLoading: boolean\n uploadError: string | undefined\n upload: (file: File) => Promise<SetResult<TSchema>>\n clear: () => Promise<SetResult<TSchema>>\n inputProps: {\n type: 'file'\n disabled: boolean\n onChange: (event: ChangeEvent<HTMLInputElement>) => void\n }\n} {\n const { values, errors } = useFormSnapshot(form)\n const [isLoading, setIsLoading] = useState(false)\n const [uploadError, setUploadError] = useState<string | undefined>(undefined)\n const uploadGenerationRef = useRef(0)\n\n useEffect(() => {\n return () => {\n uploadGenerationRef.current += 1\n setIsLoading(false)\n setUploadError(undefined)\n }\n }, [form, key])\n\n const upload = useCallback(\n async (file: File): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetResult<TSchema>()\n\n const generation = ++uploadGenerationRef.current\n setIsLoading(true)\n setUploadError(undefined)\n try {\n const ref = await form.uploadFile({ key, file })\n if (generation !== uploadGenerationRef.current) {\n return { ok: false, errors: {} as FieldErrors<TSchema> }\n }\n return await form.set({ [key]: ref } as Partial<FormValues<TSchema>>)\n } catch (error) {\n if (generation !== uploadGenerationRef.current) {\n return { ok: false, errors: {} as FieldErrors<TSchema> }\n }\n const message = error instanceof FormsError ? error.message : 'File upload failed.'\n setUploadError(message)\n return { ok: false, errors: {} as FieldErrors<TSchema> }\n } finally {\n if (generation === uploadGenerationRef.current) {\n setIsLoading(false)\n }\n }\n },\n [form, key],\n )\n\n const clear = useCallback(async (): Promise<SetResult<TSchema>> => {\n if (form === null) return noopSetResult<TSchema>()\n uploadGenerationRef.current += 1\n setIsLoading(false)\n setUploadError(undefined)\n return form.set({ [key]: null } as Partial<FormValues<TSchema>>)\n }, [form, key])\n\n const onChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0]\n if (file === undefined) return\n void upload(file)\n // * Lets the user pick the same file again after a failed upload.\n event.target.value = ''\n },\n [upload],\n )\n\n if (form === null) {\n return {\n value: undefined,\n error: undefined,\n isLoading: false,\n uploadError: undefined,\n upload: async () => noopSetResult<TSchema>(),\n clear: async () => noopSetResult<TSchema>(),\n inputProps: {\n type: 'file',\n disabled: true,\n onChange: () => undefined,\n },\n }\n }\n\n return {\n value: values[key],\n error: errors[key],\n isLoading,\n uploadError,\n upload,\n clear,\n inputProps: {\n type: 'file',\n disabled: isLoading,\n onChange,\n },\n }\n}\n","import type { AnalyticsInstance } from '@embeddables/core'\nimport type { EmbeddablesInstance } from '@embeddables/core'\n\nexport function resolveCoreAnalyticsInstance(\n core: EmbeddablesInstance,\n): AnalyticsInstance | undefined {\n if (typeof core.getAnalyticsInstance !== 'function') return undefined\n return core.getAnalyticsInstance() ?? undefined\n}\n","import { initForms } from '../core/form.js'\nimport { formsByCore } from './forms-registry.js'\nimport { resolveCoreAnalyticsInstance } from './resolve-core-analytics.js'\n\nimport type { FormsClient, InitFormsOptions } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\n\ninterface RegisterFormsModuleClientOptions extends InitFormsOptions<RegisteredSchemas> {\n /**\n * Set when `excludeAnalyticsInModules` names Forms. The exclusion is absolute:\n * it suppresses the Core-instance fallback as well as the injected client.\n */\n disableAnalyticsFallback?: boolean\n}\n\nfunction register({\n disableAnalyticsFallback,\n ...options\n}: RegisterFormsModuleClientOptions): FormsClient<RegisteredSchemas> {\n const { core } = options\n const existing = formsByCore.get(core)\n if (existing !== undefined) return existing\n\n const analyticsInstance = disableAnalyticsFallback\n ? undefined\n : (options.analyticsInstance ?? resolveCoreAnalyticsInstance(core))\n\n const client = initForms<RegisteredSchemas>({ ...options, core, analyticsInstance })\n formsByCore.set(core, client)\n return client\n}\n\nexport function registerFormsClient(\n options: InitFormsOptions<RegisteredSchemas>,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n\nexport function registerFormsModuleClient(\n options: RegisterFormsModuleClientOptions,\n): FormsClient<RegisteredSchemas> {\n return register(options)\n}\n","import type { EmbeddablesReactModule } from '@embeddables/core/react'\n\nimport { FormsError } from '../errors.js'\nimport { FORMS_MODULE_KEY } from './forms-registry.js'\nimport { registerFormsModuleClient } from './register-forms-client.js'\n\nimport type { AnalyticsInstance } from '../core/analytics.js'\nimport type { FormsClient } from '../core/form.js'\nimport type { RegisteredSchemas } from './schema-registry.js'\nimport type { FormsReactOptions } from './use-forms.js'\n\nexport type { FormsReactOptions } from './use-forms.js'\n\n/**\n * What `EmbeddablesProvider` accepts under its top-level `forms` prop.\n *\n * `analyticsInstance` is deliberately absent: the provider injects the\n * Analytics module client through module dependencies, so an app never wires\n * that instance by hand.\n */\nexport type FormsProviderOptions = Omit<FormsReactOptions<RegisteredSchemas>, 'analyticsInstance'>\n\ndeclare module '@embeddables/core/react' {\n interface EmbeddablesReactModuleParameters {\n readonly forms: FormsProviderOptions\n }\n}\n\nconst ANALYTICS_MODULE_KEY = 'analytics'\n\nfunction resolveInjectedAnalytics(value: unknown): AnalyticsInstance | undefined {\n if (value === undefined) return undefined\n if (typeof value !== 'object' || value === null) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n const candidate = value as Partial<AnalyticsInstance>\n if (\n typeof candidate.trackEvent !== 'function' ||\n typeof candidate.getAppUserId !== 'function' ||\n typeof candidate.getProjectId !== 'function'\n ) {\n throw new FormsError('Forms received an invalid Analytics module dependency.')\n }\n return candidate as AnalyticsInstance\n}\n\nexport function forms(\n options: FormsReactOptions<RegisteredSchemas> = {},\n): EmbeddablesReactModule<FormsClient<RegisteredSchemas>, FormsProviderOptions> {\n return {\n key: FORMS_MODULE_KEY,\n dependencies: [{ key: ANALYTICS_MODULE_KEY, optional: true }],\n init: (core, context) => {\n const analyticsInstance = context?.analyticsExcluded\n ? undefined\n : (options.analyticsInstance ??\n resolveInjectedAnalytics(context?.dependencies.get(ANALYTICS_MODULE_KEY)))\n\n return registerFormsModuleClient({\n core,\n customValidations: context?.parameters?.customValidations ?? options.customValidations,\n serverFormData: context?.parameters?.serverFormData ?? options.serverFormData,\n analyticsInstance,\n disableAnalyticsFallback: context?.analyticsExcluded,\n })\n },\n }\n}\n"],"mappings":";;;;AAUA,MAAM,iBAA2C,OAAO,OAAO;CAC7D,QAAQ,CAAC;CACT,QAAQ,CAAC;AACX,CAAC;AAED,SAAS,eACP,MACuB;CACvB,OAAO,OAAO,OAAO;EACnB,QAAQ,KAAK,OAAO;EACpB,QAAQ,KAAK,OAAO;CACtB,CAAC;AACH;AAOA,SAAgB,gBACd,MACuB;CACvB,MAAM,YAAY,OAAuC,IAAI;CAC7D,MAAM,WAAW,OAA8B,cAAuC;CAEtF,MAAM,YAAY,aACf,aAAyB;EACxB,IAAI,SAAS,MAAM,aAAa,KAAA;EAChC,OAAO,KAAK,gBAAgB;GAC1B,UAAU,UAAU;IAAE;IAAM,UAAU,eAAe,IAAI;GAAE;GAC3D,SAAS;EACX,CAAC;CACH,GACA,CAAC,IAAI,CACP;CAEA,MAAM,cAAc,kBAAyC;EAC3D,IAAI,SAAS,MAAM;GAGjB,UAAU,UAAU;GACpB,OAAO,SAAS;EAClB;EAIA,IAAI,UAAU,YAAY,QAAQ,UAAU,QAAQ,SAAS,MAC3D,UAAU,UAAU;GAAE;GAAM,UAAU,eAAe,IAAI;EAAE;EAE7D,OAAO,UAAU,QAAQ;CAC3B,GAAG,CAAC,IAAI,CAAC;CAET,OAAO,qBAAqB,WAAW,aAAa,WAAW;AACjE;;;AC7DA,MAAa,mBAAmB;;;;;AAMhC,MAAa,8BAAc,IAAI,QAA4C;AAE3E,SAAgB,yBAAyB,MAAsD;CAC7F,OAAO,YAAY,IAAI,IAAI;AAC7B;;;;ACAA,SAAgB,2BAEkB;CAChC,OAAO,qBAA4C,EAAE,KAAK,iBAAiB,CAAC;AAC9E;;;;;;;;;;;ACFA,SAAgB,QAGd,EACA,UAOA;CACA,MAAM,SAAS,yBAAmC;CAGlD,MAAM,OAAO,WAAW,OAAO,OAAO,OAAO,QAAQ,EAAE,OAAO,CAAC;CAC/D,MAAM,EAAE,QAAQ,WAAW,gBAAgB,IAAI;CAE/C,OAAO;EAAE;EAAM;EAAQ;CAAO;AAChC;;;AC5BA,SAAgB,cACd,MACsB;CACtB,MAAM,EAAE,WAAW,gBAAgB,IAAI;CACvC,OAAO;AACT;;;ACHA,MAAM,eAAe,aAA6C;CAChE,IAAI;CACJ,QAAQ,CAAC;AACX;AAEA,SAAgB,aAAgF,EAC9F,MACA,OAUA;CACA,MAAM,EAAE,QAAQ,WAAW,gBAAgB,IAAI;CAC/C,MAAM,YAAY,OAAO;CACzB,MAAM,CAAC,OAAO,YAAY,SAA6C,SAAS;CAEhF,gBAAgB;EACd,SAAS,SAAS;CACpB,GAAG;EAAC;EAAM;EAAK;CAAS,CAAC;CAEzB,MAAM,WAAW,aAAa,UAA8C;EAC1E,SAAS,KAAK;CAChB,GAAG,CAAC,CAAC;CAML,MAAM,SAAS,aACZ,UAA2E;EAC1E,IAAI,SAAS,MAAM,OAAO,aAAa;EAGvC,SAAS,KAAK;EACd,OAAO,KAAK,IAAI,GAAG,MAAM,MAAM,CAAiC;CAClE,GACA,CAAC,MAAM,GAAG,CACZ;CAEA,MAAM,SAAS,YAAY,YAAyC;EAClE,IAAI,SAAS,MAAM,OAAO,aAAa;EACvC,IAAI,UAAU,WACZ,OAAO;GAAE,IAAI;GAAM,QAAQ,CAAC;EAA0B;EAExD,OAAO,KAAK,IAAI,GAAG,MAAM,MAAM,CAAiC;CAClE,GAAG;EAAC;EAAW;EAAO;EAAM;CAAG,CAAC;CAEhC,IAAI,SAAS,MACX,OAAO;EACL,OAAO,KAAA;EACP,OAAO,KAAA;EACP,gBAAgB,KAAA;EAChB,QAAQ,YAAY,aAAa;EACjC,QAAQ,YAAY,aAAa;CACnC;CAGF,OAAO;EACL,OAAO;EACP,OAAO,OAAO;EACd;EACA;EACA;CACF;AACF;;;AC9DA,MAAM,gBAAgB,aAAsE;CAC1F,IAAI;CACJ,QAAQ,CAAC;AACX;;;;;;AAOA,SAAgB,kBAGd,EACA,MACA,OAgBA;CACA,MAAM,EAAE,QAAQ,WAAW,gBAAgB,IAAI;CAC/C,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,CAAC,aAAa,kBAAkB,SAA6B,KAAA,CAAS;CAC5E,MAAM,sBAAsB,OAAO,CAAC;CAEpC,gBAAgB;EACd,aAAa;GACX,oBAAoB,WAAW;GAC/B,aAAa,KAAK;GAClB,eAAe,KAAA,CAAS;EAC1B;CACF,GAAG,CAAC,MAAM,GAAG,CAAC;CAEd,MAAM,SAAS,YACb,OAAO,SAA4C;EACjD,IAAI,SAAS,MAAM,OAAO,cAAuB;EAEjD,MAAM,aAAa,EAAE,oBAAoB;EACzC,aAAa,IAAI;EACjB,eAAe,KAAA,CAAS;EACxB,IAAI;GACF,MAAM,MAAM,MAAM,KAAK,WAAW;IAAE;IAAK;GAAK,CAAC;GAC/C,IAAI,eAAe,oBAAoB,SACrC,OAAO;IAAE,IAAI;IAAO,QAAQ,CAAC;GAA0B;GAEzD,OAAO,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAiC;EACtE,SAAS,OAAO;GACd,IAAI,eAAe,oBAAoB,SACrC,OAAO;IAAE,IAAI;IAAO,QAAQ,CAAC;GAA0B;GAEzD,MAAM,UAAU,iBAAiB,aAAa,MAAM,UAAU;GAC9D,eAAe,OAAO;GACtB,OAAO;IAAE,IAAI;IAAO,QAAQ,CAAC;GAA0B;EACzD,UAAU;GACR,IAAI,eAAe,oBAAoB,SACrC,aAAa,KAAK;EAEtB;CACF,GACA,CAAC,MAAM,GAAG,CACZ;CAEA,MAAM,QAAQ,YAAY,YAAyC;EACjE,IAAI,SAAS,MAAM,OAAO,cAAuB;EACjD,oBAAoB,WAAW;EAC/B,aAAa,KAAK;EAClB,eAAe,KAAA,CAAS;EACxB,OAAO,KAAK,IAAI,GAAG,MAAM,KAAK,CAAiC;CACjE,GAAG,CAAC,MAAM,GAAG,CAAC;CAEd,MAAM,WAAW,aACd,UAAyC;EACxC,MAAM,OAAO,MAAM,OAAO,QAAQ;EAClC,IAAI,SAAS,KAAA,GAAW;EACxB,OAAY,IAAI;EAEhB,MAAM,OAAO,QAAQ;CACvB,GACA,CAAC,MAAM,CACT;CAEA,IAAI,SAAS,MACX,OAAO;EACL,OAAO,KAAA;EACP,OAAO,KAAA;EACP,WAAW;EACX,aAAa,KAAA;EACb,QAAQ,YAAY,cAAuB;EAC3C,OAAO,YAAY,cAAuB;EAC1C,YAAY;GACV,MAAM;GACN,UAAU;GACV,gBAAgB,KAAA;EAClB;CACF;CAGF,OAAO;EACL,OAAO,OAAO;EACd,OAAO,OAAO;EACd;EACA;EACA;EACA;EACA,YAAY;GACV,MAAM;GACN,UAAU;GACV;EACF;CACF;AACF;;;ACtIA,SAAgB,6BACd,MAC+B;CAC/B,IAAI,OAAO,KAAK,yBAAyB,YAAY,OAAO,KAAA;CAC5D,OAAO,KAAK,qBAAqB,KAAK,KAAA;AACxC;;;ACOA,SAAS,SAAS,EAChB,0BACA,GAAG,WACgE;CACnE,MAAM,EAAE,SAAS;CACjB,MAAM,WAAW,YAAY,IAAI,IAAI;CACrC,IAAI,aAAa,KAAA,GAAW,OAAO;CAEnC,MAAM,oBAAoB,2BACtB,KAAA,IACC,QAAQ,qBAAqB,6BAA6B,IAAI;CAEnE,MAAM,SAAS,UAA6B;EAAE,GAAG;EAAS;EAAM;CAAkB,CAAC;CACnF,YAAY,IAAI,MAAM,MAAM;CAC5B,OAAO;AACT;AAEA,SAAgB,oBACd,SACgC;CAChC,OAAO,SAAS,OAAO;AACzB;AAEA,SAAgB,0BACd,SACgC;CAChC,OAAO,SAAS,OAAO;AACzB;;;ACdA,MAAM,uBAAuB;AAE7B,SAAS,yBAAyB,OAA+C;CAC/E,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,MAAM,IAAI,WAAW,wDAAwD;CAE/E,MAAM,YAAY;CAClB,IACE,OAAO,UAAU,eAAe,cAChC,OAAO,UAAU,iBAAiB,cAClC,OAAO,UAAU,iBAAiB,YAElC,MAAM,IAAI,WAAW,wDAAwD;CAE/E,OAAO;AACT;AAEA,SAAgB,MACd,UAAgD,CAAC,GAC6B;CAC9E,OAAO;EACL,KAAK;EACL,cAAc,CAAC;GAAE,KAAK;GAAsB,UAAU;EAAK,CAAC;EAC5D,OAAO,MAAM,YAAY;GACvB,MAAM,oBAAoB,SAAS,oBAC/B,KAAA,IACC,QAAQ,qBACT,yBAAyB,SAAS,aAAa,IAAI,oBAAoB,CAAC;GAE5E,OAAO,0BAA0B;IAC/B;IACA,mBAAmB,SAAS,YAAY,qBAAqB,QAAQ;IACrE,gBAAgB,SAAS,YAAY,kBAAkB,QAAQ;IAC/D;IACA,0BAA0B,SAAS;GACrC,CAAC;EACH;CACF;AACF"}
package/dist/server.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_form = require("./form-BOHdxeuO.cjs");
2
+ const require_form = require("./form-lmr-O7j7.cjs");
3
3
  //#region src/core/server.ts
4
4
  function toServerFormInstance(instance) {
5
5
  return {
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as FormSchemaMap, c as FormsServerInitOptions, d as ServerFormInstance, u as ServerFormDataByFormId } from "./form-Br23yPDS.js";
1
+ import { a as FormSchemaMap, c as FormsServerInitOptions, d as ServerFormInstance, u as ServerFormDataByFormId } from "./form-DKPfOrTG.js";
2
2
  //#region src/core/server.d.ts
3
3
  interface FormsServerClient<TSchemas extends FormSchemaMap = FormSchemaMap> {
4
4
  getForm<K extends keyof TSchemas & string>(params: {
package/dist/server.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as seedServerFormsStorageFromCookies, o as createMemoryFormsStorage, r as createNoopPersistence, s as FormsError, t as createFormsClient } from "./form-Bt5pwVP6.js";
1
+ import { i as seedServerFormsStorageFromCookies, o as createMemoryFormsStorage, r as createNoopPersistence, s as FormsError, t as createFormsClient } from "./form-CR5xJ_nQ.js";
2
2
  //#region src/core/server.ts
3
3
  function toServerFormInstance(instance) {
4
4
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embeddables/forms",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Schema-driven form state, local persistence, and analytics events for Embeddables funnels.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  "hono": "^4.12.25"
45
45
  },
46
46
  "peerDependencies": {
47
- "@embeddables/core": ">=0.1.0",
47
+ "@embeddables/core": ">=0.2.0",
48
48
  "react": ">=18"
49
49
  },
50
50
  "devDependencies": {
@@ -57,8 +57,8 @@
57
57
  "tsdown": "^0.22.14",
58
58
  "typescript": "~6.0.2",
59
59
  "vitest": "^4.1.9",
60
- "@embeddables/core": "0.1.0",
61
60
  "@embeddables/shared-types": "1.0.0",
61
+ "@embeddables/core": "0.2.0",
62
62
  "backend-worker": "1.0.0"
63
63
  },
64
64
  "scripts": {