import { c as TAsUnionContext, n as TAsChangeType, o as TAsComponentProps, s as TAsTypeComponents } from "./types-nuUi10Kl.mjs"; import * as vue from "vue"; import { Component, ComputedRef, MaybeRef, MaybeRefOrGetter, Ref, ShallowRef, WritableComputedRef } from "vue"; import * as _atscript_ui0 from "@atscript/ui"; import { ClientFactory, ClientFactory as ClientFactory$1, FormArrayFieldDef, FormDef, FormDiffOptions, FormDiffOptions as FormDiffOptions$1, FormFieldChange, FormFieldChange as FormFieldChange$1, FormFieldDef, FormRebaseOptions, FormRebaseOptions as FormRebaseOptions$1, FormTupleFieldDef, FormUnionFieldDef, FormUnionVariant, ResolvedValueHelp, TResolveOptions, ValueHelpInfo, getDefaultClientFactory, hasFieldMeta as hasFieldMeta$1, isFieldHidden as isFieldHidden$1, joinPath as joinPath$1, resetDefaultClientFactory, setDefaultClientFactory } from "@atscript/ui"; import { TFnScope } from "@atscript/ui-fns"; //#region ../../node_modules/.pnpm/@atscript+typescript@0.1.89_@atscript+core@0.1.89_@emnapi+core@1.10.0_@emnapi+runtime@1_b0e5f363a69ffdf76d52ca9544abe0f7/node_modules/@atscript/typescript/dist/utils.d.ts interface TError { path: string; message: string; details?: TError[]; } /** * A plugin function that can intercept validation. * * Return `true` to accept the value, `false` to reject it, * or `undefined` to fall through to the default validation. */ type TValidatorPlugin = (ctx: TValidatorPluginContext, def: TAtscriptAnnotatedType, value: any) => boolean | undefined; /** Options for configuring {@link Validator} behavior. */ interface TValidatorOptions { partial: boolean | 'deep' | ((type: TAtscriptAnnotatedType, path: string) => boolean); replace?: (type: TAtscriptAnnotatedType, path: string) => TAtscriptAnnotatedType; plugins: TValidatorPlugin[]; unknownProps: 'strip' | 'ignore' | 'error'; errorLimit: number; skipList?: Set; } /** Context exposed to {@link TValidatorPlugin} functions. */ interface TValidatorPluginContext { opts: Validator['opts']; validateAnnotatedType: Validator['validateAnnotatedType']; error: Validator['error']; path: Validator['path']; context: unknown; } /** * Validates values against an {@link TAtscriptAnnotatedType} definition. * * `DataType` is automatically inferred from the type definition's phantom generic, * enabling the {@link validate} method to act as a type guard. * * @example * ```ts * // From a generated interface class: * const validator = new Validator(MyInterface) * if (validator.validate(data, true)) { * data // narrowed to MyInterface * } * * // Or use the built-in factory: * MyInterface.validator().validate(data) * ``` * * @typeParam T - The annotated type definition. * @typeParam DataType - The TypeScript type that `validate` narrows to (auto-inferred). */ declare class Validator> { protected readonly def: T; protected opts: TValidatorOptions; protected hasPlugins: boolean; protected hasReplace: boolean; private replaceCache?; constructor(def: T, opts?: Partial); /** Validation errors collected during the last {@link validate} call. */ errors: TError[]; protected stackErrors: Array; protected pathSegments: string[]; protected depth: number; protected limitExceeded: boolean; protected context: unknown; protected buildPath(): string; protected push(name: string): void; protected pop(saveErrors: boolean): TError[] | null | undefined; protected clear(): void; protected error(message: string, path?: string, details?: TError[]): void; protected throw(): void; /** * Validates a value against the type definition. * * Acts as a TypeScript type guard — when it returns `true`, the value * is narrowed to `DataType`. * * @param value - The value to validate. * @param safe - If `true`, returns `false` on failure instead of throwing. * @returns `true` if the value matches the type definition. * @throws {ValidatorError} When validation fails and `safe` is not `true`. */ validate(value: any, safe?: boolean, context?: unknown): value is TT; protected validateSafe(def: TAtscriptAnnotatedType, value: any): boolean; protected get path(): string; protected validateAnnotatedType(def: TAtscriptAnnotatedType, value: any): boolean; protected validateUnion(def: TAtscriptAnnotatedType, value: any): boolean; protected validateIntersection(def: TAtscriptAnnotatedType, value: any): boolean; protected validateTuple(def: TAtscriptAnnotatedType, value: any): boolean; protected validateArray(def: TAtscriptAnnotatedType, value: any): boolean; protected validateObject(def: TAtscriptAnnotatedType, value: any): boolean; protected validatePrimitive(def: TAtscriptAnnotatedType, value: any): boolean; protected validateString(def: TAtscriptAnnotatedType, value: string): boolean; protected validateNumber(def: TAtscriptAnnotatedType, value: number): boolean; protected validateBoolean(def: TAtscriptAnnotatedType, value: boolean): boolean; } /** Error thrown by {@link Validator.validate} when validation fails. Contains structured error details. */ /** Type definition for union, intersection, or tuple types. */ interface TAtscriptTypeComplex { kind: 'union' | 'intersection' | 'tuple'; items: TAtscriptAnnotatedType[]; tags: Set; /** @internal phantom — carries the DataType at the type level, never set at runtime */ __dataType?: DataType; } /** Type definition for array types. */ interface TAtscriptTypeArray { kind: 'array'; of: TAtscriptAnnotatedType; tags: Set; /** @internal phantom — carries the DataType at the type level, never set at runtime */ __dataType?: DataType; } /** Type definition for object types with named and pattern-matched properties. */ interface TAtscriptTypeObject> { kind: 'object'; props: Map; propsPatterns: Array<{ pattern: RegExp; def: TAtscriptAnnotatedType; }>; tags: Set; /** @internal phantom — carries the DataType at the type level, never set at runtime */ __dataType?: DataType; } /** Type definition for primitive/literal types (string, number, boolean, null, etc.). */ interface TAtscriptTypeFinal { kind: ''; /** * design type */ designType: 'string' | 'number' | 'boolean' | 'undefined' | 'null' | 'object' | 'any' | 'never' | 'phantom' | 'decimal'; /** * value for literals */ value?: string | number | boolean; tags: Set; /** @internal phantom — carries the DataType at the type level, never set at runtime */ __dataType?: DataType; } /** * Extract DataType from a type def's phantom generic */ type InferDataType = T extends { __dataType?: infer D; } ? D : unknown; /** * Extract the DataType from a {@link TAtscriptAnnotatedType}. * * Resolves the phantom `__dataType` carried by the type definition. * When `__dataType` is `unknown` (unset), falls back to the constructor * instance type if `T` is also a class (i.e. a generated interface). * * @example * ```ts * import type { TAtscriptDataType } from '@atscript/typescript/utils' * import MyInterface from './my-interface.as' * * type Data = TAtscriptDataType * ``` */ type TAtscriptDataType = T extends { type: { __dataType?: infer D; }; } ? unknown extends D ? T extends (new (...args: any[]) => infer I) ? I : unknown : D : unknown; /** Union of all possible type definition shapes. */ type TAtscriptTypeDef = TAtscriptTypeComplex | TAtscriptTypeFinal | TAtscriptTypeArray | TAtscriptTypeObject; /** * Core annotated type — wraps a type definition with metadata and a validator factory. * * Generated `.as` files produce classes/namespaces that conform to this interface. * The `DataType` phantom generic carries the TypeScript data shape for type-safe validation. * * @typeParam T - The underlying type definition (e.g. {@link TAtscriptTypeObject}). * @typeParam DataType - The TypeScript type the validated data narrows to (auto-inferred from `T`). */ interface TAtscriptAnnotatedType> { __is_atscript_annotated_type: true; type: T; validator(opts?: Partial): Validator; metadata: TMetadataMap; optional?: boolean; id?: string; ref?: { type: () => TAtscriptAnnotatedType; field: string; }; } /** An annotated type that is also a class constructor (i.e. a generated interface class). */ /** * Atscript Metadata Map with typed setters/getters */ interface TMetadataMap extends Map { get(key: K): O[K] | undefined; get(key: string): unknown; set(key: K, value: O[K]): this; has(key: K): boolean; has(key: string): boolean; } /** Fluent builder handle returned by {@link defineAnnotatedType}. */ //#endregion //#region src/composables/create-as-form-def.d.ts /** * Creates a reactive form definition and data object from an ATScript annotated type. * * @param type - An ATScript annotated type (imported from a `.as` file). * @param context - Optional context object forwarded to `ui.fn.value` resolvers during data creation. * Only effective when `@atscript/ui-fns` is installed (dynamic resolver). * @returns `{ def, formData }` — the FormDef and a Vue reactive data object with defaults applied */ declare function createAsFormDef(type: T, context?: Record): { def: _atscript_ui0.FormDef; formData: { value: vue.UnwrapRef>; }; }; //#endregion //#region src/composables/create-default-types.d.ts /** * Returns a fresh type-to-component map pre-filled with all built-in defaults. * * Spread or assign additional entries to extend with custom field types: * ```ts * const types = { ...createDefaultTypes(), rating: MyRatingComponent } * ``` */ declare function createDefaultTypes(): TAsTypeComponents; //#endregion //#region src/composables/types.d.ts type TFormRule = (v: TValue, data?: TFormData, context?: TContext) => boolean | string; interface TFormFieldCallbacks { validate: () => boolean | string; clearErrors: () => void; reset: () => void; setExternalError: (msg?: string) => void; /** * Read the error message the field is DISPLAYING right now (external > * submit > live-validated per `firstValidation` gating), or `undefined` * when clean. Feeds the form-level live error aggregation (descendant * error-count badges / auto-open), so badges track what's on screen * without waiting for a submit. Optional so manually built registrations * keep working — a field that omits it simply doesn't contribute live * errors (submit-time errors still count through the form's own map). */ getError?: () => string | undefined; } interface TFormFieldRegistration { path: () => string; callbacks: TFormFieldCallbacks; } interface TFormState { firstSubmitHappened: boolean; firstValidation: "on-change" | "touched-on-blur" | "on-blur" | "on-submit" | "none"; /** * Fields registered AFTER `firstSubmitHappened` flipped to true. They stay * in this set until either the user edits the field (model watch removes * the id) or the next submit fires (set is cleared). Live validation is * suppressed for these fields so a freshly-added array item doesn't render * red required-field errors before the user has had a chance to type. */ freshFields: Set; register: (id: symbol, registration: TFormFieldRegistration) => void; unregister: (id: symbol) => void; } //#endregion //#region src/composables/use-as-field.d.ts interface UseAsFieldOptions { getValue: () => TValue; setValue: (v: TValue) => void; rules?: TFormRule[]; path: () => string; /** Value to set on reset. Defaults to `''`. Use `[]` for arrays, `{}` for objects. */ resetValue?: TValue; } interface UseAsFieldReturn { model: WritableComputedRef; error: ComputedRef; onBlur: () => void; /** * Reactive "changed-since-baseline" flag for THIS field. `true` when the * form has `track-changes` enabled AND the field at `opts.path()` differs * from the tracker's baseline. Recomputes whenever the change list does * (delegates to the injected {@link AsFormPatchHandle.isDirtyPath}). * * Always `false` when tracking is off (no patch handle injected) — the * handle is injected OPTIONALLY, so reading `isDirty` never throws. * Granularity matches the change list: object/section containers light up * via their leaves' prefix, whole-array fields via exact match; an * array-ITEM leaf stays `false` (the array container lights up instead). */ isDirty: ComputedRef; } declare function useAsField(opts: UseAsFieldOptions): UseAsFieldReturn; //#endregion //#region src/composables/use-as-state.d.ts /** Custom form-level validator. Returns `Record` (empty = passed). */ type TFormSubmitValidator = () => Record; interface UseAsStateReturn { formState: TFormState; clearErrors: () => void; reset: () => Promise; submit: () => true | { path: string; message: string; }[]; setErrors: (errors: Record) => void; /** * What every registered field DISPLAYS right now, keyed by path * (`callbacks.getError` per field; fields without the callback are * skipped). Recomputes when any field's displayed error changes and on * register/unregister — the live source for error-count badges. */ liveErrors: ComputedRef>; /** Paths of all currently registered (mounted) fields. */ registeredPaths: ComputedRef>; } declare function useAsState(opts: { formData: MaybeRef; formContext?: MaybeRef; firstValidation?: MaybeRef; /** When provided, replaces per-field iteration on submit. */ submitValidator?: TFormSubmitValidator; }): UseAsStateReturn; //#endregion //#region src/composables/use-as-form-patch.d.ts /** * Result of {@link AsFormPatchHandle.rebaseOnto}. Aliases the `@atscript/ui` * rebase shape (minus `next`, which is written into the live container rather * than returned): the surviving local diff on top of the NEW baseline plus the * conflict paths. */ interface RebaseOntoResult { /** Paths changed on both sides to different values, plus ancestor-clear paths. */ conflicts: string[]; /** Local edits that survive on top of the new (upstream) baseline. */ reapplied: FormFieldChange[]; } /** * Change-tracking handle for a single ``. Exposed three ways: * * 1. injected via {@link useAsFormPatch} inside any descendant component, * 2. spread into every `` slot (`isDirty` / `changes` / `getPatch` / * `getChanges` — so a footer slot can gate a Save button), and * 3. `defineExpose`d on `` (so a parent template ref can call * `asForm.value.getPatch()`). * * Built on `@atscript/ui`'s `buildFormDiff`, which diffs the form's CURRENT * data against a BASELINE snapshot and produces both a per-field change list * and an `@atscript/db` patch object (keyed-array `$update`/`$insert`/`$remove`, * `$cas` optimistic-concurrency sibling, revert-aware). */ interface AsFormPatchHandle { /** * Reactive dirtiness — `true` when current data differs from the baseline. * Revert-aware: a value edited back to its baseline flips this back to * `false`. Memoised by Vue; recomputes only when the form data changes. */ isDirty: ComputedRef; /** * Reactive per-field change list (revert-aware — reverted fields drop out). * `before` / `after` hold live references into the baseline / current data. */ changes: ComputedRef; /** * Builds the `@atscript/db` patch object on demand against the baseline * snapshot. Safe to call at submit time (a fresh re-snapshot point). Returns * `{}` when nothing changed. Carries a top-level `$cas` sibling when the form * has a `@db.column.version` column and `opts.cas` is on (default). */ getPatch: (opts?: FormDiffOptions) => Record; /** Builds the per-field change list on demand (same data as `changes`). */ getChanges: () => FormFieldChange[]; /** * Reactive per-field dirty predicate. `true` when the field at the dot-path * `path` differs from the baseline. Reads the reactive {@link changes} list, * so a per-field `isDirty` derived from this recomputes whenever the change * list does. * * Granularity matches the change list (leaf-grained for scalars/objects, * WHOLE-ARRAY for arrays): a field is dirty iff some change path equals * `path` OR starts with `path + "."`. Object/section containers light up via * the prefix branch; whole-array fields via exact match; an array-ITEM leaf * (e.g. `items.0.qty`) returns `false` (the array container lights up * instead — a known, documented limitation of the array diff). The empty * root path `''` is dirty iff there are ANY changes. Backed by an O(1) * `Set.has` against `@atscript/ui`'s `collectDirtyPaths` precompute, whose * membership matches `isPathDirty` exactly (locked by an invariant test). */ isDirtyPath: (path: string) => boolean; /** * Re-baseline to the current data. Call after a successful save so the form * becomes clean again WITHOUT a remount. No-op when tracking is inactive. */ rebase: () => void; /** * 3-way rebase onto a fresh upstream snapshot. Sets the baseline to * `upstream` and rewrites the live form to `upstream` + the local diff * (current vs. old baseline) reapplied on top: * * - fields the user never touched adopt `upstream`'s value, * - local edits survive, * - fields changed on both sides to a different value are conflicts, resolved * by `opts.conflict` (`'ours'` default keeps local, `'theirs'` takes * upstream). * * `upstream` is the WRAPPED form-data container (`{ value }`). The live form * data is rewritten in a SINGLE mutation (the bound `:form-data` container * identity is preserved, so the consumer's ref stays the same object). After * the write the baseline becomes a deep clone of `upstream`, so a subsequent * `getPatch()` carries exactly the surviving local diff (`reapplied`). * * Returns the conflict paths and the surviving local diff. No-op returning * empty when tracking is inactive. */ rebaseOnto: (upstream: Record, opts?: FormRebaseOptions) => RebaseOntoResult; } /** * Reactive read-only access to the form's change-tracking handle from any * descendant of an ``. Mirrors the `useAsData` / * `useAsPath` injector pattern. * * THROWS when called outside a form, or inside a form that did not enable * `track-changes` — fail loud rather than silently report "not dirty". * * @example * ```vue * * * ``` */ declare function useAsFormPatch(): AsFormPatchHandle; //#endregion //#region src/composables/use-as-form.d.ts /** * Options for {@link useAsForm}. Each reactive prop is supplied as a * **getter** so the composable can subscribe to its changes without owning * a `Ref`. Pass component-level `defineProps` accessors verbatim: * * ```ts * useAsForm({ * def: () => props.def, * formData: () => props.formData, * types: () => props.types, * // ... * emits: { submit: (data) => emit("submit", data), ... }, * }) * ``` * * Generic `TFormData` / `TFormContext` mirror the `` component * generics. They flow through to emitted callbacks; if you build a custom * form root with a known data shape, pin them at the call site. */ interface UseAsFormOptions { /** Form definition produced by `createAsFormDef(type)`. Reactive. */ def: () => FormDef; /** * Externally-managed form data container `{ value: domainData }`. When * unset, the composable creates an internal one initialized to `{}`. */ formData?: () => TFormData | undefined; /** Reactive form context — exposed to validators, scope, slots, and emits. */ formContext?: () => TFormContext | undefined; /** First-validation strategy. Defaults to `"on-change"`. */ firstValidation?: () => TFormState["firstValidation"] | undefined; /** Custom field components keyed by field name (matches `Props.components`). */ components?: () => Record> | undefined; /** Type-to-component map keyed by field type (matches `Props.types`). */ types: () => TAsTypeComponents; /** Server-supplied errors keyed by absolute dotted path (`__form` for form-level). */ errors?: () => Record | undefined; /** Per-form value-help client factory. Falls back to the app-wide default when unset. */ clientFactory?: () => ClientFactory | undefined; /** Suppress the root field's title (use when the chrome already shows the form's label). */ hideRootTitle?: () => boolean | undefined; /** * Busy-state flag. When `true`, the form is locked (inert + overlay) and the * default submit button is disabled. `` wires this to its * server round-trip so consumers can drop their own submit overrides. */ loading?: () => boolean | undefined; /** * Enable change tracking. When `true`, the composable captures a deep-clone * baseline of the form data (the moment it becomes available) and exposes a * {@link AsFormPatchHandle} via `slotProps`, the return value (`patch`), and * `provide(FORM_PATCH_KEY)` (read with `useAsFormPatch()`). When falsy * (default), there is ZERO overhead — no baseline, no deep watch, and * `useAsFormPatch()` throws. Reactive. */ trackChanges?: () => boolean | undefined; /** * Outbound callbacks. Customer form roots typically wire these to * `defineEmits`; advanced uses can pass plain functions. */ emits?: { submit?: (data: TFormData) => void; error?: (errors: { path: string; message: string; }[]) => void; action?: (name: string, data: TFormData) => void; unsupportedAction?: (name: string, data: TFormData) => void; change?: (type: TAsChangeType, path: string, value: unknown, formData: TFormData) => void; }; } interface UseAsFormReturn { /** Reactive form-data container `{ value: domainData }`. */ data: ComputedRef; /** Effective external errors (post-dismissal), excluding `__form`. */ errors: ComputedRef | undefined>; /** Form-level error message (post banner-dismissal). */ formError: ComputedRef; /** Errors discovered by the local validator on the most-recent submit. */ internalErrors: Ref>; /** * Reset internal validator + dismissal state and re-run field defaults. When * `trackChanges` is enabled, also re-baselines the change tracker to the * post-reset state (the form becomes clean again). */ reset: () => Promise; /** * Imperatively clear ALL error state: per-field (touched / blur / submit / * external via `useAsState().clearErrors`) plus the form-level submit-time * error map that feeds the descendant-count badges. */ clearErrors: () => void; /** Imperatively set external-error messages by path. */ setErrors: (errors: Record) => void; /** Trigger submit. Emits `submit` on success and `error` on validation failure. */ onSubmit: () => void; /** Resolved submit-button text (`@ui.form.submit.text` / fn variant). */ submitText: ComputedRef; /** Resolved submit-button disabled state (`@ui.form.fn.submitDisabled`). */ submitDisabled: ComputedRef; /** Resolved form-level title (`@ui.form.fn.title` / `@meta.label`); may be `undefined`. */ title: ComputedRef; /** Resolved form-level description (`@ui.form.fn.description` / `@meta.description`). */ description: ComputedRef; /** Unified slot-props bag spread onto every `` slot. */ slotProps: ComputedRef<{ title: string | undefined; description: string | undefined; data: TFormData; errors: Record | undefined; formError: string | undefined; disabled: boolean; loading: boolean; submitText: string; submit: () => void; reset: () => Promise; clearErrors: () => void; setErrors: (errors: Record) => void; dismissError: (path: string) => void; dismissFormError: () => void; formContext: TFormContext | undefined; /** True when `track-changes` is on AND data differs from baseline. */ isDirty: boolean; /** Revert-aware per-field change list (empty when tracking is off). */ changes: readonly FormFieldChange[]; /** Build the `@atscript/db` patch on demand (`{}` when tracking is off). */ getPatch: (opts?: FormDiffOptions) => Record; /** Build the per-field change list on demand (`[]` when tracking is off). */ getChanges: () => FormFieldChange[]; /** Per-field dirty predicate (`false` for every path when tracking is off). */ isDirtyPath: (path: string) => boolean; }>; /** * Change-tracking handle — present ONLY when `trackChanges` is enabled. * `undefined` otherwise. Read it from descendants with `useAsFormPatch()`. */ patch: AsFormPatchHandle | undefined; /** * Remount key for the field subtree. Bound as `:key` on the root ``. * Bumped by `patch.rebaseOnto` only when a rebase lands a different union * variant, forcing the variant picker to re-detect. `0` otherwise. */ remountKey: Ref; /** Dispatch an action — invoked by ``. */ invokeAction: (name: string) => void; /** Dismiss a single external leaf error. */ dismissError: (path: string) => void; /** Dismiss the form-level banner. */ dismissFormError: () => void; /** Form-context getter (mirrors `options.formContext()`). */ formContext: ComputedRef; /** Internal change-dispatcher used by `` and structured components. */ handleChange: (type: TAsChangeType, path: string, value: unknown) => void; } /** * Composable backing ``. Owns the entire form state machine — * data container, internal validator, external-error dismissal, action * routing, change merging, descendant counts, auto-open, and all * provide/inject wiring. Customers building a custom form root can * call this directly and render their own `
` template. * * MUST be called from a component's `