attaform 0.20.2 → 0.21.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.
- package/dist/chunks/dev-key-collision-warnings.cjs +58 -0
- package/dist/chunks/dev-key-collision-warnings.cjs.map +1 -0
- package/dist/chunks/dev-key-collision-warnings.mjs +55 -0
- package/dist/chunks/dev-key-collision-warnings.mjs.map +1 -0
- package/dist/chunks/devtools.cjs +1 -1
- package/dist/chunks/devtools.mjs +1 -1
- package/dist/chunks/fingerprint.cjs +186 -0
- package/dist/chunks/fingerprint.cjs.map +1 -0
- package/dist/chunks/fingerprint.mjs +184 -0
- package/dist/chunks/fingerprint.mjs.map +1 -0
- package/dist/chunks/fingerprint2.cjs +162 -0
- package/dist/chunks/fingerprint2.cjs.map +1 -0
- package/dist/chunks/fingerprint2.mjs +160 -0
- package/dist/chunks/fingerprint2.mjs.map +1 -0
- package/dist/chunks/indexeddb.cjs +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/multi-tab-sync.cjs +367 -0
- package/dist/chunks/multi-tab-sync.cjs.map +1 -0
- package/dist/chunks/multi-tab-sync.mjs +364 -0
- package/dist/chunks/multi-tab-sync.mjs.map +1 -0
- package/dist/chunks/session-storage.cjs +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/chunks/wire-persistence.cjs +396 -0
- package/dist/chunks/wire-persistence.cjs.map +1 -0
- package/dist/chunks/wire-persistence.mjs +394 -0
- package/dist/chunks/wire-persistence.mjs.map +1 -0
- package/dist/esbuild.cjs +28 -0
- package/dist/esbuild.cjs.map +1 -0
- package/dist/esbuild.d.cts +56 -0
- package/dist/esbuild.d.mts +56 -0
- package/dist/esbuild.d.ts +56 -0
- package/dist/esbuild.mjs +26 -0
- package/dist/esbuild.mjs.map +1 -0
- package/dist/index.cjs +5 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -70
- package/dist/index.d.mts +65 -70
- package/dist/index.d.ts +65 -70
- package/dist/index.mjs +5 -5
- package/dist/nuxt.d.cts +1 -1
- package/dist/nuxt.d.mts +1 -1
- package/dist/nuxt.d.ts +1 -1
- package/dist/rollup.cjs +24 -0
- package/dist/rollup.cjs.map +1 -0
- package/dist/rollup.d.cts +35 -0
- package/dist/rollup.d.mts +35 -0
- package/dist/rollup.d.ts +35 -0
- package/dist/rollup.mjs +22 -0
- package/dist/rollup.mjs.map +1 -0
- package/dist/rspack.cjs +10 -0
- package/dist/rspack.cjs.map +1 -0
- package/dist/rspack.d.cts +40 -0
- package/dist/rspack.d.mts +40 -0
- package/dist/rspack.d.ts +40 -0
- package/dist/rspack.mjs +8 -0
- package/dist/rspack.mjs.map +1 -0
- package/dist/runtime/plugins/attaform.cjs +2 -2
- package/dist/runtime/plugins/attaform.mjs +2 -2
- package/dist/shared/{attaform.ceGEAEMk.d.ts → attaform.7lzO9pdM.d.mts} +95 -1
- package/dist/shared/{attaform.99cfHcIt.d.cts → attaform.B1nyO4ec.d.cts} +82 -30
- package/dist/shared/{attaform.99cfHcIt.d.mts → attaform.B1nyO4ec.d.mts} +82 -30
- package/dist/shared/{attaform.99cfHcIt.d.ts → attaform.B1nyO4ec.d.ts} +82 -30
- package/dist/shared/{attaform.z5j3LwJz.cjs → attaform.BA3vRDos.cjs} +3 -3
- package/dist/shared/attaform.BA3vRDos.cjs.map +1 -0
- package/dist/shared/{attaform.BXinSW2T.d.mts → attaform.BDIEq9qP.d.cts} +1 -1
- package/dist/shared/attaform.BJGA_UOS.mjs +37 -0
- package/dist/shared/attaform.BJGA_UOS.mjs.map +1 -0
- package/dist/shared/{attaform.DN5CvZrg.d.ts → attaform.BK1RE2ha.d.ts} +1 -1
- package/dist/shared/{attaform.CywE4y8x.d.cts → attaform.BQ6drorq.d.mts} +1 -1
- package/dist/shared/attaform.BRGIpZo4.cjs +26 -0
- package/dist/shared/attaform.BRGIpZo4.cjs.map +1 -0
- package/dist/shared/{attaform.CwLjUqmQ.cjs → attaform.BUszFoKq.cjs} +383 -911
- package/dist/shared/attaform.BUszFoKq.cjs.map +1 -0
- package/dist/shared/{attaform.C5aYC_T8.mjs → attaform.BnK_bfcb.mjs} +39 -392
- package/dist/shared/attaform.BnK_bfcb.mjs.map +1 -0
- package/dist/shared/{attaform.DAKrGhxc.cjs → attaform.BzvOdiSI.cjs} +101 -417
- package/dist/shared/attaform.BzvOdiSI.cjs.map +1 -0
- package/dist/shared/attaform.C3Doa9Pt.mjs +24 -0
- package/dist/shared/attaform.C3Doa9Pt.mjs.map +1 -0
- package/dist/shared/{attaform.D2SCCd4O.cjs → attaform.CEf6wYfD.cjs} +2 -2
- package/dist/shared/{attaform.D2SCCd4O.cjs.map → attaform.CEf6wYfD.cjs.map} +1 -1
- package/dist/shared/attaform.CQN9R62B.cjs +39 -0
- package/dist/shared/attaform.CQN9R62B.cjs.map +1 -0
- package/dist/shared/{attaform.sWm8B15V.d.mts → attaform.CRsXyy-Y.d.ts} +95 -1
- package/dist/shared/{attaform.Dt7dEcHk.mjs → attaform.CkjTapyq.mjs} +89 -405
- package/dist/shared/attaform.CkjTapyq.mjs.map +1 -0
- package/dist/shared/{attaform.tiWEVznj.mjs → attaform.DSqO6Db7.mjs} +372 -912
- package/dist/shared/attaform.DSqO6Db7.mjs.map +1 -0
- package/dist/shared/attaform.DuzQYscR.d.cts +41 -0
- package/dist/shared/attaform.DuzQYscR.d.mts +41 -0
- package/dist/shared/attaform.DuzQYscR.d.ts +41 -0
- package/dist/shared/{attaform.DbRgDFa7.d.cts → attaform.F8LMHHWV.d.cts} +95 -1
- package/dist/shared/attaform.LEWUFqUw.cjs +54 -0
- package/dist/shared/attaform.LEWUFqUw.cjs.map +1 -0
- package/dist/shared/{attaform.Cd4AOfwu.cjs → attaform.PnqML3xW.cjs} +68 -402
- package/dist/shared/attaform.PnqML3xW.cjs.map +1 -0
- package/dist/shared/{attaform.QG5TG8lB.mjs → attaform.Y_Mgg0Yp.mjs} +3 -3
- package/dist/shared/attaform.Y_Mgg0Yp.mjs.map +1 -0
- package/dist/shared/{attaform.B_hph5AE.cjs → attaform._rsCZy2j.cjs} +172 -20
- package/dist/shared/attaform._rsCZy2j.cjs.map +1 -0
- package/dist/shared/{attaform.CnrxbkB6.mjs → attaform.ezb5Nh2t.mjs} +2 -2
- package/dist/shared/{attaform.CnrxbkB6.mjs.map → attaform.ezb5Nh2t.mjs.map} +1 -1
- package/dist/shared/{attaform.BGk8cfw2.mjs → attaform.r3PePkDR.mjs} +172 -21
- package/dist/shared/attaform.r3PePkDR.mjs.map +1 -0
- package/dist/shared/attaform.sHkHv_98.mjs +51 -0
- package/dist/shared/attaform.sHkHv_98.mjs.map +1 -0
- package/dist/vite.cjs +9 -45
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.cts +36 -0
- package/dist/vite.d.mts +36 -0
- package/dist/vite.d.ts +36 -0
- package/dist/vite.mjs +8 -44
- package/dist/vite.mjs.map +1 -1
- package/dist/webpack.cjs +10 -0
- package/dist/webpack.cjs.map +1 -0
- package/dist/webpack.d.cts +37 -0
- package/dist/webpack.d.mts +37 -0
- package/dist/webpack.d.ts +37 -0
- package/dist/webpack.mjs +8 -0
- package/dist/webpack.mjs.map +1 -0
- package/dist/zod-v3.cjs +3 -3
- package/dist/zod-v3.d.cts +3 -3
- package/dist/zod-v3.d.mts +3 -3
- package/dist/zod-v3.d.ts +3 -3
- package/dist/zod-v3.mjs +3 -3
- package/dist/zod-v4.cjs +3 -3
- package/dist/zod-v4.d.cts +4 -4
- package/dist/zod-v4.d.mts +4 -4
- package/dist/zod-v4.d.ts +4 -4
- package/dist/zod-v4.mjs +3 -3
- package/dist/zod.cjs +8 -8
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +5 -5
- package/dist/zod.d.mts +5 -5
- package/dist/zod.d.ts +5 -5
- package/dist/zod.mjs +6 -6
- package/package.json +19 -5
- package/dist/shared/attaform.BGk8cfw2.mjs.map +0 -1
- package/dist/shared/attaform.B_hph5AE.cjs.map +0 -1
- package/dist/shared/attaform.C5aYC_T8.mjs.map +0 -1
- package/dist/shared/attaform.Cd4AOfwu.cjs.map +0 -1
- package/dist/shared/attaform.CwLjUqmQ.cjs.map +0 -1
- package/dist/shared/attaform.DAKrGhxc.cjs.map +0 -1
- package/dist/shared/attaform.Dt7dEcHk.mjs.map +0 -1
- package/dist/shared/attaform.QG5TG8lB.mjs.map +0 -1
- package/dist/shared/attaform.tiWEVznj.mjs.map +0 -1
- package/dist/shared/attaform.z5j3LwJz.cjs.map +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { W as WebpackFamilyPlugin, a as WebpackFamilyPluginOptions } from './shared/attaform.DuzQYscR.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `attaform/rspack` — Rspack plugin that rewrites `attaform/zod` imports
|
|
5
|
+
* to the single matching adapter subpath (`attaform/zod-v3` or
|
|
6
|
+
* `attaform/zod-v4`) at build time, based on the consumer's installed Zod
|
|
7
|
+
* major. Without it, Rspack ships both adapters because the unified
|
|
8
|
+
* `attaform/zod` entry imports both for runtime dispatch.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
*
|
|
12
|
+
* // rspack.config.mjs
|
|
13
|
+
* import { attaform } from 'attaform/rspack'
|
|
14
|
+
*
|
|
15
|
+
* export default {
|
|
16
|
+
* plugins: [attaform()],
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* Rspack mirrors webpack's plugin API for the resolve hook attaform taps,
|
|
20
|
+
* so this shares its body with `attaform/webpack` via
|
|
21
|
+
* `createWebpackFamilyPlugin`; only the diagnostic tag differs.
|
|
22
|
+
*
|
|
23
|
+
* This plugin only does the adapter rewrite. The Vue SFC `v-register`
|
|
24
|
+
* transforms that `attaform/vite` wires (load-bearing for SSR initial
|
|
25
|
+
* render) are `@vitejs/plugin-vue`-specific and do not transfer; a
|
|
26
|
+
* non-Vite consumer that needs them wires `attaform/transforms` into
|
|
27
|
+
* their Vue compiler separately.
|
|
28
|
+
*
|
|
29
|
+
* Zero-dep: the plugin imports nothing from `@rspack/core` (it taps the
|
|
30
|
+
* resolve hook the compiler injects at the consumer's build).
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** Options for the Rspack `attaform()` plugin. */
|
|
34
|
+
type AttaformRspackPluginOptions = WebpackFamilyPluginOptions;
|
|
35
|
+
/** The structural shape Rspack requires of the plugin. */
|
|
36
|
+
type AttaformRspackPlugin = WebpackFamilyPlugin;
|
|
37
|
+
declare function attaform(options?: AttaformRspackPluginOptions): AttaformRspackPlugin;
|
|
38
|
+
|
|
39
|
+
export { attaform };
|
|
40
|
+
export type { AttaformRspackPlugin, AttaformRspackPluginOptions };
|
package/dist/rspack.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { W as WebpackFamilyPlugin, a as WebpackFamilyPluginOptions } from './shared/attaform.DuzQYscR.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `attaform/rspack` — Rspack plugin that rewrites `attaform/zod` imports
|
|
5
|
+
* to the single matching adapter subpath (`attaform/zod-v3` or
|
|
6
|
+
* `attaform/zod-v4`) at build time, based on the consumer's installed Zod
|
|
7
|
+
* major. Without it, Rspack ships both adapters because the unified
|
|
8
|
+
* `attaform/zod` entry imports both for runtime dispatch.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
*
|
|
12
|
+
* // rspack.config.mjs
|
|
13
|
+
* import { attaform } from 'attaform/rspack'
|
|
14
|
+
*
|
|
15
|
+
* export default {
|
|
16
|
+
* plugins: [attaform()],
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* Rspack mirrors webpack's plugin API for the resolve hook attaform taps,
|
|
20
|
+
* so this shares its body with `attaform/webpack` via
|
|
21
|
+
* `createWebpackFamilyPlugin`; only the diagnostic tag differs.
|
|
22
|
+
*
|
|
23
|
+
* This plugin only does the adapter rewrite. The Vue SFC `v-register`
|
|
24
|
+
* transforms that `attaform/vite` wires (load-bearing for SSR initial
|
|
25
|
+
* render) are `@vitejs/plugin-vue`-specific and do not transfer; a
|
|
26
|
+
* non-Vite consumer that needs them wires `attaform/transforms` into
|
|
27
|
+
* their Vue compiler separately.
|
|
28
|
+
*
|
|
29
|
+
* Zero-dep: the plugin imports nothing from `@rspack/core` (it taps the
|
|
30
|
+
* resolve hook the compiler injects at the consumer's build).
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/** Options for the Rspack `attaform()` plugin. */
|
|
34
|
+
type AttaformRspackPluginOptions = WebpackFamilyPluginOptions;
|
|
35
|
+
/** The structural shape Rspack requires of the plugin. */
|
|
36
|
+
type AttaformRspackPlugin = WebpackFamilyPlugin;
|
|
37
|
+
declare function attaform(options?: AttaformRspackPluginOptions): AttaformRspackPlugin;
|
|
38
|
+
|
|
39
|
+
export { attaform };
|
|
40
|
+
export type { AttaformRspackPlugin, AttaformRspackPluginOptions };
|
package/dist/rspack.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rspack.mjs","sources":["../src/rspack.ts"],"sourcesContent":["/**\n * `attaform/rspack` — Rspack plugin that rewrites `attaform/zod` imports\n * to the single matching adapter subpath (`attaform/zod-v3` or\n * `attaform/zod-v4`) at build time, based on the consumer's installed Zod\n * major. Without it, Rspack ships both adapters because the unified\n * `attaform/zod` entry imports both for runtime dispatch.\n *\n * Usage:\n *\n * // rspack.config.mjs\n * import { attaform } from 'attaform/rspack'\n *\n * export default {\n * plugins: [attaform()],\n * }\n *\n * Rspack mirrors webpack's plugin API for the resolve hook attaform taps,\n * so this shares its body with `attaform/webpack` via\n * `createWebpackFamilyPlugin`; only the diagnostic tag differs.\n *\n * This plugin only does the adapter rewrite. The Vue SFC `v-register`\n * transforms that `attaform/vite` wires (load-bearing for SSR initial\n * render) are `@vitejs/plugin-vue`-specific and do not transfer; a\n * non-Vite consumer that needs them wires `attaform/transforms` into\n * their Vue compiler separately.\n *\n * Zero-dep: the plugin imports nothing from `@rspack/core` (it taps the\n * resolve hook the compiler injects at the consumer's build).\n */\nimport {\n createWebpackFamilyPlugin,\n type WebpackFamilyPlugin,\n type WebpackFamilyPluginOptions,\n} from './core/webpack-family-plugin'\n\n/** Options for the Rspack `attaform()` plugin. */\nexport type AttaformRspackPluginOptions = WebpackFamilyPluginOptions\n/** The structural shape Rspack requires of the plugin. */\nexport type AttaformRspackPlugin = WebpackFamilyPlugin\n\nexport function attaform(options: AttaformRspackPluginOptions = {}): AttaformRspackPlugin {\n return createWebpackFamilyPlugin('attaform/rspack', options)\n}\n"],"names":[],"mappings":";;AAwCO,SAAS,QAAA,CAAS,OAAA,GAAuC,EAAC,EAAyB;AACxF,EAAA,OAAO,yBAAA,CAA0B,mBAAmB,OAAO,CAAA;AAC7D;;;;"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const app = require('nuxt/app');
|
|
4
|
-
const devtoolsShared = require('../../shared/attaform.
|
|
5
|
-
const paths = require('../../shared/attaform.
|
|
4
|
+
const devtoolsShared = require('../../shared/attaform.CEf6wYfD.cjs');
|
|
5
|
+
const paths = require('../../shared/attaform.BA3vRDos.cjs');
|
|
6
6
|
|
|
7
7
|
var attaform_default = app.defineNuxtPlugin({
|
|
8
8
|
// `enforce: 'pre'` makes the "we run before any component's setup" claim
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineNuxtPlugin, useRuntimeConfig, useRoute } from 'nuxt/app';
|
|
2
|
-
import { r as renderAttaformState, h as hydrateAttaformState, D as DEVTOOLS_WINDOW_KEY } from '../../shared/attaform.
|
|
3
|
-
import { m as createAttaform, y as kAttaformWizardActiveStepResolver, s as getRegistryFromApp } from '../../shared/attaform.
|
|
2
|
+
import { r as renderAttaformState, h as hydrateAttaformState, D as DEVTOOLS_WINDOW_KEY } from '../../shared/attaform.ezb5Nh2t.mjs';
|
|
3
|
+
import { m as createAttaform, y as kAttaformWizardActiveStepResolver, s as getRegistryFromApp } from '../../shared/attaform.Y_Mgg0Yp.mjs';
|
|
4
4
|
|
|
5
5
|
var attaform_default = defineNuxtPlugin({
|
|
6
6
|
// `enforce: 'pre'` makes the "we run before any component's setup" claim
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { v as FormKey, V as PathKey, m as DisplayCtx, z as GetDisplayState, n as DisplayMachine, ag as SlimPrimitiveKind, C as CoercionEntry, g as CoercionRegistry, G as GenericForm, U as Path, ao as ValidationError, A as AbstractSchema, as as WriteMeta, D as DeepPartial, at as WriteShape, am as ValidateOn, _ as PersistOptInRegistry, f as AttaformDefaults, al as UseFormReturnType, aa as RegisterValue } from './attaform.B1nyO4ec.mjs';
|
|
2
2
|
import { Ref, ComputedRef, App, InjectionKey } from 'vue';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -455,6 +455,68 @@ type UseWizardReturnType<S extends ReadonlyArray<StepSlot> = ReadonlyArray<StepS
|
|
|
455
455
|
readonly reset: () => void;
|
|
456
456
|
};
|
|
457
457
|
|
|
458
|
+
/**
|
|
459
|
+
* Per-form display engine: owns the clock and the timers that the pure
|
|
460
|
+
* `getDisplayState` reducer policy needs, so the reducer itself stays a
|
|
461
|
+
* deterministic `(prev, ctx) => next` function.
|
|
462
|
+
*
|
|
463
|
+
* It keeps a `Map` of the machines that are still *active* (a spinner is
|
|
464
|
+
* showing, a verdict is being held, or a `reviewAt` deadline is pending),
|
|
465
|
+
* a single reactive `tick` ref, and a single `setTimeout` aimed at the
|
|
466
|
+
* nearest `reviewAt` across every active field. When a field-state
|
|
467
|
+
* computed reads `resolve`, it subscribes to `tick`; when the timer
|
|
468
|
+
* fires, `tick` bumps and every dependent computed re-runs the reducer,
|
|
469
|
+
* so a field whose deadline elapsed transitions (verdict → spinner, or
|
|
470
|
+
* spinner → settled verdict) without any per-field watcher.
|
|
471
|
+
*
|
|
472
|
+
* Eviction: a machine is dropped once it reaches a terminal *idle* state
|
|
473
|
+
* with no pending review. Error / success / pending machines are retained
|
|
474
|
+
* so the reducer can hold the prior verdict under the show-delay window of
|
|
475
|
+
* the *next* validation streak (no success → idle → success flicker). The
|
|
476
|
+
* retained set is bounded by the rendered non-idle fields; none of them
|
|
477
|
+
* arm a timer, so retention costs memory, never CPU.
|
|
478
|
+
*
|
|
479
|
+
* Untrusted reducer: `getDisplayState` is consumer-overridable, so the
|
|
480
|
+
* engine treats the returned `reviewAt` as untrusted. A non-finite deadline
|
|
481
|
+
* (NaN / ±Infinity from a custom predicate's bad arithmetic) is ignored
|
|
482
|
+
* rather than handed to `setTimeout`, where it coerces to 0 and spins; an
|
|
483
|
+
* over-large finite deadline is clamped below the 32-bit `setTimeout`
|
|
484
|
+
* overflow; and the timer refuses to re-arm for the exact deadline it just
|
|
485
|
+
* fired, so a predicate re-emitting a fixed or past `reviewAt` can't drive an
|
|
486
|
+
* infinite fire loop. None of these arise from the library default, which
|
|
487
|
+
* always advances its deadline or drops it.
|
|
488
|
+
*
|
|
489
|
+
* Background tabs: `setTimeout` is throttled to >= 1s while a tab is hidden,
|
|
490
|
+
* so a min-visible hold can overshoot. A `visibilitychange` listener bumps
|
|
491
|
+
* the clock on return to the foreground, so any overdue deadline resolves at
|
|
492
|
+
* once instead of lingering.
|
|
493
|
+
*
|
|
494
|
+
* SSR: no clock, no timers, no listener. With `now` frozen and nothing
|
|
495
|
+
* validating at render, the reducer returns the plain verdict (never
|
|
496
|
+
* pending) and the engine stores nothing, so the server HTML and the
|
|
497
|
+
* client's first render agree — no hydration mismatch on the display
|
|
498
|
+
* projection.
|
|
499
|
+
*/
|
|
500
|
+
type DisplayEngine = {
|
|
501
|
+
/**
|
|
502
|
+
* Resolve a path's next `DisplayMachine`. Subscribes the calling
|
|
503
|
+
* computed to the engine clock, threads the path's previous machine
|
|
504
|
+
* through `reducer`, persists or evicts the result, and re-arms the
|
|
505
|
+
* single timer to the nearest deadline.
|
|
506
|
+
*/
|
|
507
|
+
resolve(key: PathKey, ctx: DisplayCtx, reducer: GetDisplayState): DisplayMachine;
|
|
508
|
+
/** Drop every retained machine and cancel the timer (used by `reset()`). */
|
|
509
|
+
clear(): void;
|
|
510
|
+
/** Tear down for good: `clear()` plus detaching the visibility listener. */
|
|
511
|
+
dispose(): void;
|
|
512
|
+
/** Introspection for tests: count of retained machines. */
|
|
513
|
+
size(): number;
|
|
514
|
+
/** Introspection for tests: whether a path currently has a retained machine. */
|
|
515
|
+
has(key: PathKey): boolean;
|
|
516
|
+
/** Introspection for tests: whether a deadline timer is currently armed. */
|
|
517
|
+
hasTimer(): boolean;
|
|
518
|
+
};
|
|
519
|
+
|
|
458
520
|
/**
|
|
459
521
|
* Schema-driven coercion of user-typed DOM values at the v-register
|
|
460
522
|
* directive layer. When the slim schema declares a numeric or
|
|
@@ -669,6 +731,16 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
669
731
|
* read.
|
|
670
732
|
*/
|
|
671
733
|
readonly getDisplayState: GetDisplayState;
|
|
734
|
+
/**
|
|
735
|
+
* Per-form display engine: owns the clock and the single timer the timed
|
|
736
|
+
* `getDisplayState` reducer policy needs, keeping the reducer itself a
|
|
737
|
+
* pure `(prev, ctx) => next` function. The field-state computeds route
|
|
738
|
+
* every `displayState` read through `displayEngine.resolve(...)`, which
|
|
739
|
+
* threads the path's previous machine, persists or evicts the result, and
|
|
740
|
+
* re-arms the nearest-deadline timer. Constructed once at form
|
|
741
|
+
* construction; torn down via `registerCleanup` on store eviction.
|
|
742
|
+
*/
|
|
743
|
+
readonly displayEngine: DisplayEngine;
|
|
672
744
|
readonly submitting: Ref<boolean>;
|
|
673
745
|
readonly activeSubmissions: Ref<number>;
|
|
674
746
|
readonly submissionAttempts: Ref<number>;
|
|
@@ -838,6 +910,28 @@ type FormStore<F extends GenericForm, G extends GenericForm = F> = {
|
|
|
838
910
|
* computed only re-runs when the count for ITS key changes.
|
|
839
911
|
*/
|
|
840
912
|
readonly fieldValidationCounts: Map<PathKey, number>;
|
|
913
|
+
/**
|
|
914
|
+
* Per-path `Date.now()` stamp marking when the field's LATEST validation
|
|
915
|
+
* run started, re-anchored on every run start (every increment), deleted
|
|
916
|
+
* on the `→ 0` edge. The display reducer reads it as `ctx.validatingSince`
|
|
917
|
+
* to time the anti-flash spinner, which measures `now - validatingSince`:
|
|
918
|
+
* re-anchoring on each run means a burst of keystrokes (each aborting the
|
|
919
|
+
* prior run and starting a new one) keeps pushing the stamp forward, so the
|
|
920
|
+
* spinner stays suppressed until the user pauses rather than surfacing
|
|
921
|
+
* mid-typing. Anchoring only at the streak start would pin it to the first
|
|
922
|
+
* keystroke, because with `debounceMs: 0` the aborted run's decrement lands
|
|
923
|
+
* after the next run's increment and the count never returns to 0 between
|
|
924
|
+
* fast keystrokes. The field-state container walk takes the descendant-min
|
|
925
|
+
* so a row spinner anchors at its earliest still-active leaf. Runtime-only,
|
|
926
|
+
* never hydrated, like the counts. REACTIVE: the display computed reads this
|
|
927
|
+
* (as `ctx.validatingSince`) but not the `validating` flag, and a long
|
|
928
|
+
* validation that settles with an unchanged verdict (same error, still
|
|
929
|
+
* invalid) leaves `errors` / `valid` untouched — so a non-reactive map would
|
|
930
|
+
* leave a held `pending` spinner stranded after the run ends, until some
|
|
931
|
+
* unrelated reactive change happened to re-run the computed. Reactivity ties
|
|
932
|
+
* the computed to both the streak start (set) and end (delete).
|
|
933
|
+
*/
|
|
934
|
+
readonly fieldValidatingSince: Map<PathKey, number>;
|
|
841
935
|
/**
|
|
842
936
|
* Replace the form value wholesale. Optional `meta` is forwarded to
|
|
843
937
|
* every `onFormChange` listener so they can decide whether THIS write
|
|
@@ -814,6 +814,12 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
814
814
|
* Structural fingerprint of the schema. Same shape → same string;
|
|
815
815
|
* different shape → (best-effort) different string.
|
|
816
816
|
*
|
|
817
|
+
* Resolves a `Promise` so adapters can defer the structural walk (and
|
|
818
|
+
* its `canonicalStringify` helper) onto a dynamic import. The framework
|
|
819
|
+
* only ever needs the fingerprint on opt-in async paths (the multi-tab
|
|
820
|
+
* channel name, the persistence storage key) plus a dev-only mismatch
|
|
821
|
+
* warning, so none of those bytes belong on the eager `useForm` path.
|
|
822
|
+
*
|
|
817
823
|
* The library uses this to detect schema mismatches at a shared
|
|
818
824
|
* form key: two `useForm({ key: 'x', schema })` calls are allowed
|
|
819
825
|
* to land on the same `FormStore` (the "shared store" semantic),
|
|
@@ -841,7 +847,7 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
841
847
|
* look identical. The warning is a footgun catcher, not a
|
|
842
848
|
* soundness guarantee.
|
|
843
849
|
*/
|
|
844
|
-
fingerprint(): string
|
|
850
|
+
fingerprint(): Promise<string>;
|
|
845
851
|
getDefaultValues(config: GetDefaultValuesConfig<Form>): DefaultValuesResponse<Form>;
|
|
846
852
|
/**
|
|
847
853
|
* Return the schema-prescribed default value at the given path. The
|
|
@@ -2047,29 +2053,31 @@ type AttaformDefaults = {
|
|
|
2047
2053
|
* useForm({ getDisplayState }) > AttaformDefaults > library default
|
|
2048
2054
|
*
|
|
2049
2055
|
* The library default opens one timing gate, then resolves by
|
|
2050
|
-
* precedence: gate closed → `'idle'`; a run in flight →
|
|
2051
|
-
*
|
|
2052
|
-
*
|
|
2053
|
-
*
|
|
2056
|
+
* precedence: gate closed → `'idle'`; a run in flight → a delayed
|
|
2057
|
+
* `'pending'` (held briefly to smooth fast validations, then held a
|
|
2058
|
+
* minimum so it never flashes); an own-path error → `'error'`;
|
|
2059
|
+
* otherwise earned `valid` → `'success'`, else `'idle'`. The gate opens
|
|
2060
|
+
* after the first submit attempt OR once the field is edited and left:
|
|
2054
2061
|
*
|
|
2055
2062
|
* ```ts
|
|
2056
|
-
* (
|
|
2063
|
+
* (prev, ctx) => {
|
|
2057
2064
|
* const gateOpen =
|
|
2058
|
-
* formMeta.submissionAttempts > 0 ||
|
|
2059
|
-
*
|
|
2060
|
-
* if (!gateOpen) return 'idle'
|
|
2061
|
-
*
|
|
2062
|
-
* //
|
|
2065
|
+
* ctx.formMeta.submissionAttempts > 0 ||
|
|
2066
|
+
* ctx.field.blurredAfterInteraction === true
|
|
2067
|
+
* if (!gateOpen) return { display: 'idle' }
|
|
2068
|
+
* // ...timed 'pending' while validating; own-path error → 'error';
|
|
2069
|
+
* // earned valid → 'success'; else 'idle'
|
|
2063
2070
|
* }
|
|
2064
2071
|
* ```
|
|
2065
2072
|
*
|
|
2066
2073
|
* Compose with the library default via the public `defaultDisplayState`
|
|
2067
|
-
* export
|
|
2074
|
+
* export, or retune its timing via `makeDefaultDisplayState`. The
|
|
2075
|
+
* reducer runs on every field-state read, so it owns the
|
|
2068
2076
|
* idle / pending / error / success decision outright.
|
|
2069
2077
|
*
|
|
2070
|
-
* The
|
|
2071
|
-
* `show*` / `firstError` keys (see
|
|
2072
|
-
* a self-referential
|
|
2078
|
+
* The reducer's `ctx.field` / `ctx.formMeta` are `Omit`'d of the
|
|
2079
|
+
* derived `displayState` / `show*` / `firstError` keys (see
|
|
2080
|
+
* `FieldStateDerivedKey`) to prevent a self-referential reducer.
|
|
2073
2081
|
*/
|
|
2074
2082
|
getDisplayState?: GetDisplayState;
|
|
2075
2083
|
/**
|
|
@@ -2230,16 +2238,58 @@ type DisplayState = 'idle' | 'pending' | 'error' | 'success';
|
|
|
2230
2238
|
*/
|
|
2231
2239
|
type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError';
|
|
2232
2240
|
/**
|
|
2233
|
-
*
|
|
2234
|
-
*
|
|
2235
|
-
* `
|
|
2236
|
-
*
|
|
2237
|
-
*
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2241
|
+
* One step of the display state machine: the verdict the field should
|
|
2242
|
+
* render right now (`display`, projected to `displayState` and the
|
|
2243
|
+
* `show*` booleans) plus two optional timing cells the engine reads.
|
|
2244
|
+
*
|
|
2245
|
+
* - `reviewAt` — an absolute `Date.now()` millisecond stamp telling the
|
|
2246
|
+
* engine "re-evaluate this field no later than here." The engine keeps
|
|
2247
|
+
* a single timer per form aimed at the nearest `reviewAt` across all
|
|
2248
|
+
* active fields; when it fires, the dependent field computeds re-run
|
|
2249
|
+
* and call the reducer again. A machine with no `reviewAt` and a
|
|
2250
|
+
* non-pending `display` is terminal — the engine evicts it.
|
|
2251
|
+
* - `pendingShownAt` — the stamp at which `'pending'` was first shown,
|
|
2252
|
+
* the memory the min-visible hold needs so a spinner that just appeared
|
|
2253
|
+
* is not yanked away the instant validation resolves. Opaque to the
|
|
2254
|
+
* engine; a custom reducer may carry its own extra memory fields too.
|
|
2255
|
+
*/
|
|
2256
|
+
type DisplayMachine = {
|
|
2257
|
+
readonly display: DisplayState;
|
|
2258
|
+
readonly reviewAt?: number;
|
|
2259
|
+
readonly pendingShownAt?: number;
|
|
2260
|
+
};
|
|
2261
|
+
/**
|
|
2262
|
+
* Inputs to a `getDisplayState` reducer. `field` and `formMeta` are the
|
|
2263
|
+
* same reactive snapshots a predicate has always received (still minus
|
|
2264
|
+
* the derived `displayState` / `show*` / `firstError` keys — see
|
|
2265
|
+
* `FieldStateDerivedKey` — so a reducer can never read its own output and
|
|
2266
|
+
* form a cycle), now joined by:
|
|
2267
|
+
*
|
|
2268
|
+
* - `validatingSince` — `Date.now()` at which the field's current
|
|
2269
|
+
* validation streak opened, or `null` when nothing is in flight. This,
|
|
2270
|
+
* not `field.validating`, is the timing anchor: the elapsed wait is
|
|
2271
|
+
* `now - validatingSince`. Pinned to the start of the streak, so
|
|
2272
|
+
* overlapping sub-runs do not reset it.
|
|
2273
|
+
* - `now` — the engine's clock, injected so the reducer stays pure and
|
|
2274
|
+
* deterministic (and frozen to `0` under SSR, where there is no clock).
|
|
2275
|
+
*/
|
|
2276
|
+
type DisplayCtx = {
|
|
2277
|
+
readonly field: Omit<FieldState, FieldStateDerivedKey>;
|
|
2278
|
+
readonly formMeta: Omit<FormMeta, FieldStateDerivedKey>;
|
|
2279
|
+
readonly validatingSince: number | null;
|
|
2280
|
+
readonly now: number;
|
|
2281
|
+
};
|
|
2282
|
+
/**
|
|
2283
|
+
* Pure transition reducer that resolves a path's `displayState`. Given
|
|
2284
|
+
* the field's previous `DisplayMachine` and the current `DisplayCtx`, it
|
|
2285
|
+
* returns the next machine; the engine owns the clock and the timers, the
|
|
2286
|
+
* reducer owns the timing policy. Runs on every field-state read (and
|
|
2287
|
+
* again whenever a `reviewAt` deadline fires), so the whole app's
|
|
2288
|
+
* validation-display behavior flows from this one function.
|
|
2240
2289
|
*
|
|
2241
|
-
* The library default — `defaultDisplayState` — is publicly exported so
|
|
2242
|
-
*
|
|
2290
|
+
* The library default — `defaultDisplayState` — is publicly exported so a
|
|
2291
|
+
* layered reducer can compose with it, and `makeDefaultDisplayState`
|
|
2292
|
+
* builds a default with custom anti-flash timings:
|
|
2243
2293
|
*
|
|
2244
2294
|
* ```ts
|
|
2245
2295
|
* import { defaultDisplayState } from 'attaform'
|
|
@@ -2247,14 +2297,16 @@ type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'sho
|
|
|
2247
2297
|
* useForm({
|
|
2248
2298
|
* schema,
|
|
2249
2299
|
* // Defer to the default everywhere, but never show a success check on `username`.
|
|
2250
|
-
* getDisplayState: (
|
|
2251
|
-
* const
|
|
2252
|
-
* return
|
|
2300
|
+
* getDisplayState: (prev, ctx) => {
|
|
2301
|
+
* const next = defaultDisplayState(prev, ctx)
|
|
2302
|
+
* return next.display === 'success' && ctx.field.path[0] === 'username'
|
|
2303
|
+
* ? { display: 'idle' }
|
|
2304
|
+
* : next
|
|
2253
2305
|
* },
|
|
2254
2306
|
* })
|
|
2255
2307
|
* ```
|
|
2256
2308
|
*/
|
|
2257
|
-
type GetDisplayState = (
|
|
2309
|
+
type GetDisplayState = (prev: DisplayMachine, ctx: DisplayCtx) => DisplayMachine;
|
|
2258
2310
|
/**
|
|
2259
2311
|
* Submit handler returned by `handleSubmit(onSubmit, onError)`. Bind
|
|
2260
2312
|
* it to a `<form>`:
|
|
@@ -4644,5 +4696,5 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4644
4696
|
blankPaths: ComputedRef<BlankPathsView>;
|
|
4645
4697
|
};
|
|
4646
4698
|
|
|
4647
|
-
export {
|
|
4648
|
-
export type { AbstractSchema as A,
|
|
4699
|
+
export { ROOT_PATH as a0, ROOT_PATH_KEY as a1, canonicalizePath as au, isPathPrefix as av, isUnset as aw, parseDottedPath as ax, unset as ay };
|
|
4700
|
+
export type { Primitive as $, AbstractSchema as A, HistoryConfig as B, CoercionEntry as C, DeepPartial as D, ErrorsProxyShape as E, FieldMetaPayload as F, GenericForm as G, HandleSubmit as H, IsTuple as I, IsUnion as J, JoinSegments as K, KeyofUnion as L, LiftedValueShape as M, MetaTrackerValue as N, NestedReadType as O, NestedType as P, OnError as Q, OnInvalidSubmitPolicy as R, OnSubmit as S, PartialFlatPath as T, Path as U, PathKey as V, PendingValidationStatus as W, PersistConfig as X, PersistConfigOptions as Y, PersistIncludeMode as Z, PersistOptInRegistry as _, ApiErrorDetails as a, ReactiveValidationStatus as a2, RegisterDirective as a3, RegisterFlatPath as a4, RegisterModelDynamicCustomDirective as a5, RegisterOptions as a6, RegisterSelectModifier as a7, RegisterTextModifier as a8, RegisterTransform as a9, RegisterValue as aa, SchemaFactoryOptions as ab, Segment as ac, SetValueCallback as ad, SetValuePayload as ae, SettledValidationStatus as af, SlimPrimitiveKind as ag, SlimRuntimeOf as ah, SubmitHandler as ai, Unset as aj, UseFormConfiguration as ak, UseFormReturnType as al, ValidateOn as am, ValidateOnConfig as an, ValidationError as ao, ValidationResponse as ap, ValidationResponseWithoutValue as aq, ValueOfUnion as ar, WriteMeta as as, WriteShape as at, ApiErrorEntry as b, ApiErrorEnvelope as c, ArrayItem as d, ArrayPath as e, AttaformDefaults as f, CoercionRegistry as g, CoercionResult as h, CustomDirectiveRegisterAssignerFn as i, DefaultValuesInput as j, DefaultValuesResponse as k, DefaultValuesShape as l, DisplayCtx as m, DisplayMachine as n, DisplayState as o, FieldState as p, FieldStateMap as q, FieldStateMapEntry as r, FlatPath as s, FormErrorRecord as t, FormErrorsSurface as u, FormKey as v, FormMeta as w, FormStorage as x, FormStorageKind as y, GetDisplayState as z };
|
|
@@ -814,6 +814,12 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
814
814
|
* Structural fingerprint of the schema. Same shape → same string;
|
|
815
815
|
* different shape → (best-effort) different string.
|
|
816
816
|
*
|
|
817
|
+
* Resolves a `Promise` so adapters can defer the structural walk (and
|
|
818
|
+
* its `canonicalStringify` helper) onto a dynamic import. The framework
|
|
819
|
+
* only ever needs the fingerprint on opt-in async paths (the multi-tab
|
|
820
|
+
* channel name, the persistence storage key) plus a dev-only mismatch
|
|
821
|
+
* warning, so none of those bytes belong on the eager `useForm` path.
|
|
822
|
+
*
|
|
817
823
|
* The library uses this to detect schema mismatches at a shared
|
|
818
824
|
* form key: two `useForm({ key: 'x', schema })` calls are allowed
|
|
819
825
|
* to land on the same `FormStore` (the "shared store" semantic),
|
|
@@ -841,7 +847,7 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
841
847
|
* look identical. The warning is a footgun catcher, not a
|
|
842
848
|
* soundness guarantee.
|
|
843
849
|
*/
|
|
844
|
-
fingerprint(): string
|
|
850
|
+
fingerprint(): Promise<string>;
|
|
845
851
|
getDefaultValues(config: GetDefaultValuesConfig<Form>): DefaultValuesResponse<Form>;
|
|
846
852
|
/**
|
|
847
853
|
* Return the schema-prescribed default value at the given path. The
|
|
@@ -2047,29 +2053,31 @@ type AttaformDefaults = {
|
|
|
2047
2053
|
* useForm({ getDisplayState }) > AttaformDefaults > library default
|
|
2048
2054
|
*
|
|
2049
2055
|
* The library default opens one timing gate, then resolves by
|
|
2050
|
-
* precedence: gate closed → `'idle'`; a run in flight →
|
|
2051
|
-
*
|
|
2052
|
-
*
|
|
2053
|
-
*
|
|
2056
|
+
* precedence: gate closed → `'idle'`; a run in flight → a delayed
|
|
2057
|
+
* `'pending'` (held briefly to smooth fast validations, then held a
|
|
2058
|
+
* minimum so it never flashes); an own-path error → `'error'`;
|
|
2059
|
+
* otherwise earned `valid` → `'success'`, else `'idle'`. The gate opens
|
|
2060
|
+
* after the first submit attempt OR once the field is edited and left:
|
|
2054
2061
|
*
|
|
2055
2062
|
* ```ts
|
|
2056
|
-
* (
|
|
2063
|
+
* (prev, ctx) => {
|
|
2057
2064
|
* const gateOpen =
|
|
2058
|
-
* formMeta.submissionAttempts > 0 ||
|
|
2059
|
-
*
|
|
2060
|
-
* if (!gateOpen) return 'idle'
|
|
2061
|
-
*
|
|
2062
|
-
* //
|
|
2065
|
+
* ctx.formMeta.submissionAttempts > 0 ||
|
|
2066
|
+
* ctx.field.blurredAfterInteraction === true
|
|
2067
|
+
* if (!gateOpen) return { display: 'idle' }
|
|
2068
|
+
* // ...timed 'pending' while validating; own-path error → 'error';
|
|
2069
|
+
* // earned valid → 'success'; else 'idle'
|
|
2063
2070
|
* }
|
|
2064
2071
|
* ```
|
|
2065
2072
|
*
|
|
2066
2073
|
* Compose with the library default via the public `defaultDisplayState`
|
|
2067
|
-
* export
|
|
2074
|
+
* export, or retune its timing via `makeDefaultDisplayState`. The
|
|
2075
|
+
* reducer runs on every field-state read, so it owns the
|
|
2068
2076
|
* idle / pending / error / success decision outright.
|
|
2069
2077
|
*
|
|
2070
|
-
* The
|
|
2071
|
-
* `show*` / `firstError` keys (see
|
|
2072
|
-
* a self-referential
|
|
2078
|
+
* The reducer's `ctx.field` / `ctx.formMeta` are `Omit`'d of the
|
|
2079
|
+
* derived `displayState` / `show*` / `firstError` keys (see
|
|
2080
|
+
* `FieldStateDerivedKey`) to prevent a self-referential reducer.
|
|
2073
2081
|
*/
|
|
2074
2082
|
getDisplayState?: GetDisplayState;
|
|
2075
2083
|
/**
|
|
@@ -2230,16 +2238,58 @@ type DisplayState = 'idle' | 'pending' | 'error' | 'success';
|
|
|
2230
2238
|
*/
|
|
2231
2239
|
type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'showSuccess' | 'showIdle' | 'firstError';
|
|
2232
2240
|
/**
|
|
2233
|
-
*
|
|
2234
|
-
*
|
|
2235
|
-
* `
|
|
2236
|
-
*
|
|
2237
|
-
*
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2241
|
+
* One step of the display state machine: the verdict the field should
|
|
2242
|
+
* render right now (`display`, projected to `displayState` and the
|
|
2243
|
+
* `show*` booleans) plus two optional timing cells the engine reads.
|
|
2244
|
+
*
|
|
2245
|
+
* - `reviewAt` — an absolute `Date.now()` millisecond stamp telling the
|
|
2246
|
+
* engine "re-evaluate this field no later than here." The engine keeps
|
|
2247
|
+
* a single timer per form aimed at the nearest `reviewAt` across all
|
|
2248
|
+
* active fields; when it fires, the dependent field computeds re-run
|
|
2249
|
+
* and call the reducer again. A machine with no `reviewAt` and a
|
|
2250
|
+
* non-pending `display` is terminal — the engine evicts it.
|
|
2251
|
+
* - `pendingShownAt` — the stamp at which `'pending'` was first shown,
|
|
2252
|
+
* the memory the min-visible hold needs so a spinner that just appeared
|
|
2253
|
+
* is not yanked away the instant validation resolves. Opaque to the
|
|
2254
|
+
* engine; a custom reducer may carry its own extra memory fields too.
|
|
2255
|
+
*/
|
|
2256
|
+
type DisplayMachine = {
|
|
2257
|
+
readonly display: DisplayState;
|
|
2258
|
+
readonly reviewAt?: number;
|
|
2259
|
+
readonly pendingShownAt?: number;
|
|
2260
|
+
};
|
|
2261
|
+
/**
|
|
2262
|
+
* Inputs to a `getDisplayState` reducer. `field` and `formMeta` are the
|
|
2263
|
+
* same reactive snapshots a predicate has always received (still minus
|
|
2264
|
+
* the derived `displayState` / `show*` / `firstError` keys — see
|
|
2265
|
+
* `FieldStateDerivedKey` — so a reducer can never read its own output and
|
|
2266
|
+
* form a cycle), now joined by:
|
|
2267
|
+
*
|
|
2268
|
+
* - `validatingSince` — `Date.now()` at which the field's current
|
|
2269
|
+
* validation streak opened, or `null` when nothing is in flight. This,
|
|
2270
|
+
* not `field.validating`, is the timing anchor: the elapsed wait is
|
|
2271
|
+
* `now - validatingSince`. Pinned to the start of the streak, so
|
|
2272
|
+
* overlapping sub-runs do not reset it.
|
|
2273
|
+
* - `now` — the engine's clock, injected so the reducer stays pure and
|
|
2274
|
+
* deterministic (and frozen to `0` under SSR, where there is no clock).
|
|
2275
|
+
*/
|
|
2276
|
+
type DisplayCtx = {
|
|
2277
|
+
readonly field: Omit<FieldState, FieldStateDerivedKey>;
|
|
2278
|
+
readonly formMeta: Omit<FormMeta, FieldStateDerivedKey>;
|
|
2279
|
+
readonly validatingSince: number | null;
|
|
2280
|
+
readonly now: number;
|
|
2281
|
+
};
|
|
2282
|
+
/**
|
|
2283
|
+
* Pure transition reducer that resolves a path's `displayState`. Given
|
|
2284
|
+
* the field's previous `DisplayMachine` and the current `DisplayCtx`, it
|
|
2285
|
+
* returns the next machine; the engine owns the clock and the timers, the
|
|
2286
|
+
* reducer owns the timing policy. Runs on every field-state read (and
|
|
2287
|
+
* again whenever a `reviewAt` deadline fires), so the whole app's
|
|
2288
|
+
* validation-display behavior flows from this one function.
|
|
2240
2289
|
*
|
|
2241
|
-
* The library default — `defaultDisplayState` — is publicly exported so
|
|
2242
|
-
*
|
|
2290
|
+
* The library default — `defaultDisplayState` — is publicly exported so a
|
|
2291
|
+
* layered reducer can compose with it, and `makeDefaultDisplayState`
|
|
2292
|
+
* builds a default with custom anti-flash timings:
|
|
2243
2293
|
*
|
|
2244
2294
|
* ```ts
|
|
2245
2295
|
* import { defaultDisplayState } from 'attaform'
|
|
@@ -2247,14 +2297,16 @@ type FieldStateDerivedKey = 'displayState' | 'showErrors' | 'showPending' | 'sho
|
|
|
2247
2297
|
* useForm({
|
|
2248
2298
|
* schema,
|
|
2249
2299
|
* // Defer to the default everywhere, but never show a success check on `username`.
|
|
2250
|
-
* getDisplayState: (
|
|
2251
|
-
* const
|
|
2252
|
-
* return
|
|
2300
|
+
* getDisplayState: (prev, ctx) => {
|
|
2301
|
+
* const next = defaultDisplayState(prev, ctx)
|
|
2302
|
+
* return next.display === 'success' && ctx.field.path[0] === 'username'
|
|
2303
|
+
* ? { display: 'idle' }
|
|
2304
|
+
* : next
|
|
2253
2305
|
* },
|
|
2254
2306
|
* })
|
|
2255
2307
|
* ```
|
|
2256
2308
|
*/
|
|
2257
|
-
type GetDisplayState = (
|
|
2309
|
+
type GetDisplayState = (prev: DisplayMachine, ctx: DisplayCtx) => DisplayMachine;
|
|
2258
2310
|
/**
|
|
2259
2311
|
* Submit handler returned by `handleSubmit(onSubmit, onError)`. Bind
|
|
2260
2312
|
* it to a `<form>`:
|
|
@@ -4644,5 +4696,5 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4644
4696
|
blankPaths: ComputedRef<BlankPathsView>;
|
|
4645
4697
|
};
|
|
4646
4698
|
|
|
4647
|
-
export {
|
|
4648
|
-
export type { AbstractSchema as A,
|
|
4699
|
+
export { ROOT_PATH as a0, ROOT_PATH_KEY as a1, canonicalizePath as au, isPathPrefix as av, isUnset as aw, parseDottedPath as ax, unset as ay };
|
|
4700
|
+
export type { Primitive as $, AbstractSchema as A, HistoryConfig as B, CoercionEntry as C, DeepPartial as D, ErrorsProxyShape as E, FieldMetaPayload as F, GenericForm as G, HandleSubmit as H, IsTuple as I, IsUnion as J, JoinSegments as K, KeyofUnion as L, LiftedValueShape as M, MetaTrackerValue as N, NestedReadType as O, NestedType as P, OnError as Q, OnInvalidSubmitPolicy as R, OnSubmit as S, PartialFlatPath as T, Path as U, PathKey as V, PendingValidationStatus as W, PersistConfig as X, PersistConfigOptions as Y, PersistIncludeMode as Z, PersistOptInRegistry as _, ApiErrorDetails as a, ReactiveValidationStatus as a2, RegisterDirective as a3, RegisterFlatPath as a4, RegisterModelDynamicCustomDirective as a5, RegisterOptions as a6, RegisterSelectModifier as a7, RegisterTextModifier as a8, RegisterTransform as a9, RegisterValue as aa, SchemaFactoryOptions as ab, Segment as ac, SetValueCallback as ad, SetValuePayload as ae, SettledValidationStatus as af, SlimPrimitiveKind as ag, SlimRuntimeOf as ah, SubmitHandler as ai, Unset as aj, UseFormConfiguration as ak, UseFormReturnType as al, ValidateOn as am, ValidateOnConfig as an, ValidationError as ao, ValidationResponse as ap, ValidationResponseWithoutValue as aq, ValueOfUnion as ar, WriteMeta as as, WriteShape as at, ApiErrorEntry as b, ApiErrorEnvelope as c, ArrayItem as d, ArrayPath as e, AttaformDefaults as f, CoercionRegistry as g, CoercionResult as h, CustomDirectiveRegisterAssignerFn as i, DefaultValuesInput as j, DefaultValuesResponse as k, DefaultValuesShape as l, DisplayCtx as m, DisplayMachine as n, DisplayState as o, FieldState as p, FieldStateMap as q, FieldStateMapEntry as r, FlatPath as s, FormErrorRecord as t, FormErrorsSurface as u, FormKey as v, FormMeta as w, FormStorage as x, FormStorageKind as y, GetDisplayState as z };
|