@atscript/vue-form 0.1.103 → 0.1.105
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/{as-action-lLooKipk.cjs → as-action-B712j9xf.cjs} +4 -0
- package/dist/{as-action-BoZtbaXt.mjs → as-action-CCjN5EFP.mjs} +4 -0
- package/dist/as-action.cjs +1 -1
- package/dist/as-action.d.cts +1 -1
- package/dist/as-action.d.mts +1 -1
- package/dist/as-action.mjs +1 -1
- package/dist/{as-action.vue-BCbopk0S.d.cts → as-action.vue-BL8_a0fE.d.cts} +1 -1
- package/dist/{as-action.vue-BtQX09n-.d.mts → as-action.vue-CcOPK2qI.d.mts} +1 -1
- package/dist/{as-array-4rQYVD9_.mjs → as-array-BGG38Y1L.mjs} +5 -1
- package/dist/{as-array-C6tCzZir.cjs → as-array-DVc9_ood.cjs} +5 -1
- package/dist/as-array.cjs +1 -1
- package/dist/as-array.d.cts +1 -1
- package/dist/as-array.d.mts +1 -1
- package/dist/as-array.mjs +1 -1
- package/dist/{as-array.vue-Ci4xO292.d.cts → as-array.vue-Be1tDTdH.d.cts} +1 -1
- package/dist/{as-array.vue-I42wuF6e.d.mts → as-array.vue-CtBBY2gF.d.mts} +1 -1
- package/dist/{as-checkbox-C3i6ZmRk.mjs → as-checkbox-DwLRHmXj.mjs} +5 -1
- package/dist/{as-checkbox-oxG8_Isu.cjs → as-checkbox-sgF16SuJ.cjs} +5 -1
- package/dist/as-checkbox.cjs +1 -1
- package/dist/as-checkbox.d.cts +1 -1
- package/dist/as-checkbox.d.mts +1 -1
- package/dist/as-checkbox.mjs +1 -1
- package/dist/{as-checkbox.vue-BoY72SV8.d.mts → as-checkbox.vue-B6zk5IbU.d.cts} +1 -1
- package/dist/{as-checkbox.vue-DqIm0ms2.d.cts → as-checkbox.vue-CXpsn_WG.d.mts} +1 -1
- package/dist/as-collapsible.d.cts +1 -18
- package/dist/as-collapsible.d.mts +1 -19
- package/dist/as-collapsible.vue-34S3TEq5.d.cts +20 -0
- package/dist/as-collapsible.vue-CIfMlTQ6.d.mts +20 -0
- package/dist/{as-date-BfISLr-e.mjs → as-date-CfCa2Kp1.mjs} +6 -2
- package/dist/{as-date-C7pJIpe-.cjs → as-date-hCCTd52o.cjs} +6 -2
- package/dist/as-date.cjs +1 -1
- package/dist/as-date.d.cts +1 -1
- package/dist/as-date.d.mts +1 -1
- package/dist/as-date.mjs +1 -1
- package/dist/{as-date.vue-BfSVrED7.d.mts → as-date.vue-BZiy1s5s.d.cts} +1 -1
- package/dist/{as-date.vue-SdlJH5fn.d.cts → as-date.vue-DWWoojir.d.mts} +1 -1
- package/dist/{as-datetime-F3In2A6l.mjs → as-datetime-B1I_zREk.mjs} +6 -2
- package/dist/{as-datetime-DFTI8Wcr.cjs → as-datetime-DDlWca2Q.cjs} +6 -2
- package/dist/as-datetime.cjs +1 -1
- package/dist/as-datetime.d.cts +1 -1
- package/dist/as-datetime.d.mts +1 -1
- package/dist/as-datetime.mjs +1 -1
- package/dist/{as-datetime.vue-B47V1siL.d.mts → as-datetime.vue-DYEHokj_.d.cts} +1 -1
- package/dist/{as-datetime.vue-DUp_TDOW.d.cts → as-datetime.vue-NblA-SVE.d.mts} +1 -1
- package/dist/{as-decimal-DIO8bD2Y.mjs → as-decimal-CQM5OfqB.mjs} +5 -1
- package/dist/{as-decimal-CJAHWYjW.cjs → as-decimal-DM10ycwv.cjs} +5 -1
- package/dist/as-decimal.cjs +1 -1
- package/dist/as-decimal.d.cts +1 -1
- package/dist/as-decimal.d.mts +1 -1
- package/dist/as-decimal.mjs +1 -1
- package/dist/{as-decimal.vue-Bhq4C1Ix.d.cts → as-decimal.vue-BoNNIhbL.d.mts} +1 -1
- package/dist/{as-decimal.vue-DitPZpS_.d.mts → as-decimal.vue-D3eGMvC0.d.cts} +1 -1
- package/dist/{as-field-DLW-csEu.mjs → as-field-5rz47opo.mjs} +10 -4
- package/dist/{as-field-shell-CW3DDHnq.cjs → as-field-shell-C4epFfvE.cjs} +29 -23
- package/dist/{as-field-shell-BHYEjGcn.mjs → as-field-shell-DLvPV8WS.mjs} +29 -23
- package/dist/as-field-shell.cjs +1 -1
- package/dist/as-field-shell.d.cts +1 -1
- package/dist/as-field-shell.d.mts +1 -1
- package/dist/as-field-shell.mjs +1 -1
- package/dist/{as-field-shell.vue-Ct1ixFqc.d.cts → as-field-shell.vue-CLDHaWN0.d.cts} +1 -1
- package/dist/{as-field-shell.vue-K4Flr3gw.d.mts → as-field-shell.vue-DssDDSal.d.mts} +1 -1
- package/dist/{as-field-BKa4D63r.cjs → as-field-vktmRs-V.cjs} +9 -3
- package/dist/as-field.cjs +1 -1
- package/dist/as-field.d.cts +1 -24
- package/dist/as-field.d.mts +1 -25
- package/dist/as-field.mjs +1 -1
- package/dist/as-field.vue-A2cJj-Ih.d.cts +26 -0
- package/dist/as-field.vue-CmjIDgQ5.d.mts +26 -0
- package/dist/{as-form-CrMA0HdQ.cjs → as-form-B4DKpAVk.cjs} +75 -37
- package/dist/{as-form-OsyP7m-A.mjs → as-form-me0zA-52.mjs} +77 -39
- package/dist/as-form.cjs +1 -1
- package/dist/as-form.d.cts +1 -1
- package/dist/as-form.d.mts +1 -1
- package/dist/as-form.mjs +1 -1
- package/dist/as-form.vue-BEXuZ83-.d.mts +1425 -0
- package/dist/as-form.vue-liXf4fgq.d.cts +1425 -0
- package/dist/{as-input-CqxNYh5q.cjs → as-input-Bp1Ltp15.cjs} +6 -2
- package/dist/{as-input-D7aA22Yx.mjs → as-input-DF--i7kY.mjs} +6 -2
- package/dist/{as-input-control-BYo_dfQA.cjs → as-input-control-B7F2q99A.cjs} +4 -0
- package/dist/{as-input-control-Bx-isLZN.mjs → as-input-control-BofS4mCo.mjs} +4 -0
- package/dist/as-input.cjs +1 -1
- package/dist/as-input.d.cts +1 -1
- package/dist/as-input.d.mts +1 -1
- package/dist/as-input.mjs +1 -1
- package/dist/{as-input.vue-BHsVVncq.d.cts → as-input.vue-CCAEWqK8.d.mts} +1 -1
- package/dist/{as-input.vue-DgZrW4pc.d.mts → as-input.vue-Nc9Q3RPh.d.cts} +1 -1
- package/dist/{as-iterator-DsDKfpTh.cjs → as-iterator-Bd-bKTMY.cjs} +1 -1
- package/dist/{as-iterator-DW7giLlz.mjs → as-iterator-BjIF-O-J.mjs} +1 -1
- package/dist/as-iterator.cjs +1 -1
- package/dist/as-iterator.d.cts +1 -20
- package/dist/as-iterator.d.mts +1 -21
- package/dist/as-iterator.mjs +1 -1
- package/dist/as-iterator.vue-BZeozFr-.d.cts +22 -0
- package/dist/as-iterator.vue-C8HW6n25.d.mts +22 -0
- package/dist/{as-multi-select-DQUInqwY.cjs → as-multi-select-b1l34vP5.cjs} +5 -1
- package/dist/{as-multi-select-Bsf4Y_mv.mjs → as-multi-select-mp-aM3LV.mjs} +5 -1
- package/dist/as-multi-select.cjs +1 -1
- package/dist/as-multi-select.d.cts +1 -1
- package/dist/as-multi-select.d.mts +1 -1
- package/dist/as-multi-select.mjs +1 -1
- package/dist/{as-multi-select.vue--bavpcN-.d.cts → as-multi-select.vue-D9mseRFm.d.cts} +1 -1
- package/dist/{as-multi-select.vue-rsDUkzxa.d.mts → as-multi-select.vue-DKpOsOmM.d.mts} +1 -1
- package/dist/{as-number-B8MCg-ph.mjs → as-number-De9zTltV.mjs} +6 -2
- package/dist/{as-number-CFdK5xjM.cjs → as-number-joydTMcJ.cjs} +6 -2
- package/dist/as-number.cjs +1 -1
- package/dist/as-number.d.cts +1 -1
- package/dist/as-number.d.mts +1 -1
- package/dist/as-number.mjs +1 -1
- package/dist/{as-number.vue-D2DrbnQu.d.cts → as-number.vue-CZC0-zs8.d.cts} +1 -1
- package/dist/{as-number.vue-Oml2y6Nt.d.mts → as-number.vue-DrvjSOdq.d.mts} +1 -1
- package/dist/{as-object-CN3KZFXO.mjs → as-object-CQMTYtcY.mjs} +5 -1
- package/dist/{as-object-B4sF9sIh.cjs → as-object-DgeItRdH.cjs} +5 -1
- package/dist/as-object.cjs +1 -1
- package/dist/as-object.d.cts +1 -1
- package/dist/as-object.d.mts +1 -1
- package/dist/as-object.mjs +1 -1
- package/dist/{as-object.vue-BljKYrMo.d.cts → as-object.vue-BItO19fw.d.mts} +1 -1
- package/dist/{as-object.vue-DAq7Kha3.d.mts → as-object.vue-DbHog5M-.d.cts} +1 -1
- package/dist/{as-paragraph-GIGj6UgL.mjs → as-paragraph-BP3-0EY4.mjs} +4 -0
- package/dist/{as-paragraph-BA-c863H.cjs → as-paragraph-CPhDTH_V.cjs} +4 -0
- package/dist/as-paragraph.cjs +1 -1
- package/dist/as-paragraph.d.cts +1 -1
- package/dist/as-paragraph.d.mts +1 -1
- package/dist/as-paragraph.mjs +1 -1
- package/dist/{as-paragraph.vue-CBU_olev.d.mts → as-paragraph.vue-BGDpjceO.d.mts} +1 -1
- package/dist/{as-paragraph.vue-LxXA7VPD.d.cts → as-paragraph.vue-D36pdOoc.d.cts} +1 -1
- package/dist/{as-radio-BeOQdoeq.cjs → as-radio-Dlmxk1vr.cjs} +5 -1
- package/dist/{as-radio-CFaDbRPe.mjs → as-radio-SwpgM1xP.mjs} +5 -1
- package/dist/as-radio.cjs +1 -1
- package/dist/as-radio.d.cts +1 -1
- package/dist/as-radio.d.mts +1 -1
- package/dist/as-radio.mjs +1 -1
- package/dist/{as-radio.vue-Dk4nlz-d.d.cts → as-radio.vue-EfrhKcBF.d.cts} +1 -1
- package/dist/{as-radio.vue-TVMliE1e.d.mts → as-radio.vue-WywkI-zY.d.mts} +1 -1
- package/dist/{as-ref-CNQgr6zE.mjs → as-ref-8JnEuan0.mjs} +5 -1
- package/dist/{as-ref-RawBvR6v.cjs → as-ref-BCpvUq8E.cjs} +5 -1
- package/dist/as-ref.cjs +1 -1
- package/dist/as-ref.d.cts +1 -1
- package/dist/as-ref.d.mts +1 -1
- package/dist/as-ref.mjs +1 -1
- package/dist/{as-ref.vue-CUxxGqyg.d.mts → as-ref.vue-BD_vsu7I.d.mts} +1 -1
- package/dist/{as-ref.vue-CnzqRblA.d.cts → as-ref.vue-Cxg-A5QR.d.cts} +1 -1
- package/dist/{as-select-Cr00CPKf.mjs → as-select-C3ukCyGQ.mjs} +5 -1
- package/dist/{as-select-LJIvBPiv.cjs → as-select-CtSNZXtC.cjs} +5 -1
- package/dist/as-select.cjs +1 -1
- package/dist/as-select.d.cts +1 -1
- package/dist/as-select.d.mts +1 -1
- package/dist/as-select.mjs +1 -1
- package/dist/{as-select.vue-CKjAg-Y2.d.mts → as-select.vue-DoAG5njV.d.mts} +1 -1
- package/dist/{as-select.vue-ZZtjsmcO.d.cts → as-select.vue-hd94jaH_.d.cts} +1 -1
- package/dist/{as-time-CE2FaqZ3.mjs → as-time-QJ9YiVj9.mjs} +6 -2
- package/dist/{as-time-CqCF0pKQ.cjs → as-time-nAPtGL3t.cjs} +6 -2
- package/dist/as-time.cjs +1 -1
- package/dist/as-time.d.cts +1 -1
- package/dist/as-time.d.mts +1 -1
- package/dist/as-time.mjs +1 -1
- package/dist/{as-time.vue-BCEE4uCV.d.mts → as-time.vue-DMy_Au0C.d.cts} +1 -1
- package/dist/{as-time.vue-BUAvE5m3.d.cts → as-time.vue-DgW7qSAM.d.mts} +1 -1
- package/dist/{as-tuple-B3ysbvxB.cjs → as-tuple-CFn7aZYt.cjs} +5 -1
- package/dist/{as-tuple-CeJWgP6l.mjs → as-tuple-CJXpGGKj.mjs} +5 -1
- package/dist/as-tuple.cjs +1 -1
- package/dist/as-tuple.d.cts +1 -1
- package/dist/as-tuple.d.mts +1 -1
- package/dist/as-tuple.mjs +1 -1
- package/dist/{as-tuple.vue-WN7k43tv.d.mts → as-tuple.vue-BDwz5FeN.d.mts} +1 -1
- package/dist/{as-tuple.vue-cy0ThAGl.d.cts → as-tuple.vue-DZ2Soqyw.d.cts} +1 -1
- package/dist/{as-union-Djhjo69H.cjs → as-union-BDRNBacb.cjs} +4 -0
- package/dist/{as-union-BPlYyGVk.mjs → as-union-DZWgGqqM.mjs} +4 -0
- package/dist/as-union.cjs +1 -1
- package/dist/as-union.d.cts +1 -1
- package/dist/as-union.d.mts +1 -1
- package/dist/as-union.mjs +1 -1
- package/dist/{as-union.vue-AqH35ozq.d.cts → as-union.vue-D9Mh0M3_.d.mts} +1 -1
- package/dist/{as-union.vue-Ew3Bany8.d.mts → as-union.vue-DQKWNuhd.d.cts} +1 -1
- package/dist/index.cjs +22 -22
- package/dist/index.d.cts +24 -1081
- package/dist/index.d.mts +24 -1081
- package/dist/index.mjs +22 -22
- package/dist/{types-BYfe1QEF.d.cts → types-B8aPXWL5.d.cts} +13 -0
- package/dist/{types-CV9ss4UN.d.mts → types-nuUi10Kl.d.mts} +13 -0
- package/dist/{use-as-date-XLE8HBbo.mjs → use-as-date-B6RGkjjB.mjs} +4 -0
- package/dist/{use-as-date-DY8b1_V4.cjs → use-as-date-CslHBPmQ.cjs} +4 -0
- package/package.json +9 -9
- package/dist/as-form.vue-2NZSk1F9.d.mts +0 -285
- package/dist/as-form.vue-Dg_5GYWG.d.cts +0 -285
|
@@ -0,0 +1,1425 @@
|
|
|
1
|
+
import { c as TAsUnionContext, n as TAsChangeType, o as TAsComponentProps, s as TAsTypeComponents } from "./types-nuUi10Kl.mjs";
|
|
2
|
+
import * as vue from "vue";
|
|
3
|
+
import { Component, ComputedRef, MaybeRef, Ref, ShallowRef, WritableComputedRef } from "vue";
|
|
4
|
+
import * as _atscript_ui0 from "@atscript/ui";
|
|
5
|
+
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, ValueHelpInfo, getDefaultClientFactory, resetDefaultClientFactory, setDefaultClientFactory } from "@atscript/ui";
|
|
6
|
+
//#region ../../node_modules/.pnpm/@atscript+typescript@0.1.78_@atscript+core@0.1.78_@emnapi+core@1.10.0_@emnapi+runtime@1_be14c480978dbacf288a9776effe0cc5/node_modules/@atscript/typescript/dist/utils.d.ts
|
|
7
|
+
interface TError {
|
|
8
|
+
path: string;
|
|
9
|
+
message: string;
|
|
10
|
+
details?: TError[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A plugin function that can intercept validation.
|
|
14
|
+
*
|
|
15
|
+
* Return `true` to accept the value, `false` to reject it,
|
|
16
|
+
* or `undefined` to fall through to the default validation.
|
|
17
|
+
*/
|
|
18
|
+
type TValidatorPlugin = (ctx: TValidatorPluginContext, def: TAtscriptAnnotatedType, value: any) => boolean | undefined;
|
|
19
|
+
/** Options for configuring {@link Validator} behavior. */
|
|
20
|
+
interface TValidatorOptions {
|
|
21
|
+
partial: boolean | 'deep' | ((type: TAtscriptAnnotatedType<TAtscriptTypeObject>, path: string) => boolean);
|
|
22
|
+
replace?: (type: TAtscriptAnnotatedType, path: string) => TAtscriptAnnotatedType;
|
|
23
|
+
plugins: TValidatorPlugin[];
|
|
24
|
+
unknownProps: 'strip' | 'ignore' | 'error';
|
|
25
|
+
errorLimit: number;
|
|
26
|
+
skipList?: Set<string>;
|
|
27
|
+
}
|
|
28
|
+
/** Context exposed to {@link TValidatorPlugin} functions. */
|
|
29
|
+
interface TValidatorPluginContext {
|
|
30
|
+
opts: Validator<any>['opts'];
|
|
31
|
+
validateAnnotatedType: Validator<any>['validateAnnotatedType'];
|
|
32
|
+
error: Validator<any>['error'];
|
|
33
|
+
path: Validator<any>['path'];
|
|
34
|
+
context: unknown;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validates values against an {@link TAtscriptAnnotatedType} definition.
|
|
38
|
+
*
|
|
39
|
+
* `DataType` is automatically inferred from the type definition's phantom generic,
|
|
40
|
+
* enabling the {@link validate} method to act as a type guard.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // From a generated interface class:
|
|
45
|
+
* const validator = new Validator(MyInterface)
|
|
46
|
+
* if (validator.validate(data, true)) {
|
|
47
|
+
* data // narrowed to MyInterface
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* // Or use the built-in factory:
|
|
51
|
+
* MyInterface.validator().validate(data)
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @typeParam T - The annotated type definition.
|
|
55
|
+
* @typeParam DataType - The TypeScript type that `validate` narrows to (auto-inferred).
|
|
56
|
+
*/
|
|
57
|
+
declare class Validator<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType, DataType = TAtscriptDataType<T>> {
|
|
58
|
+
protected readonly def: T;
|
|
59
|
+
protected opts: TValidatorOptions;
|
|
60
|
+
protected hasPlugins: boolean;
|
|
61
|
+
protected hasReplace: boolean;
|
|
62
|
+
private replaceCache?;
|
|
63
|
+
constructor(def: T, opts?: Partial<TValidatorOptions>);
|
|
64
|
+
/** Validation errors collected during the last {@link validate} call. */
|
|
65
|
+
errors: TError[];
|
|
66
|
+
protected stackErrors: Array<TError[] | null>;
|
|
67
|
+
protected pathSegments: string[];
|
|
68
|
+
protected depth: number;
|
|
69
|
+
protected limitExceeded: boolean;
|
|
70
|
+
protected context: unknown;
|
|
71
|
+
protected buildPath(): string;
|
|
72
|
+
protected push(name: string): void;
|
|
73
|
+
protected pop(saveErrors: boolean): TError[] | null | undefined;
|
|
74
|
+
protected clear(): void;
|
|
75
|
+
protected error(message: string, path?: string, details?: TError[]): void;
|
|
76
|
+
protected throw(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Validates a value against the type definition.
|
|
79
|
+
*
|
|
80
|
+
* Acts as a TypeScript type guard — when it returns `true`, the value
|
|
81
|
+
* is narrowed to `DataType`.
|
|
82
|
+
*
|
|
83
|
+
* @param value - The value to validate.
|
|
84
|
+
* @param safe - If `true`, returns `false` on failure instead of throwing.
|
|
85
|
+
* @returns `true` if the value matches the type definition.
|
|
86
|
+
* @throws {ValidatorError} When validation fails and `safe` is not `true`.
|
|
87
|
+
*/
|
|
88
|
+
validate<TT = DataType>(value: any, safe?: boolean, context?: unknown): value is TT;
|
|
89
|
+
protected validateSafe(def: TAtscriptAnnotatedType, value: any): boolean;
|
|
90
|
+
protected get path(): string;
|
|
91
|
+
protected validateAnnotatedType(def: TAtscriptAnnotatedType, value: any): boolean;
|
|
92
|
+
protected validateUnion(def: TAtscriptAnnotatedType<TAtscriptTypeComplex>, value: any): boolean;
|
|
93
|
+
protected validateIntersection(def: TAtscriptAnnotatedType<TAtscriptTypeComplex>, value: any): boolean;
|
|
94
|
+
protected validateTuple(def: TAtscriptAnnotatedType<TAtscriptTypeComplex>, value: any): boolean;
|
|
95
|
+
protected validateArray(def: TAtscriptAnnotatedType<TAtscriptTypeArray>, value: any): boolean;
|
|
96
|
+
protected validateObject(def: TAtscriptAnnotatedType<TAtscriptTypeObject>, value: any): boolean;
|
|
97
|
+
protected validatePrimitive(def: TAtscriptAnnotatedType<TAtscriptTypeFinal>, value: any): boolean;
|
|
98
|
+
protected validateString(def: TAtscriptAnnotatedType<TAtscriptTypeFinal>, value: string): boolean;
|
|
99
|
+
protected validateNumber(def: TAtscriptAnnotatedType<TAtscriptTypeFinal>, value: number): boolean;
|
|
100
|
+
protected validateBoolean(def: TAtscriptAnnotatedType<TAtscriptTypeFinal>, value: boolean): boolean;
|
|
101
|
+
}
|
|
102
|
+
/** Error thrown by {@link Validator.validate} when validation fails. Contains structured error details. */
|
|
103
|
+
/** Type definition for union, intersection, or tuple types. */
|
|
104
|
+
interface TAtscriptTypeComplex<DataType = unknown> {
|
|
105
|
+
kind: 'union' | 'intersection' | 'tuple';
|
|
106
|
+
items: TAtscriptAnnotatedType[];
|
|
107
|
+
tags: Set<AtscriptPrimitiveTags>;
|
|
108
|
+
/** @internal phantom — carries the DataType at the type level, never set at runtime */
|
|
109
|
+
__dataType?: DataType;
|
|
110
|
+
}
|
|
111
|
+
/** Type definition for array types. */
|
|
112
|
+
interface TAtscriptTypeArray<DataType = unknown[]> {
|
|
113
|
+
kind: 'array';
|
|
114
|
+
of: TAtscriptAnnotatedType;
|
|
115
|
+
tags: Set<AtscriptPrimitiveTags>;
|
|
116
|
+
/** @internal phantom — carries the DataType at the type level, never set at runtime */
|
|
117
|
+
__dataType?: DataType;
|
|
118
|
+
}
|
|
119
|
+
/** Type definition for object types with named and pattern-matched properties. */
|
|
120
|
+
interface TAtscriptTypeObject<K extends string = string, DataType = Record<K, unknown>> {
|
|
121
|
+
kind: 'object';
|
|
122
|
+
props: Map<K, TAtscriptAnnotatedType>;
|
|
123
|
+
propsPatterns: Array<{
|
|
124
|
+
pattern: RegExp;
|
|
125
|
+
def: TAtscriptAnnotatedType;
|
|
126
|
+
}>;
|
|
127
|
+
tags: Set<AtscriptPrimitiveTags>;
|
|
128
|
+
/** @internal phantom — carries the DataType at the type level, never set at runtime */
|
|
129
|
+
__dataType?: DataType;
|
|
130
|
+
}
|
|
131
|
+
/** Type definition for primitive/literal types (string, number, boolean, null, etc.). */
|
|
132
|
+
interface TAtscriptTypeFinal<DataType = unknown> {
|
|
133
|
+
kind: '';
|
|
134
|
+
/**
|
|
135
|
+
* design type
|
|
136
|
+
*/
|
|
137
|
+
designType: 'string' | 'number' | 'boolean' | 'undefined' | 'null' | 'object' | 'any' | 'never' | 'phantom' | 'decimal';
|
|
138
|
+
/**
|
|
139
|
+
* value for literals
|
|
140
|
+
*/
|
|
141
|
+
value?: string | number | boolean;
|
|
142
|
+
tags: Set<AtscriptPrimitiveTags>;
|
|
143
|
+
/** @internal phantom — carries the DataType at the type level, never set at runtime */
|
|
144
|
+
__dataType?: DataType;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Extract DataType from a type def's phantom generic
|
|
148
|
+
*/
|
|
149
|
+
type InferDataType<T> = T extends {
|
|
150
|
+
__dataType?: infer D;
|
|
151
|
+
} ? D : unknown;
|
|
152
|
+
/**
|
|
153
|
+
* Extract the DataType from a {@link TAtscriptAnnotatedType}.
|
|
154
|
+
*
|
|
155
|
+
* Resolves the phantom `__dataType` carried by the type definition.
|
|
156
|
+
* When `__dataType` is `unknown` (unset), falls back to the constructor
|
|
157
|
+
* instance type if `T` is also a class (i.e. a generated interface).
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* import type { TAtscriptDataType } from '@atscript/typescript/utils'
|
|
162
|
+
* import MyInterface from './my-interface.as'
|
|
163
|
+
*
|
|
164
|
+
* type Data = TAtscriptDataType<typeof MyInterface>
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
type TAtscriptDataType<T extends TAtscriptAnnotatedType = TAtscriptAnnotatedType> = T extends {
|
|
168
|
+
type: {
|
|
169
|
+
__dataType?: infer D;
|
|
170
|
+
};
|
|
171
|
+
} ? unknown extends D ? T extends (new (...args: any[]) => infer I) ? I : unknown : D : unknown;
|
|
172
|
+
/** Union of all possible type definition shapes. */
|
|
173
|
+
type TAtscriptTypeDef<DataType = unknown> = TAtscriptTypeComplex<DataType> | TAtscriptTypeFinal<DataType> | TAtscriptTypeArray<DataType> | TAtscriptTypeObject<string, DataType>;
|
|
174
|
+
/**
|
|
175
|
+
* Core annotated type — wraps a type definition with metadata and a validator factory.
|
|
176
|
+
*
|
|
177
|
+
* Generated `.as` files produce classes/namespaces that conform to this interface.
|
|
178
|
+
* The `DataType` phantom generic carries the TypeScript data shape for type-safe validation.
|
|
179
|
+
*
|
|
180
|
+
* @typeParam T - The underlying type definition (e.g. {@link TAtscriptTypeObject}).
|
|
181
|
+
* @typeParam DataType - The TypeScript type the validated data narrows to (auto-inferred from `T`).
|
|
182
|
+
*/
|
|
183
|
+
interface TAtscriptAnnotatedType<T extends TAtscriptTypeDef = TAtscriptTypeDef, DataType = InferDataType<T>> {
|
|
184
|
+
__is_atscript_annotated_type: true;
|
|
185
|
+
type: T;
|
|
186
|
+
validator(opts?: Partial<TValidatorOptions>): Validator<this, DataType>;
|
|
187
|
+
metadata: TMetadataMap<AtscriptMetadata>;
|
|
188
|
+
optional?: boolean;
|
|
189
|
+
id?: string;
|
|
190
|
+
ref?: {
|
|
191
|
+
type: () => TAtscriptAnnotatedType;
|
|
192
|
+
field: string;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/** An annotated type that is also a class constructor (i.e. a generated interface class). */
|
|
196
|
+
/**
|
|
197
|
+
* Atscript Metadata Map with typed setters/getters
|
|
198
|
+
*/
|
|
199
|
+
interface TMetadataMap<O extends object> extends Map<keyof O, O[keyof O]> {
|
|
200
|
+
get<K extends keyof O>(key: K): O[K] | undefined;
|
|
201
|
+
get(key: string): unknown;
|
|
202
|
+
set<K extends keyof O>(key: K, value: O[K]): this;
|
|
203
|
+
has<K extends keyof O>(key: K): boolean;
|
|
204
|
+
has(key: string): boolean;
|
|
205
|
+
}
|
|
206
|
+
/** Fluent builder handle returned by {@link defineAnnotatedType}. */
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/composables/create-as-form-def.d.ts
|
|
209
|
+
/**
|
|
210
|
+
* Creates a reactive form definition and data object from an ATScript annotated type.
|
|
211
|
+
*
|
|
212
|
+
* @param type - An ATScript annotated type (imported from a `.as` file).
|
|
213
|
+
* @param context - Optional context object forwarded to `ui.fn.value` resolvers during data creation.
|
|
214
|
+
* Only effective when `@atscript/ui-fns` is installed (dynamic resolver).
|
|
215
|
+
* @returns `{ def, formData }` — the FormDef and a Vue reactive data object with defaults applied
|
|
216
|
+
*/
|
|
217
|
+
declare function createAsFormDef<T extends TAtscriptAnnotatedType>(type: T, context?: Record<string, unknown>): {
|
|
218
|
+
def: _atscript_ui0.FormDef;
|
|
219
|
+
formData: {
|
|
220
|
+
value: vue.UnwrapRef<TAtscriptDataType<T>>;
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/composables/create-default-types.d.ts
|
|
225
|
+
/**
|
|
226
|
+
* Returns a fresh type-to-component map pre-filled with all built-in defaults.
|
|
227
|
+
*
|
|
228
|
+
* Spread or assign additional entries to extend with custom field types:
|
|
229
|
+
* ```ts
|
|
230
|
+
* const types = { ...createDefaultTypes(), rating: MyRatingComponent }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
declare function createDefaultTypes(): TAsTypeComponents;
|
|
234
|
+
//#endregion
|
|
235
|
+
//#region src/composables/types.d.ts
|
|
236
|
+
type TFormRule<TValue, TFormData, TContext> = (v: TValue, data?: TFormData, context?: TContext) => boolean | string;
|
|
237
|
+
interface TFormFieldCallbacks {
|
|
238
|
+
validate: () => boolean | string;
|
|
239
|
+
clearErrors: () => void;
|
|
240
|
+
reset: () => void;
|
|
241
|
+
setExternalError: (msg?: string) => void;
|
|
242
|
+
}
|
|
243
|
+
interface TFormFieldRegistration {
|
|
244
|
+
path: () => string;
|
|
245
|
+
callbacks: TFormFieldCallbacks;
|
|
246
|
+
}
|
|
247
|
+
interface TFormState {
|
|
248
|
+
firstSubmitHappened: boolean;
|
|
249
|
+
firstValidation: "on-change" | "touched-on-blur" | "on-blur" | "on-submit" | "none";
|
|
250
|
+
/**
|
|
251
|
+
* Fields registered AFTER `firstSubmitHappened` flipped to true. They stay
|
|
252
|
+
* in this set until either the user edits the field (model watch removes
|
|
253
|
+
* the id) or the next submit fires (set is cleared). Live validation is
|
|
254
|
+
* suppressed for these fields so a freshly-added array item doesn't render
|
|
255
|
+
* red required-field errors before the user has had a chance to type.
|
|
256
|
+
*/
|
|
257
|
+
freshFields: Set<symbol>;
|
|
258
|
+
register: (id: symbol, registration: TFormFieldRegistration) => void;
|
|
259
|
+
unregister: (id: symbol) => void;
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/composables/use-as-field.d.ts
|
|
263
|
+
interface UseAsFieldOptions<TValue = any, TFormData = any, TContext = any> {
|
|
264
|
+
getValue: () => TValue;
|
|
265
|
+
setValue: (v: TValue) => void;
|
|
266
|
+
rules?: TFormRule<TValue, TFormData, TContext>[];
|
|
267
|
+
path: () => string;
|
|
268
|
+
/** Value to set on reset. Defaults to `''`. Use `[]` for arrays, `{}` for objects. */
|
|
269
|
+
resetValue?: TValue;
|
|
270
|
+
}
|
|
271
|
+
interface UseAsFieldReturn<TValue = any> {
|
|
272
|
+
model: WritableComputedRef<TValue>;
|
|
273
|
+
error: ComputedRef<string | undefined>;
|
|
274
|
+
onBlur: () => void;
|
|
275
|
+
/**
|
|
276
|
+
* Reactive "changed-since-baseline" flag for THIS field. `true` when the
|
|
277
|
+
* form has `track-changes` enabled AND the field at `opts.path()` differs
|
|
278
|
+
* from the tracker's baseline. Recomputes whenever the change list does
|
|
279
|
+
* (delegates to the injected {@link AsFormPatchHandle.isDirtyPath}).
|
|
280
|
+
*
|
|
281
|
+
* Always `false` when tracking is off (no patch handle injected) — the
|
|
282
|
+
* handle is injected OPTIONALLY, so reading `isDirty` never throws.
|
|
283
|
+
* Granularity matches the change list: object/section containers light up
|
|
284
|
+
* via their leaves' prefix, whole-array fields via exact match; an
|
|
285
|
+
* array-ITEM leaf stays `false` (the array container lights up instead).
|
|
286
|
+
*/
|
|
287
|
+
isDirty: ComputedRef<boolean>;
|
|
288
|
+
}
|
|
289
|
+
declare function useAsField<TValue = any, TFormData = any, TContext = any>(opts: UseAsFieldOptions<TValue, TFormData, TContext>): UseAsFieldReturn<TValue>;
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/composables/use-as-state.d.ts
|
|
292
|
+
/** Custom form-level validator. Returns `Record<path, message>` (empty = passed). */
|
|
293
|
+
type TFormSubmitValidator = () => Record<string, string>;
|
|
294
|
+
interface UseAsStateReturn {
|
|
295
|
+
formState: TFormState;
|
|
296
|
+
clearErrors: () => void;
|
|
297
|
+
reset: () => Promise<void>;
|
|
298
|
+
submit: () => true | {
|
|
299
|
+
path: string;
|
|
300
|
+
message: string;
|
|
301
|
+
}[];
|
|
302
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
303
|
+
}
|
|
304
|
+
declare function useAsState<TFormData, TContext>(opts: {
|
|
305
|
+
formData: MaybeRef<TFormData>;
|
|
306
|
+
formContext?: MaybeRef<TContext>;
|
|
307
|
+
firstValidation?: MaybeRef<TFormState["firstValidation"] | undefined>; /** When provided, replaces per-field iteration on submit. */
|
|
308
|
+
submitValidator?: TFormSubmitValidator;
|
|
309
|
+
}): UseAsStateReturn;
|
|
310
|
+
//#endregion
|
|
311
|
+
//#region src/composables/use-as-form-patch.d.ts
|
|
312
|
+
/**
|
|
313
|
+
* Result of {@link AsFormPatchHandle.rebaseOnto}. Aliases the `@atscript/ui`
|
|
314
|
+
* rebase shape (minus `next`, which is written into the live container rather
|
|
315
|
+
* than returned): the surviving local diff on top of the NEW baseline plus the
|
|
316
|
+
* conflict paths.
|
|
317
|
+
*/
|
|
318
|
+
interface RebaseOntoResult {
|
|
319
|
+
/** Paths changed on both sides to different values, plus ancestor-clear paths. */
|
|
320
|
+
conflicts: string[];
|
|
321
|
+
/** Local edits that survive on top of the new (upstream) baseline. */
|
|
322
|
+
reapplied: FormFieldChange[];
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Change-tracking handle for a single `<AsForm>`. Exposed three ways:
|
|
326
|
+
*
|
|
327
|
+
* 1. injected via {@link useAsFormPatch} inside any descendant component,
|
|
328
|
+
* 2. spread into every `<AsForm>` slot (`isDirty` / `changes` / `getPatch` /
|
|
329
|
+
* `getChanges` — so a footer slot can gate a Save button), and
|
|
330
|
+
* 3. `defineExpose`d on `<AsForm>` (so a parent template ref can call
|
|
331
|
+
* `asForm.value.getPatch()`).
|
|
332
|
+
*
|
|
333
|
+
* Built on `@atscript/ui`'s `buildFormDiff`, which diffs the form's CURRENT
|
|
334
|
+
* data against a BASELINE snapshot and produces both a per-field change list
|
|
335
|
+
* and an `@atscript/db` patch object (keyed-array `$update`/`$insert`/`$remove`,
|
|
336
|
+
* `$cas` optimistic-concurrency sibling, revert-aware).
|
|
337
|
+
*/
|
|
338
|
+
interface AsFormPatchHandle {
|
|
339
|
+
/**
|
|
340
|
+
* Reactive dirtiness — `true` when current data differs from the baseline.
|
|
341
|
+
* Revert-aware: a value edited back to its baseline flips this back to
|
|
342
|
+
* `false`. Memoised by Vue; recomputes only when the form data changes.
|
|
343
|
+
*/
|
|
344
|
+
isDirty: ComputedRef<boolean>;
|
|
345
|
+
/**
|
|
346
|
+
* Reactive per-field change list (revert-aware — reverted fields drop out).
|
|
347
|
+
* `before` / `after` hold live references into the baseline / current data.
|
|
348
|
+
*/
|
|
349
|
+
changes: ComputedRef<FormFieldChange[]>;
|
|
350
|
+
/**
|
|
351
|
+
* Builds the `@atscript/db` patch object on demand against the baseline
|
|
352
|
+
* snapshot. Safe to call at submit time (a fresh re-snapshot point). Returns
|
|
353
|
+
* `{}` when nothing changed. Carries a top-level `$cas` sibling when the form
|
|
354
|
+
* has a `@db.column.version` column and `opts.cas` is on (default).
|
|
355
|
+
*/
|
|
356
|
+
getPatch: (opts?: FormDiffOptions) => Record<string, unknown>;
|
|
357
|
+
/** Builds the per-field change list on demand (same data as `changes`). */
|
|
358
|
+
getChanges: () => FormFieldChange[];
|
|
359
|
+
/**
|
|
360
|
+
* Reactive per-field dirty predicate. `true` when the field at the dot-path
|
|
361
|
+
* `path` differs from the baseline. Reads the reactive {@link changes} list,
|
|
362
|
+
* so a per-field `isDirty` derived from this recomputes whenever the change
|
|
363
|
+
* list does.
|
|
364
|
+
*
|
|
365
|
+
* Granularity matches the change list (leaf-grained for scalars/objects,
|
|
366
|
+
* WHOLE-ARRAY for arrays): a field is dirty iff some change path equals
|
|
367
|
+
* `path` OR starts with `path + "."`. Object/section containers light up via
|
|
368
|
+
* the prefix branch; whole-array fields via exact match; an array-ITEM leaf
|
|
369
|
+
* (e.g. `items.0.qty`) returns `false` (the array container lights up
|
|
370
|
+
* instead — a known, documented limitation of the array diff). The empty
|
|
371
|
+
* root path `''` is dirty iff there are ANY changes. Backed by an O(1)
|
|
372
|
+
* `Set.has` against `@atscript/ui`'s `collectDirtyPaths` precompute, whose
|
|
373
|
+
* membership matches `isPathDirty` exactly (locked by an invariant test).
|
|
374
|
+
*/
|
|
375
|
+
isDirtyPath: (path: string) => boolean;
|
|
376
|
+
/**
|
|
377
|
+
* Re-baseline to the current data. Call after a successful save so the form
|
|
378
|
+
* becomes clean again WITHOUT a remount. No-op when tracking is inactive.
|
|
379
|
+
*/
|
|
380
|
+
rebase: () => void;
|
|
381
|
+
/**
|
|
382
|
+
* 3-way rebase onto a fresh upstream snapshot. Sets the baseline to
|
|
383
|
+
* `upstream` and rewrites the live form to `upstream` + the local diff
|
|
384
|
+
* (current vs. old baseline) reapplied on top:
|
|
385
|
+
*
|
|
386
|
+
* - fields the user never touched adopt `upstream`'s value,
|
|
387
|
+
* - local edits survive,
|
|
388
|
+
* - fields changed on both sides to a different value are conflicts, resolved
|
|
389
|
+
* by `opts.conflict` (`'ours'` default keeps local, `'theirs'` takes
|
|
390
|
+
* upstream).
|
|
391
|
+
*
|
|
392
|
+
* `upstream` is the WRAPPED form-data container (`{ value }`). The live form
|
|
393
|
+
* data is rewritten in a SINGLE mutation (the bound `:form-data` container
|
|
394
|
+
* identity is preserved, so the consumer's ref stays the same object). After
|
|
395
|
+
* the write the baseline becomes a deep clone of `upstream`, so a subsequent
|
|
396
|
+
* `getPatch()` carries exactly the surviving local diff (`reapplied`).
|
|
397
|
+
*
|
|
398
|
+
* Returns the conflict paths and the surviving local diff. No-op returning
|
|
399
|
+
* empty when tracking is inactive.
|
|
400
|
+
*/
|
|
401
|
+
rebaseOnto: (upstream: Record<string, unknown>, opts?: FormRebaseOptions) => RebaseOntoResult;
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Reactive read-only access to the form's change-tracking handle from any
|
|
405
|
+
* descendant of an `<AsForm track-changes>`. Mirrors the `useAsData` /
|
|
406
|
+
* `useAsPath` injector pattern.
|
|
407
|
+
*
|
|
408
|
+
* THROWS when called outside a form, or inside a form that did not enable
|
|
409
|
+
* `track-changes` — fail loud rather than silently report "not dirty".
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* ```vue
|
|
413
|
+
* <script setup lang="ts">
|
|
414
|
+
* import { useAsFormPatch } from "@atscript/vue-form";
|
|
415
|
+
* const { isDirty, getPatch } = useAsFormPatch();
|
|
416
|
+
* </script>
|
|
417
|
+
* <template>
|
|
418
|
+
* <button :disabled="!isDirty" @click="save(getPatch())">Save</button>
|
|
419
|
+
* </template>
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
declare function useAsFormPatch(): AsFormPatchHandle;
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/composables/use-as-form.d.ts
|
|
425
|
+
/**
|
|
426
|
+
* Options for {@link useAsForm}. Each reactive prop is supplied as a
|
|
427
|
+
* **getter** so the composable can subscribe to its changes without owning
|
|
428
|
+
* a `Ref`. Pass component-level `defineProps` accessors verbatim:
|
|
429
|
+
*
|
|
430
|
+
* ```ts
|
|
431
|
+
* useAsForm({
|
|
432
|
+
* def: () => props.def,
|
|
433
|
+
* formData: () => props.formData,
|
|
434
|
+
* types: () => props.types,
|
|
435
|
+
* // ...
|
|
436
|
+
* emits: { submit: (data) => emit("submit", data), ... },
|
|
437
|
+
* })
|
|
438
|
+
* ```
|
|
439
|
+
*
|
|
440
|
+
* Generic `TFormData` / `TFormContext` mirror the `<AsForm>` component
|
|
441
|
+
* generics. They flow through to emitted callbacks; if you build a custom
|
|
442
|
+
* form root with a known data shape, pin them at the call site.
|
|
443
|
+
*/
|
|
444
|
+
interface UseAsFormOptions<TFormData = unknown, TFormContext = unknown> {
|
|
445
|
+
/** Form definition produced by `createAsFormDef(type)`. Reactive. */
|
|
446
|
+
def: () => FormDef;
|
|
447
|
+
/**
|
|
448
|
+
* Externally-managed form data container `{ value: domainData }`. When
|
|
449
|
+
* unset, the composable creates an internal one initialized to `{}`.
|
|
450
|
+
*/
|
|
451
|
+
formData?: () => TFormData | undefined;
|
|
452
|
+
/** Reactive form context — exposed to validators, scope, slots, and emits. */
|
|
453
|
+
formContext?: () => TFormContext | undefined;
|
|
454
|
+
/** First-validation strategy. Defaults to `"on-change"`. */
|
|
455
|
+
firstValidation?: () => TFormState["firstValidation"] | undefined;
|
|
456
|
+
/** Custom field components keyed by field name (matches `Props.components`). */
|
|
457
|
+
components?: () => Record<string, Component<TAsComponentProps>> | undefined;
|
|
458
|
+
/** Type-to-component map keyed by field type (matches `Props.types`). */
|
|
459
|
+
types: () => TAsTypeComponents;
|
|
460
|
+
/** Server-supplied errors keyed by absolute dotted path (`__form` for form-level). */
|
|
461
|
+
errors?: () => Record<string, string | undefined> | undefined;
|
|
462
|
+
/** Per-form value-help client factory. Falls back to the app-wide default when unset. */
|
|
463
|
+
clientFactory?: () => ClientFactory | undefined;
|
|
464
|
+
/** Suppress the root field's title (use when the chrome already shows the form's label). */
|
|
465
|
+
hideRootTitle?: () => boolean | undefined;
|
|
466
|
+
/**
|
|
467
|
+
* Busy-state flag. When `true`, the form is locked (inert + overlay) and the
|
|
468
|
+
* default submit button is disabled. `<AsWfForm>` wires this to its
|
|
469
|
+
* server round-trip so consumers can drop their own submit overrides.
|
|
470
|
+
*/
|
|
471
|
+
loading?: () => boolean | undefined;
|
|
472
|
+
/**
|
|
473
|
+
* Enable change tracking. When `true`, the composable captures a deep-clone
|
|
474
|
+
* baseline of the form data (the moment it becomes available) and exposes a
|
|
475
|
+
* {@link AsFormPatchHandle} via `slotProps`, the return value (`patch`), and
|
|
476
|
+
* `provide(FORM_PATCH_KEY)` (read with `useAsFormPatch()`). When falsy
|
|
477
|
+
* (default), there is ZERO overhead — no baseline, no deep watch, and
|
|
478
|
+
* `useAsFormPatch()` throws. Reactive.
|
|
479
|
+
*/
|
|
480
|
+
trackChanges?: () => boolean | undefined;
|
|
481
|
+
/**
|
|
482
|
+
* Outbound callbacks. Customer form roots typically wire these to
|
|
483
|
+
* `defineEmits`; advanced uses can pass plain functions.
|
|
484
|
+
*/
|
|
485
|
+
emits?: {
|
|
486
|
+
submit?: (data: TFormData) => void;
|
|
487
|
+
error?: (errors: {
|
|
488
|
+
path: string;
|
|
489
|
+
message: string;
|
|
490
|
+
}[]) => void;
|
|
491
|
+
action?: (name: string, data: TFormData) => void;
|
|
492
|
+
unsupportedAction?: (name: string, data: TFormData) => void;
|
|
493
|
+
change?: (type: TAsChangeType, path: string, value: unknown, formData: TFormData) => void;
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
interface UseAsFormReturn<TFormData = unknown, TFormContext = unknown> {
|
|
497
|
+
/** Reactive form-data container `{ value: domainData }`. */
|
|
498
|
+
data: ComputedRef<TFormData>;
|
|
499
|
+
/** Effective external errors (post-dismissal), excluding `__form`. */
|
|
500
|
+
errors: ComputedRef<Record<string, string | undefined> | undefined>;
|
|
501
|
+
/** Form-level error message (post banner-dismissal). */
|
|
502
|
+
formError: ComputedRef<string | undefined>;
|
|
503
|
+
/** Errors discovered by the local validator on the most-recent submit. */
|
|
504
|
+
internalErrors: Ref<Record<string, string>>;
|
|
505
|
+
/**
|
|
506
|
+
* Reset internal validator + dismissal state and re-run field defaults. When
|
|
507
|
+
* `trackChanges` is enabled, also re-baselines the change tracker to the
|
|
508
|
+
* post-reset state (the form becomes clean again).
|
|
509
|
+
*/
|
|
510
|
+
reset: () => Promise<void>;
|
|
511
|
+
/** Imperatively clear errors (matches `useAsState().clearErrors`). */
|
|
512
|
+
clearErrors: () => void;
|
|
513
|
+
/** Imperatively set external-error messages by path. */
|
|
514
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
515
|
+
/** Trigger submit. Emits `submit` on success and `error` on validation failure. */
|
|
516
|
+
onSubmit: () => void;
|
|
517
|
+
/** Resolved submit-button text (`@ui.form.submit.text` / fn variant). */
|
|
518
|
+
submitText: ComputedRef<string>;
|
|
519
|
+
/** Resolved submit-button disabled state (`@ui.form.fn.submitDisabled`). */
|
|
520
|
+
submitDisabled: ComputedRef<boolean>;
|
|
521
|
+
/** Resolved form-level title (`@ui.form.fn.title` / `@meta.label`); may be `undefined`. */
|
|
522
|
+
title: ComputedRef<string | undefined>;
|
|
523
|
+
/** Resolved form-level description (`@ui.form.fn.description` / `@meta.description`). */
|
|
524
|
+
description: ComputedRef<string | undefined>;
|
|
525
|
+
/** Unified slot-props bag spread onto every `<AsForm>` slot. */
|
|
526
|
+
slotProps: ComputedRef<{
|
|
527
|
+
title: string | undefined;
|
|
528
|
+
description: string | undefined;
|
|
529
|
+
data: TFormData;
|
|
530
|
+
errors: Record<string, string | undefined> | undefined;
|
|
531
|
+
formError: string | undefined;
|
|
532
|
+
disabled: boolean;
|
|
533
|
+
loading: boolean;
|
|
534
|
+
submitText: string;
|
|
535
|
+
submit: () => void;
|
|
536
|
+
reset: () => Promise<void>;
|
|
537
|
+
clearErrors: () => void;
|
|
538
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
539
|
+
dismissError: (path: string) => void;
|
|
540
|
+
dismissFormError: () => void;
|
|
541
|
+
formContext: TFormContext | undefined; /** True when `track-changes` is on AND data differs from baseline. */
|
|
542
|
+
isDirty: boolean; /** Revert-aware per-field change list (empty when tracking is off). */
|
|
543
|
+
changes: readonly FormFieldChange[]; /** Build the `@atscript/db` patch on demand (`{}` when tracking is off). */
|
|
544
|
+
getPatch: (opts?: FormDiffOptions) => Record<string, unknown>; /** Build the per-field change list on demand (`[]` when tracking is off). */
|
|
545
|
+
getChanges: () => FormFieldChange[]; /** Per-field dirty predicate (`false` for every path when tracking is off). */
|
|
546
|
+
isDirtyPath: (path: string) => boolean;
|
|
547
|
+
}>;
|
|
548
|
+
/**
|
|
549
|
+
* Change-tracking handle — present ONLY when `trackChanges` is enabled.
|
|
550
|
+
* `undefined` otherwise. Read it from descendants with `useAsFormPatch()`.
|
|
551
|
+
*/
|
|
552
|
+
patch: AsFormPatchHandle | undefined;
|
|
553
|
+
/**
|
|
554
|
+
* Remount key for the field subtree. Bound as `:key` on the root `<AsField>`.
|
|
555
|
+
* Bumped by `patch.rebaseOnto` only when a rebase lands a different union
|
|
556
|
+
* variant, forcing the variant picker to re-detect. `0` otherwise.
|
|
557
|
+
*/
|
|
558
|
+
remountKey: Ref<number>;
|
|
559
|
+
/** Dispatch an action — invoked by `<AsAction>`. */
|
|
560
|
+
invokeAction: (name: string) => void;
|
|
561
|
+
/** Dismiss a single external leaf error. */
|
|
562
|
+
dismissError: (path: string) => void;
|
|
563
|
+
/** Dismiss the form-level banner. */
|
|
564
|
+
dismissFormError: () => void;
|
|
565
|
+
/** Form-context getter (mirrors `options.formContext()`). */
|
|
566
|
+
formContext: ComputedRef<TFormContext | undefined>;
|
|
567
|
+
/** Internal change-dispatcher used by `<AsField>` and structured components. */
|
|
568
|
+
handleChange: (type: TAsChangeType, path: string, value: unknown) => void;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Composable backing `<AsForm>`. Owns the entire form state machine —
|
|
572
|
+
* data container, internal validator, external-error dismissal, action
|
|
573
|
+
* routing, change merging, descendant counts, auto-open, and all
|
|
574
|
+
* provide/inject wiring. Customers building a custom form root can
|
|
575
|
+
* call this directly and render their own `<form>` template.
|
|
576
|
+
*
|
|
577
|
+
* MUST be called from a component's `<script setup>` (it issues
|
|
578
|
+
* `provide()` calls that need an active component instance).
|
|
579
|
+
*/
|
|
580
|
+
declare function useAsForm<TFormData = unknown, TFormContext = unknown>(options: UseAsFormOptions<TFormData, TFormContext>): UseAsFormReturn<TFormData, TFormContext>;
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/composables/use-as-external-errors.d.ts
|
|
583
|
+
/**
|
|
584
|
+
* Source of externally-supplied (server) errors. Reading this getter
|
|
585
|
+
* inside a Vue reactive scope subscribes the composable to identity
|
|
586
|
+
* changes — when the source returns a *different* object reference
|
|
587
|
+
* (typically a fresh server response), all locally-applied dismissals
|
|
588
|
+
* reset automatically.
|
|
589
|
+
*/
|
|
590
|
+
interface UseAsExternalErrorsOptions {
|
|
591
|
+
source: () => Record<string, string | undefined> | undefined;
|
|
592
|
+
}
|
|
593
|
+
interface UseAsExternalErrorsReturn {
|
|
594
|
+
/**
|
|
595
|
+
* Errors map after leaf-path dismissals applied. The `__form` key is
|
|
596
|
+
* always omitted — render form-level errors via `formError`. Returns
|
|
597
|
+
* `undefined` when the source itself is `undefined` (no errors at all),
|
|
598
|
+
* so consumers can preserve the original "errors prop unset" semantics.
|
|
599
|
+
*/
|
|
600
|
+
effective: ComputedRef<Record<string, string | undefined> | undefined>;
|
|
601
|
+
/** Top-level `__form` error (post banner-dismissal). `undefined` while dismissed or absent. */
|
|
602
|
+
formError: ComputedRef<string | undefined>;
|
|
603
|
+
/** Whether the form-level banner is currently dismissed. */
|
|
604
|
+
isFormDismissed: ComputedRef<boolean>;
|
|
605
|
+
/** Mark a leaf-field path as dismissed locally. Idempotent. */
|
|
606
|
+
dismissAt: (path: string) => void;
|
|
607
|
+
/** Dismiss the form-level banner. */
|
|
608
|
+
dismissForm: () => void;
|
|
609
|
+
/** Reset all dismissals (rarely needed; identity-change does this for you). */
|
|
610
|
+
reset: () => void;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Local dismissal state for externally-supplied errors.
|
|
614
|
+
*
|
|
615
|
+
* - `dismissAt(path)` hides a leaf error until either the user un-dismisses
|
|
616
|
+
* it or a *fresh* errors object arrives (new identity).
|
|
617
|
+
* - `dismissForm()` hides the `__form` banner. Same identity-reset rule, but
|
|
618
|
+
* never cleared by leaf calls.
|
|
619
|
+
* - In-place mutation of the source object does NOT reset dismissals; only
|
|
620
|
+
* identity changes do. A fresh response (`errors.value = { ... }`) re-arms
|
|
621
|
+
* everything, while in-place tweaks (rare) deliberately preserve them.
|
|
622
|
+
*
|
|
623
|
+
* The composable is pure — it does NOT call `provide()`. The owning form
|
|
624
|
+
* composable wires `dismissAt` into the form's inject contract.
|
|
625
|
+
*/
|
|
626
|
+
declare function useAsExternalErrors(options: UseAsExternalErrorsOptions): UseAsExternalErrorsReturn;
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/composables/use-as-array.d.ts
|
|
629
|
+
interface UseAsArrayReturn {
|
|
630
|
+
arrayValue: ComputedRef<unknown[]>;
|
|
631
|
+
itemKeys: string[];
|
|
632
|
+
isUnion: boolean;
|
|
633
|
+
unionVariants: FormUnionVariant[];
|
|
634
|
+
isOptional: boolean;
|
|
635
|
+
isEmpty: ComputedRef<boolean>;
|
|
636
|
+
getItemField: (index: number, name?: string) => FormFieldDef;
|
|
637
|
+
addItem: (variantIndex?: number) => void;
|
|
638
|
+
removeItem: (index: number) => void;
|
|
639
|
+
clear: () => void;
|
|
640
|
+
canAdd: ComputedRef<boolean>;
|
|
641
|
+
canRemove: ComputedRef<boolean>;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Composable for managing array field state.
|
|
645
|
+
*
|
|
646
|
+
* Manages stable keys, add/remove with constraints, and item field resolution.
|
|
647
|
+
* Union item types are handled transparently — AsUnion manages variant state locally.
|
|
648
|
+
* Used by the default `AsArray` component and available for custom array components.
|
|
649
|
+
*/
|
|
650
|
+
declare function useAsArray(field: FormArrayFieldDef, disabled?: ComputedRef<boolean>): UseAsArrayReturn;
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/composables/use-as-tuple.d.ts
|
|
653
|
+
interface UseAsTupleReturn {
|
|
654
|
+
itemFields: FormFieldDef[];
|
|
655
|
+
positionLabeled: boolean[];
|
|
656
|
+
isOptional: boolean;
|
|
657
|
+
isEmpty: ComputedRef<boolean>;
|
|
658
|
+
clear: () => void;
|
|
659
|
+
fillMissing: () => void;
|
|
660
|
+
}
|
|
661
|
+
/** Composable for managing tuple field state. Fixed-length, position-typed; auto-fills missing positions on mount unless optional. */
|
|
662
|
+
declare function useAsTuple(field: FormTupleFieldDef): UseAsTupleReturn;
|
|
663
|
+
//#endregion
|
|
664
|
+
//#region src/composables/use-as-union.d.ts
|
|
665
|
+
interface UseAsUnionReturn {
|
|
666
|
+
unionField: ComputedRef<FormUnionFieldDef | undefined>;
|
|
667
|
+
hasMultipleVariants: ComputedRef<boolean>;
|
|
668
|
+
localUnionIndex: Ref<number>;
|
|
669
|
+
innerField: ComputedRef<FormFieldDef | undefined>;
|
|
670
|
+
changeVariant: (newIndex: number) => void;
|
|
671
|
+
optionalEnabled: ComputedRef<boolean>;
|
|
672
|
+
}
|
|
673
|
+
/** Composable for union field state. Switching variants stashes per-index data so toggling back restores user's work instead of fresh defaults. */
|
|
674
|
+
declare function useAsUnion(props: TAsComponentProps): UseAsUnionReturn;
|
|
675
|
+
//#endregion
|
|
676
|
+
//#region src/composables/use-form-context.d.ts
|
|
677
|
+
/**
|
|
678
|
+
* Consume and clear the union context injection.
|
|
679
|
+
*
|
|
680
|
+
* Structured components (object, tuple, array, field-shell) call this to
|
|
681
|
+
* read the union context provided by `AsUnion` and immediately clear it
|
|
682
|
+
* so nested children don't inherit it.
|
|
683
|
+
*/
|
|
684
|
+
declare function useAsUnionVariant(): TAsUnionContext | undefined;
|
|
685
|
+
/** Split a label into base + optional `#N` suffix for two-part rendering. */
|
|
686
|
+
declare function formatIndexedLabelParts(label: string | undefined, arrayIndex: number | undefined): {
|
|
687
|
+
base: string;
|
|
688
|
+
suffix?: string;
|
|
689
|
+
} | undefined;
|
|
690
|
+
//#endregion
|
|
691
|
+
//#region src/composables/use-as-value-help.d.ts
|
|
692
|
+
interface UseAsValueHelpOptions {
|
|
693
|
+
info: ValueHelpInfo;
|
|
694
|
+
model: {
|
|
695
|
+
value: unknown;
|
|
696
|
+
};
|
|
697
|
+
onBlur: () => void;
|
|
698
|
+
}
|
|
699
|
+
type UseAsValueHelpStatus = "loading" | "ready" | "error";
|
|
700
|
+
interface UseAsValueHelpReturn {
|
|
701
|
+
resolved: ShallowRef<ResolvedValueHelp | null>;
|
|
702
|
+
status: Ref<UseAsValueHelpStatus>;
|
|
703
|
+
searchText: Ref<string>;
|
|
704
|
+
results: ShallowRef<Record<string, unknown>[]>;
|
|
705
|
+
searching: Ref<boolean>;
|
|
706
|
+
labelIsFkValue: ComputedRef<boolean>;
|
|
707
|
+
kickoff: () => Promise<void>;
|
|
708
|
+
selectItem: (item: Record<string, unknown>) => void;
|
|
709
|
+
clear: () => void;
|
|
710
|
+
}
|
|
711
|
+
declare function useAsValueHelp(options: UseAsValueHelpOptions): UseAsValueHelpReturn;
|
|
712
|
+
//#endregion
|
|
713
|
+
//#region src/composables/use-as-dropdown.d.ts
|
|
714
|
+
declare function useAsDropdown(containerRef: Ref<HTMLElement | null>): {
|
|
715
|
+
isOpen: Ref<boolean, boolean>;
|
|
716
|
+
toggle: () => void;
|
|
717
|
+
close: () => void;
|
|
718
|
+
select: (callback: () => void) => void;
|
|
719
|
+
};
|
|
720
|
+
//#endregion
|
|
721
|
+
//#region src/composables/use-as-nested-sections-store.d.ts
|
|
722
|
+
/**
|
|
723
|
+
* Reactive open/closed registry for collapsible object sections rendered
|
|
724
|
+
* by `AsObject`. Provided once per `<AsForm>` so the entire form shares a
|
|
725
|
+
* single store; consumers (page chrome, devtools, dialogs) can `inject`
|
|
726
|
+
* the store via `useAsNestedSectionsStore()` to drive Expand-all /
|
|
727
|
+
* Collapse-all UI without prop drilling.
|
|
728
|
+
*
|
|
729
|
+
* **Default state is closed.** IDs only enter `open` when explicitly
|
|
730
|
+
* expanded (user click, native `<details>` toggle, programmatic
|
|
731
|
+
* `setOpen` / `expandAll`). The native `<details>` toggle event syncs
|
|
732
|
+
* back via `setOpen(id, open)` (idempotent, so browser find-in-page
|
|
733
|
+
* auto-opens don't fight the store).
|
|
734
|
+
*/
|
|
735
|
+
interface AsNestedSectionsStore {
|
|
736
|
+
open: Ref<Set<string>>;
|
|
737
|
+
register: (id: string) => void;
|
|
738
|
+
unregister: (id: string) => void;
|
|
739
|
+
toggle: (id: string) => void;
|
|
740
|
+
setOpen: (id: string, open: boolean) => void;
|
|
741
|
+
isOpen: (id: string) => boolean;
|
|
742
|
+
expandAll: () => void;
|
|
743
|
+
collapseAll: () => void;
|
|
744
|
+
allOpen: () => boolean;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Create and provide a `AsNestedSectionsStore` to the current Vue subtree.
|
|
748
|
+
* Called automatically by `<AsForm>`, but exposed for cases where you
|
|
749
|
+
* want to scope a separate store (e.g. multiple independent forms in one
|
|
750
|
+
* page that should keep their open/closed state independent, or to drive
|
|
751
|
+
* page-level Expand-all / Collapse-all UI from above the form).
|
|
752
|
+
*/
|
|
753
|
+
declare function provideAsNestedSectionsStore(): AsNestedSectionsStore;
|
|
754
|
+
/**
|
|
755
|
+
* Inject the nested-sections store provided by an ancestor `<AsForm>`
|
|
756
|
+
* (or by an explicit `provideAsNestedSectionsStore()` call). Returns
|
|
757
|
+
* `undefined` if no store is in scope.
|
|
758
|
+
*/
|
|
759
|
+
declare function useAsNestedSectionsStore(): AsNestedSectionsStore | undefined;
|
|
760
|
+
//#endregion
|
|
761
|
+
//#region src/composables/focus-after-toggle.d.ts
|
|
762
|
+
/** Run an action, then focus the first focusable input descendant of `scope`. */
|
|
763
|
+
declare function focusFirstAfter(action: () => void, scope: () => HTMLElement | null | undefined, ticks?: number): Promise<void>;
|
|
764
|
+
/**
|
|
765
|
+
* Run an action, then focus the first focusable input that wasn't present
|
|
766
|
+
* before the action. Used by array Add buttons so the user lands on the
|
|
767
|
+
* just-added row's first input regardless of how many items already exist.
|
|
768
|
+
* Falls back to first focusable when nothing existed before (the typical
|
|
769
|
+
* "enable optional + add first item" flow).
|
|
770
|
+
*/
|
|
771
|
+
declare function focusNewFocusableAfter(action: () => void, scope: () => HTMLElement | null | undefined, ticks?: number): Promise<void>;
|
|
772
|
+
/** Sugar over `focusFirstAfter` scoped to a template ref. */
|
|
773
|
+
declare function useAsFocusFirstAfter(onToggleOptional?: (enabled: boolean) => void): {
|
|
774
|
+
rootRef: Ref<HTMLElement | null>;
|
|
775
|
+
runAndFocus: (action: () => void, ticks?: number) => void;
|
|
776
|
+
runAndFocusNew: (action: () => void, ticks?: number) => void;
|
|
777
|
+
enableOptional: () => void;
|
|
778
|
+
};
|
|
779
|
+
//#endregion
|
|
780
|
+
//#region src/composables/use-as-optional-add-flow.d.ts
|
|
781
|
+
/**
|
|
782
|
+
* Options for `useAsOptionalAddFlow`.
|
|
783
|
+
*
|
|
784
|
+
* The composable consolidates the "toggle optional → register with the
|
|
785
|
+
* nested-sections store → focus first new field" choreography that
|
|
786
|
+
* structured-field defaults (AsObject, AsArray, AsTuple, AsUnion) repeat
|
|
787
|
+
* every time the user clicks an empty-state Add affordance, an Add Item
|
|
788
|
+
* button, or a variant picker.
|
|
789
|
+
*/
|
|
790
|
+
interface UseAsOptionalAddFlowOptions {
|
|
791
|
+
/**
|
|
792
|
+
* Absolute dotted path to the field — used as the nested-sections-store
|
|
793
|
+
* key. Read via a getter so the composable always reads the latest value
|
|
794
|
+
* (the path can change when the field is rendered inside a union and the
|
|
795
|
+
* variant switches).
|
|
796
|
+
*/
|
|
797
|
+
path: () => string | undefined;
|
|
798
|
+
}
|
|
799
|
+
interface UseAsOptionalAddFlowReturn {
|
|
800
|
+
/**
|
|
801
|
+
* Wrap a user-supplied action so that running it also expands the
|
|
802
|
+
* containing section in the nested-sections store. Pass the wrapped
|
|
803
|
+
* action to `AsCollapsible#runAndFocusNew` (which owns its own focus
|
|
804
|
+
* scope) so the focus query lands on the freshly mounted subtree.
|
|
805
|
+
*
|
|
806
|
+
* The wrapper is a no-op for the store-register step when no store is
|
|
807
|
+
* provided in scope (e.g. a custom default mounted standalone) — focus
|
|
808
|
+
* still happens via the host's `runAndFocusNew`.
|
|
809
|
+
*/
|
|
810
|
+
composeAction: (action: () => void) => () => void;
|
|
811
|
+
/**
|
|
812
|
+
* Sugar for the case where the call site does not have an
|
|
813
|
+
* `AsCollapsible` to delegate focus to (e.g. AsUnion's empty-state
|
|
814
|
+
* picker, which mounts its own `<div>`). Wraps the action with
|
|
815
|
+
* store-open registration, then runs it inside `focusNewFocusableAfter`.
|
|
816
|
+
*
|
|
817
|
+
* Returns the same Promise `focusNewFocusableAfter` returns so callers
|
|
818
|
+
* can `await` if they need to.
|
|
819
|
+
*/
|
|
820
|
+
runAndFocusNew: (scope: () => HTMLElement | null | undefined, action: () => void, ticks?: number) => Promise<void>;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Choreography composable for "enable-optional + add + focus-first-new"
|
|
824
|
+
* flows. The four built-in structured-field defaults consume it; custom
|
|
825
|
+
* implementations of object/array/tuple/union components can use it too
|
|
826
|
+
* to get the same UX (smooth focus handoff after an empty-state click)
|
|
827
|
+
* without re-implementing the choreography.
|
|
828
|
+
*
|
|
829
|
+
* Pairs with:
|
|
830
|
+
* - {@link useAsFocusFirstAfter} — focus mechanics (used by AsCollapsible)
|
|
831
|
+
* - {@link useAsNestedSectionsStore} — open/closed state registry
|
|
832
|
+
*
|
|
833
|
+
* Typical use, inside an `as-object.vue` swap component:
|
|
834
|
+
* ```ts
|
|
835
|
+
* const { composeAction } = useAsOptionalAddFlow({ path: () => props.path });
|
|
836
|
+
* function handleAddData() {
|
|
837
|
+
* collapsibleRef.value?.runAndFocusNew(
|
|
838
|
+
* composeAction(() => props.onToggleOptional?.(true)),
|
|
839
|
+
* 2,
|
|
840
|
+
* );
|
|
841
|
+
* }
|
|
842
|
+
* ```
|
|
843
|
+
*/
|
|
844
|
+
declare function useAsOptionalAddFlow(options: UseAsOptionalAddFlowOptions): UseAsOptionalAddFlowReturn;
|
|
845
|
+
//#endregion
|
|
846
|
+
//#region src/composables/use-as-tri-state-checkbox.d.ts
|
|
847
|
+
/**
|
|
848
|
+
* Options for `useAsTriStateCheckbox`.
|
|
849
|
+
*
|
|
850
|
+
* Consolidates the "checked / unchecked / indeterminate" mechanics for
|
|
851
|
+
* boolean fields whose model can be `undefined` (optional booleans, or
|
|
852
|
+
* checkboxes that round-trip from a SQL NULL). HTML5's `indeterminate`
|
|
853
|
+
* is a property on the DOM element — not a reflectable attribute — so
|
|
854
|
+
* the composable wires it via a `watchEffect`.
|
|
855
|
+
*/
|
|
856
|
+
interface UseAsTriStateCheckboxOptions {
|
|
857
|
+
/**
|
|
858
|
+
* Reactive getter for the current model value. `undefined` renders the
|
|
859
|
+
* indeterminate look; `true` / `false` render checked / unchecked.
|
|
860
|
+
*/
|
|
861
|
+
modelValue: () => boolean | undefined;
|
|
862
|
+
/**
|
|
863
|
+
* Called when the user toggles the checkbox. Receives the new value as
|
|
864
|
+
* read off the input's `checked` property after the click.
|
|
865
|
+
*/
|
|
866
|
+
onCommit: (value: boolean) => void;
|
|
867
|
+
}
|
|
868
|
+
interface UseAsTriStateCheckboxReturn {
|
|
869
|
+
/**
|
|
870
|
+
* Bind to `<input type="checkbox" :checked>`. Equivalent to
|
|
871
|
+
* `modelValue() === true`.
|
|
872
|
+
*/
|
|
873
|
+
checked: ComputedRef<boolean>;
|
|
874
|
+
/**
|
|
875
|
+
* `true` when the model is `undefined` — render the indeterminate
|
|
876
|
+
* look (the composable also wires the DOM property via `watchEffect`).
|
|
877
|
+
*/
|
|
878
|
+
indeterminate: ComputedRef<boolean>;
|
|
879
|
+
/**
|
|
880
|
+
* Template ref for the `<input>` element. The composable observes it
|
|
881
|
+
* and writes the `indeterminate` property whenever the model becomes
|
|
882
|
+
* `undefined`.
|
|
883
|
+
*/
|
|
884
|
+
inputRef: Ref<HTMLInputElement | null>;
|
|
885
|
+
/** Bind to `@change`. Reads `e.target.checked` and forwards to `onCommit`. */
|
|
886
|
+
onChange: (e: Event) => void;
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Tri-state checkbox helper. The visible state is derived from the
|
|
890
|
+
* model: `true` checked, `false` unchecked, `undefined` indeterminate.
|
|
891
|
+
* Clicking commits a boolean — never `undefined` — because browsers do
|
|
892
|
+
* not emit a "tri-state click". The "back to undefined" path stays a
|
|
893
|
+
* separate optional-clear affordance owned by the host component.
|
|
894
|
+
*
|
|
895
|
+
* Use this composable in a custom checkbox swap component to inherit the
|
|
896
|
+
* same a11y / DOM-sync behaviour as the built-in `AsCheckbox` without
|
|
897
|
+
* re-implementing the `watchEffect` plumbing or remembering that
|
|
898
|
+
* `indeterminate` is a property, not an attribute.
|
|
899
|
+
*/
|
|
900
|
+
declare function useAsTriStateCheckbox(options: UseAsTriStateCheckboxOptions): UseAsTriStateCheckboxReturn;
|
|
901
|
+
//#endregion
|
|
902
|
+
//#region src/composables/use-as-locale.d.ts
|
|
903
|
+
declare function provideAsLocale(getter: () => string | undefined): void;
|
|
904
|
+
interface UseAsLocaleReturn {
|
|
905
|
+
/** Resolved locale; `undefined` when no provider is present (runtime locale). */
|
|
906
|
+
locale: ComputedRef<string | undefined>;
|
|
907
|
+
}
|
|
908
|
+
declare function useAsLocale(): UseAsLocaleReturn;
|
|
909
|
+
//#endregion
|
|
910
|
+
//#region src/composables/use-as-decimal.d.ts
|
|
911
|
+
interface UseAsDecimalOptions {
|
|
912
|
+
/** Read the current value. Storage shape is preserved on commit. */
|
|
913
|
+
modelValue: () => string | number | null | undefined;
|
|
914
|
+
/**
|
|
915
|
+
* Effective display + edit scale. Composables truncate user-typed values
|
|
916
|
+
* to this so a paste of "10.99" into a JPY field doesn't propagate the
|
|
917
|
+
* lost ".99". Resolution lives at AsField — see TAsComponentProps.scale.
|
|
918
|
+
*/
|
|
919
|
+
scale?: () => number | undefined;
|
|
920
|
+
/**
|
|
921
|
+
* Storage cap (DB column scale). Outgoing strings are padded to this
|
|
922
|
+
* regardless of `scale` — display can be tighter than storage. When
|
|
923
|
+
* absent, falls back to `scale`.
|
|
924
|
+
*/
|
|
925
|
+
storageScale?: () => number | undefined;
|
|
926
|
+
/** Locale override; defaults to `useAsLocale()` then runtime locale. */
|
|
927
|
+
locale?: () => string | undefined;
|
|
928
|
+
/** Commit handler — receives the new value in the same shape as `modelValue()`. */
|
|
929
|
+
onCommit: (value: string | number | null) => void;
|
|
930
|
+
}
|
|
931
|
+
interface UseAsDecimalReturn {
|
|
932
|
+
/** Effective display + edit scale. Defaults to 2 when neither scale nor storageScale provided. */
|
|
933
|
+
scale: ComputedRef<number>;
|
|
934
|
+
/** Storage cap (always populated; falls back to effective scale, then 2). */
|
|
935
|
+
storageScale: ComputedRef<number>;
|
|
936
|
+
decimalSeparator: ComputedRef<string>;
|
|
937
|
+
thousandsSeparator: ComputedRef<string>;
|
|
938
|
+
/** Single-input renderers: locale-formatted decimal "1,234.50" / "1 234,50". */
|
|
939
|
+
displayValue: ComputedRef<string>;
|
|
940
|
+
/** Canonical decimal "1234.50": no thousands, "." separator, padded to effective scale. */
|
|
941
|
+
rawValue: ComputedRef<string>;
|
|
942
|
+
/** Split renderers: integer is grouped per locale for display. */
|
|
943
|
+
parts: ComputedRef<{
|
|
944
|
+
sign: "" | "-";
|
|
945
|
+
integer: string;
|
|
946
|
+
decimal: string;
|
|
947
|
+
}>;
|
|
948
|
+
/** Renderer received a complete typed value (single-input swap). */
|
|
949
|
+
setFromInput: (raw: string) => void;
|
|
950
|
+
/** Renderer captured the two halves separately (default two-input SFC). */
|
|
951
|
+
setFromParts: (sign: "" | "-", integer: string, decimal: string) => void;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Reactive composable for decimal-typed inputs (the `AsDecimal` SFC and
|
|
955
|
+
* customer swaps built against `TAsComponentProps`).
|
|
956
|
+
*
|
|
957
|
+
* Currency-agnostic: the SFC owns prefix/suffix render concerns and
|
|
958
|
+
* resolves the effective scale via the `scale` prop set by AsField. This
|
|
959
|
+
* composable just operates on the model with the scale given to it.
|
|
960
|
+
*
|
|
961
|
+
* Storage shape is preserved on commit — string `modelValue` commits a
|
|
962
|
+
* string padded to `storageScale`; number `modelValue` commits a number.
|
|
963
|
+
* A change to the effective `scale` getter that shrinks it below the
|
|
964
|
+
* model's actual precision triggers a re-round + re-commit (the same
|
|
965
|
+
* "currency-change" behaviour as before).
|
|
966
|
+
*/
|
|
967
|
+
declare function useAsDecimal(opts: UseAsDecimalOptions): UseAsDecimalReturn;
|
|
968
|
+
//#endregion
|
|
969
|
+
//#region src/composables/use-as-number.d.ts
|
|
970
|
+
interface UseAsNumberOptions {
|
|
971
|
+
/** Read the current value. May be a string when authored externally; commit is always a `number` or `null`. */
|
|
972
|
+
modelValue: () => string | number | null | undefined;
|
|
973
|
+
/** Locale override; defaults to `useAsLocale()` then runtime locale. */
|
|
974
|
+
locale?: () => string | undefined;
|
|
975
|
+
/** Commit handler — receives a parsed `number`, or `null` for empty input. */
|
|
976
|
+
onCommit: (value: number | null) => void;
|
|
977
|
+
}
|
|
978
|
+
interface UseAsNumberReturn {
|
|
979
|
+
decimalSeparator: ComputedRef<string>;
|
|
980
|
+
/**
|
|
981
|
+
* Single-input renderers: raw model value with the locale decimal
|
|
982
|
+
* separator swap. No Intl grouping, no padding, no truncation — numbers
|
|
983
|
+
* aren't precision-critical the way decimals are.
|
|
984
|
+
*/
|
|
985
|
+
displayValue: ComputedRef<string>;
|
|
986
|
+
/** Canonical decimal ("." separator). Verbatim from the model — no scale enforcement. */
|
|
987
|
+
rawValue: ComputedRef<string>;
|
|
988
|
+
/** Renderer received a complete typed value. */
|
|
989
|
+
setFromInput: (raw: string) => void;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Reactive composable that powers the default `AsNumber` SFC. Single-
|
|
993
|
+
* input shape — currency-agnostic, scale-agnostic, just a plain number
|
|
994
|
+
* with optional prefix/suffix chrome owned by the SFC.
|
|
995
|
+
*
|
|
996
|
+
* Commit shape is always a `number` (or `null` for empty input).
|
|
997
|
+
* atscript `number` fields are primitive `number` in the model — there
|
|
998
|
+
* is no precision-preservation reason to ship a string the way decimals
|
|
999
|
+
* do. The SFC owns prefix/suffix render concerns; this composable only
|
|
1000
|
+
* knows about the value.
|
|
1001
|
+
*/
|
|
1002
|
+
declare function useAsNumber(opts: UseAsNumberOptions): UseAsNumberReturn;
|
|
1003
|
+
//#endregion
|
|
1004
|
+
//#region src/composables/use-as-dual-input.d.ts
|
|
1005
|
+
/**
|
|
1006
|
+
* Keyboard plumbing for the bank-UX two-input pattern (integer + decimal
|
|
1007
|
+
* halves joined by a separator pill). Extracted from the original
|
|
1008
|
+
* AsAmount SFC so AsDecimal and any customer two-input renderer can
|
|
1009
|
+
* share the same arrow-bridge / digit-overwrite / paste-split behaviour.
|
|
1010
|
+
*
|
|
1011
|
+
* This composable is render-agnostic — the SFC owns the layout, the
|
|
1012
|
+
* shell chrome and the value model wiring. The composable just exposes
|
|
1013
|
+
* the input refs, edit-state, focus handlers and event handlers wired
|
|
1014
|
+
* to a `setFromParts` / `setFromInput` callback pair.
|
|
1015
|
+
*/
|
|
1016
|
+
interface UseAsDualInputOptions {
|
|
1017
|
+
/** Effective scale (max digits in the decimal half). 0 → no decimal half. */
|
|
1018
|
+
scale: () => number;
|
|
1019
|
+
/** Locale-aware decimal separator (used for bridge-key detection). */
|
|
1020
|
+
decimalSeparator: () => string;
|
|
1021
|
+
/** Read the current parts. The composable owns NO model state. */
|
|
1022
|
+
parts: () => {
|
|
1023
|
+
sign: "" | "-";
|
|
1024
|
+
integer: string;
|
|
1025
|
+
decimal: string;
|
|
1026
|
+
};
|
|
1027
|
+
/** Read the canonical "X.YZ" string — used by paste/bridge to know current state. */
|
|
1028
|
+
rawValue: () => string;
|
|
1029
|
+
/** Commit a fresh split. Pure callback into the parent's state machine. */
|
|
1030
|
+
setFromParts: (sign: "" | "-", integer: string, decimal: string) => void;
|
|
1031
|
+
/** Commit a raw typed string (for paste). */
|
|
1032
|
+
setFromInput: (raw: string) => void;
|
|
1033
|
+
/** Called from `onBlurAll` after focus leaves both inputs. */
|
|
1034
|
+
onBlur?: () => void;
|
|
1035
|
+
}
|
|
1036
|
+
interface UseAsDualInputReturn {
|
|
1037
|
+
integerInput: Ref<HTMLInputElement | null>;
|
|
1038
|
+
decimalInput: Ref<HTMLInputElement | null>;
|
|
1039
|
+
/** Display string for the integer half — un-grouped while focused, grouped on blur. */
|
|
1040
|
+
integerDisplay: ComputedRef<string>;
|
|
1041
|
+
/** Display string for the decimal half — owns the suppression rules. */
|
|
1042
|
+
decimalDisplay: ComputedRef<string>;
|
|
1043
|
+
/** True while either input has focus. */
|
|
1044
|
+
focusActive: Ref<boolean>;
|
|
1045
|
+
onIntegerFocus: (e?: FocusEvent) => void;
|
|
1046
|
+
onDecimalFocus: (e?: FocusEvent) => void;
|
|
1047
|
+
onBlurAll: (e: FocusEvent) => void;
|
|
1048
|
+
onIntegerInput: (e: Event) => void;
|
|
1049
|
+
onIntegerKeydown: (e: KeyboardEvent) => void;
|
|
1050
|
+
onIntegerPaste: (e: ClipboardEvent) => void;
|
|
1051
|
+
onDecimalInput: (e: Event) => void;
|
|
1052
|
+
onDecimalKeydown: (e: KeyboardEvent) => void;
|
|
1053
|
+
onDecimalPaste: (e: ClipboardEvent) => void;
|
|
1054
|
+
}
|
|
1055
|
+
declare function useAsDualInput(opts: UseAsDualInputOptions): UseAsDualInputReturn;
|
|
1056
|
+
//#endregion
|
|
1057
|
+
//#region src/composables/use-as-date.d.ts
|
|
1058
|
+
/**
|
|
1059
|
+
* Storage convention — atscript marks date-bearing fields with the
|
|
1060
|
+
* `number.timestamp` primitive (epoch-ms numbers). The default form
|
|
1061
|
+
* components mirror the cell-side rule: accept `Date | number | string`
|
|
1062
|
+
* for read, commit back as `number` (epoch-ms) when storage is numeric,
|
|
1063
|
+
* else commit the raw ISO string.
|
|
1064
|
+
*
|
|
1065
|
+
* `<input type="date">` uses `YYYY-MM-DD`,
|
|
1066
|
+
* `<input type="datetime-local">` uses `YYYY-MM-DDTHH:mm`,
|
|
1067
|
+
* `<input type="time">` uses `HH:mm`. The HTML5 spec treats these as
|
|
1068
|
+
* locale-agnostic strings — we must produce them deterministically.
|
|
1069
|
+
*/
|
|
1070
|
+
type ModelValue = number | string | Date | null | undefined;
|
|
1071
|
+
interface UseAsDateOptions {
|
|
1072
|
+
modelValue: () => ModelValue;
|
|
1073
|
+
/** Variant: `'date'` (default), `'datetime'`, `'time'`. Drives both parse and serialize. */
|
|
1074
|
+
kind: "date" | "datetime" | "time";
|
|
1075
|
+
/** Commit the parsed value. Numeric epoch-ms when the previous value was numeric, ISO string otherwise. `null` clears. */
|
|
1076
|
+
onCommit: (value: number | string | null) => void;
|
|
1077
|
+
}
|
|
1078
|
+
interface UseAsDateReturn {
|
|
1079
|
+
/** HTML5 input type — `'date' | 'datetime-local' | 'time'`. */
|
|
1080
|
+
inputType: "date" | "datetime-local" | "time";
|
|
1081
|
+
/** Bind to `<input :value>`. Empty string when no model. */
|
|
1082
|
+
displayValue: ComputedRef<string>;
|
|
1083
|
+
/** Bind to `@change` / `@input`. Parses the HTML5 string into the storage type. */
|
|
1084
|
+
setFromInput: (raw: string) => void;
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Composable backing `AsDate` / `AsDatetime` / `AsTime`. Pick the variant
|
|
1088
|
+
* via `kind`. Conversion direction:
|
|
1089
|
+
*
|
|
1090
|
+
* - `'date'`: epoch-ms ↔ `YYYY-MM-DD` (local TZ).
|
|
1091
|
+
* Empty input commits `null`. If previous value was a `string`,
|
|
1092
|
+
* commits a string (`YYYY-MM-DD`); otherwise commits epoch-ms (UTC
|
|
1093
|
+
* midnight on the picked date in local TZ — same as `new Date(str)`).
|
|
1094
|
+
* - `'datetime'`: epoch-ms ↔ `YYYY-MM-DDTHH:mm` (local TZ).
|
|
1095
|
+
* - `'time'`: prev-string ↔ `HH:mm`. Numeric storage isn't meaningful
|
|
1096
|
+
* for naked time-of-day, so we commit a string.
|
|
1097
|
+
*/
|
|
1098
|
+
declare function useAsDate(opts: UseAsDateOptions): UseAsDateReturn;
|
|
1099
|
+
//#endregion
|
|
1100
|
+
//#region src/composables/use-as-path.d.ts
|
|
1101
|
+
interface UseAsPathReturn {
|
|
1102
|
+
path: ComputedRef<string>;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Reactive read-only access to the absolute dotted path prefix at the
|
|
1106
|
+
* current point in the `<AsForm>` tree. Returns `''` when called outside
|
|
1107
|
+
* a form.
|
|
1108
|
+
*/
|
|
1109
|
+
declare function useAsPath(): UseAsPathReturn;
|
|
1110
|
+
//#endregion
|
|
1111
|
+
//#region src/composables/use-as-type-map.d.ts
|
|
1112
|
+
interface UseAsTypeMapReturn {
|
|
1113
|
+
types: ComputedRef<Record<string, Component>>;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Reactive read-only access to the type-to-component map provided by the
|
|
1117
|
+
* nearest `<AsForm>`. Returns an empty map when called outside a form so
|
|
1118
|
+
* call sites do not need a null-check.
|
|
1119
|
+
*/
|
|
1120
|
+
declare function useAsTypeMap(): UseAsTypeMapReturn;
|
|
1121
|
+
//#endregion
|
|
1122
|
+
//#region src/composables/use-as-data.d.ts
|
|
1123
|
+
interface UseAsDataReturn {
|
|
1124
|
+
/** Domain data (the unwrapped inner value of the form's `{ value }` container). */
|
|
1125
|
+
rootData: ComputedRef<unknown>;
|
|
1126
|
+
/** Read the value at an absolute dotted path inside the form. */
|
|
1127
|
+
getValueAt: (path: string) => ComputedRef<unknown>;
|
|
1128
|
+
/** Read a sibling field's value relative to the current `useAsPath()` prefix. */
|
|
1129
|
+
siblingValue: <T = unknown>(name: string) => ComputedRef<T | undefined>;
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Reactive read-only access to form data at any point in the
|
|
1133
|
+
* `<AsForm>` tree. Outside a form, all readers return `undefined`.
|
|
1134
|
+
*
|
|
1135
|
+
* Call sites get a `ComputedRef` so they can compose it directly with
|
|
1136
|
+
* other reactive primitives without an extra `computed()` wrapper.
|
|
1137
|
+
*/
|
|
1138
|
+
declare function useAsData(): UseAsDataReturn;
|
|
1139
|
+
//#endregion
|
|
1140
|
+
//#region src/composables/use-as-error-dismiss.d.ts
|
|
1141
|
+
/**
|
|
1142
|
+
* Imperative dismissal of an external (server-supplied) error at a given
|
|
1143
|
+
* absolute path. Calling this is equivalent to the user editing that
|
|
1144
|
+
* field — useful for custom field components that commit a value through
|
|
1145
|
+
* a side-channel (e.g. a date picker dialog) and want to hide the
|
|
1146
|
+
* server's error before the next round-trip.
|
|
1147
|
+
*/
|
|
1148
|
+
type AsErrorDismiss = (path: string) => void;
|
|
1149
|
+
/**
|
|
1150
|
+
* Returns the `dismissExternalAt` callback provided by the nearest
|
|
1151
|
+
* ancestor `<AsForm>`. Outside a form the result is a no-op so calling
|
|
1152
|
+
* it from a leaf component does not throw.
|
|
1153
|
+
*/
|
|
1154
|
+
declare function useAsErrorDismiss(): AsErrorDismiss;
|
|
1155
|
+
//#endregion
|
|
1156
|
+
//#region src/components/as-form.vue.d.ts
|
|
1157
|
+
interface Props<TF, TC> {
|
|
1158
|
+
def: FormDef;
|
|
1159
|
+
formData?: TF;
|
|
1160
|
+
formContext?: TC;
|
|
1161
|
+
firstValidation?: TFormState["firstValidation"];
|
|
1162
|
+
components?: Record<string, Component<TAsComponentProps>>;
|
|
1163
|
+
/**
|
|
1164
|
+
* Type-to-component map for field rendering. Maps field types to Vue components.
|
|
1165
|
+
* Must include entries for all built-in field types. Use `createDefaultTypes()`
|
|
1166
|
+
* for a pre-filled map, or supply your own.
|
|
1167
|
+
*/
|
|
1168
|
+
types: TAsTypeComponents;
|
|
1169
|
+
errors?: Record<string, string | undefined>;
|
|
1170
|
+
/**
|
|
1171
|
+
* Per-form client factory override. Creates `Client` instances from URL paths
|
|
1172
|
+
* for FK value-help pickers inside this form. Falls back to the app-wide
|
|
1173
|
+
* default (`setDefaultClientFactory`) and then to the built-in `new Client(url)`
|
|
1174
|
+
* factory when unset.
|
|
1175
|
+
*/
|
|
1176
|
+
clientFactory?: ClientFactory;
|
|
1177
|
+
/**
|
|
1178
|
+
* Suppress the root field's title rendering. Use when the form is mounted
|
|
1179
|
+
* inside a chrome that already shows the form's `@meta.label` (e.g. a
|
|
1180
|
+
* dialog header). Nested fields keep their own headings.
|
|
1181
|
+
*/
|
|
1182
|
+
hideRootTitle?: boolean;
|
|
1183
|
+
/**
|
|
1184
|
+
* Suppress the default submit button. Use when the host chrome owns the
|
|
1185
|
+
* submit affordance (e.g. a dialog footer with its own submit button
|
|
1186
|
+
* wired via HTML5 `<button form="...">`). Vue 3 treats an empty
|
|
1187
|
+
* `<template #form.submit />` as "slot not provided" and falls back to
|
|
1188
|
+
* the default button — this prop is the explicit way to skip it.
|
|
1189
|
+
*/
|
|
1190
|
+
hideSubmit?: boolean;
|
|
1191
|
+
/**
|
|
1192
|
+
* When true, freezes the form: the body becomes `inert` (blocks pointer
|
|
1193
|
+
* events + keyboard focus) and a loading overlay paints over the entire
|
|
1194
|
+
* form area. Used by `<AsWfForm>` to lock interaction during a server
|
|
1195
|
+
* round-trip so the user can't edit a field whose response is racing in.
|
|
1196
|
+
* Visual is shared with `<AsTable>`'s query overlay via vunor
|
|
1197
|
+
* `inner-loading`.
|
|
1198
|
+
*/
|
|
1199
|
+
loading?: boolean;
|
|
1200
|
+
/**
|
|
1201
|
+
* Enable change tracking. When set, the form captures a deep-clone baseline
|
|
1202
|
+
* of its data and surfaces both a changed-fields list and an `@atscript/db`
|
|
1203
|
+
* patch object. The tracking surface (`isDirty` / `changes` / `getPatch` /
|
|
1204
|
+
* `getChanges`) is spread into every slot AND exposed on the component
|
|
1205
|
+
* instance (template ref → `asForm.value.getPatch()`); descendants read it
|
|
1206
|
+
* with `useAsFormPatch()`. Off by default — zero overhead when unset.
|
|
1207
|
+
*/
|
|
1208
|
+
trackChanges?: boolean;
|
|
1209
|
+
}
|
|
1210
|
+
declare const __VLS_export: <TFormData = any, TFormContext = any>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
1211
|
+
props: vue.PublicProps & __VLS_PrettifyLocal<Props<TFormData, TFormContext> & {
|
|
1212
|
+
onError?: ((errors: {
|
|
1213
|
+
path: string;
|
|
1214
|
+
message: string;
|
|
1215
|
+
}[]) => any) | undefined;
|
|
1216
|
+
onSubmit?: ((data: TFormData) => any) | undefined;
|
|
1217
|
+
onAction?: ((name: string, data: TFormData) => any) | undefined;
|
|
1218
|
+
"onUnsupported-action"?: ((name: string, data: TFormData) => any) | undefined;
|
|
1219
|
+
onChange?: ((type: TAsChangeType, path: string, value: unknown, formData: TFormData) => any) | undefined;
|
|
1220
|
+
}> & (typeof globalThis extends {
|
|
1221
|
+
__VLS_PROPS_FALLBACK: infer P;
|
|
1222
|
+
} ? P : {});
|
|
1223
|
+
expose: (exposed: vue.ShallowUnwrapRef<{
|
|
1224
|
+
submit: () => void;
|
|
1225
|
+
reset: () => Promise<void>; /** True when `track-changes` is on AND data differs from baseline. */
|
|
1226
|
+
readonly isDirty: boolean; /** Revert-aware per-field change list (empty when tracking is off). */
|
|
1227
|
+
readonly changes: FormFieldChange[]; /** Build the `@atscript/db` patch object on demand (`{}` when off). */
|
|
1228
|
+
getPatch: ((opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>) | (() => {}); /** Build the per-field change list on demand (`[]` when off). */
|
|
1229
|
+
getChanges: () => FormFieldChange[];
|
|
1230
|
+
/**
|
|
1231
|
+
* Per-field dirty predicate — `true` when the field at `path` differs from
|
|
1232
|
+
* the baseline (`false` for every path when tracking is off).
|
|
1233
|
+
*/
|
|
1234
|
+
isDirtyPath: (path: string) => boolean; /** Re-baseline to current data after a successful save (no-op when off). */
|
|
1235
|
+
rebase: () => void;
|
|
1236
|
+
/**
|
|
1237
|
+
* 3-way rebase onto a fresh upstream snapshot (sets baseline := upstream,
|
|
1238
|
+
* reapplies the local diff). Pure no-op returning empty when tracking is off
|
|
1239
|
+
* — NO side effects, mirroring `rebase`/`getPatch`.
|
|
1240
|
+
*/
|
|
1241
|
+
rebaseOnto: (upstream: Record<string, unknown>, opts?: _atscript_ui0.FormRebaseOptions) => RebaseOntoResult;
|
|
1242
|
+
}>) => void;
|
|
1243
|
+
attrs: any;
|
|
1244
|
+
slots: {
|
|
1245
|
+
'form.header'?: (props: {
|
|
1246
|
+
title: string | undefined;
|
|
1247
|
+
description: string | undefined;
|
|
1248
|
+
data: TFormData;
|
|
1249
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1250
|
+
formError: string | undefined;
|
|
1251
|
+
disabled: boolean;
|
|
1252
|
+
loading: boolean;
|
|
1253
|
+
submitText: string;
|
|
1254
|
+
submit: () => void;
|
|
1255
|
+
reset: () => Promise<void>;
|
|
1256
|
+
clearErrors: () => void;
|
|
1257
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1258
|
+
dismissError: (path: string) => void;
|
|
1259
|
+
dismissFormError: () => void;
|
|
1260
|
+
formContext: TFormContext | undefined;
|
|
1261
|
+
isDirty: boolean;
|
|
1262
|
+
changes: readonly FormFieldChange[];
|
|
1263
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1264
|
+
getChanges: () => FormFieldChange[];
|
|
1265
|
+
isDirtyPath: (path: string) => boolean;
|
|
1266
|
+
}) => any;
|
|
1267
|
+
} & {
|
|
1268
|
+
'form.before'?: (props: {
|
|
1269
|
+
title: string | undefined;
|
|
1270
|
+
description: string | undefined;
|
|
1271
|
+
data: TFormData;
|
|
1272
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1273
|
+
formError: string | undefined;
|
|
1274
|
+
disabled: boolean;
|
|
1275
|
+
loading: boolean;
|
|
1276
|
+
submitText: string;
|
|
1277
|
+
submit: () => void;
|
|
1278
|
+
reset: () => Promise<void>;
|
|
1279
|
+
clearErrors: () => void;
|
|
1280
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1281
|
+
dismissError: (path: string) => void;
|
|
1282
|
+
dismissFormError: () => void;
|
|
1283
|
+
formContext: TFormContext | undefined;
|
|
1284
|
+
isDirty: boolean;
|
|
1285
|
+
changes: readonly FormFieldChange[];
|
|
1286
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1287
|
+
getChanges: () => FormFieldChange[];
|
|
1288
|
+
isDirtyPath: (path: string) => boolean;
|
|
1289
|
+
}) => any;
|
|
1290
|
+
} & {
|
|
1291
|
+
'form.after'?: (props: {
|
|
1292
|
+
title: string | undefined;
|
|
1293
|
+
description: string | undefined;
|
|
1294
|
+
data: TFormData;
|
|
1295
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1296
|
+
formError: string | undefined;
|
|
1297
|
+
disabled: boolean;
|
|
1298
|
+
loading: boolean;
|
|
1299
|
+
submitText: string;
|
|
1300
|
+
submit: () => void;
|
|
1301
|
+
reset: () => Promise<void>;
|
|
1302
|
+
clearErrors: () => void;
|
|
1303
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1304
|
+
dismissError: (path: string) => void;
|
|
1305
|
+
dismissFormError: () => void;
|
|
1306
|
+
formContext: TFormContext | undefined;
|
|
1307
|
+
isDirty: boolean;
|
|
1308
|
+
changes: readonly FormFieldChange[];
|
|
1309
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1310
|
+
getChanges: () => FormFieldChange[];
|
|
1311
|
+
isDirtyPath: (path: string) => boolean;
|
|
1312
|
+
}) => any;
|
|
1313
|
+
} & {
|
|
1314
|
+
'form.error'?: (props: {
|
|
1315
|
+
message: string;
|
|
1316
|
+
dismiss: () => void;
|
|
1317
|
+
title: string | undefined;
|
|
1318
|
+
description: string | undefined;
|
|
1319
|
+
data: TFormData;
|
|
1320
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1321
|
+
formError: string | undefined;
|
|
1322
|
+
disabled: boolean;
|
|
1323
|
+
loading: boolean;
|
|
1324
|
+
submitText: string;
|
|
1325
|
+
submit: () => void;
|
|
1326
|
+
reset: () => Promise<void>;
|
|
1327
|
+
clearErrors: () => void;
|
|
1328
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1329
|
+
dismissError: (path: string) => void;
|
|
1330
|
+
dismissFormError: () => void;
|
|
1331
|
+
formContext: TFormContext | undefined;
|
|
1332
|
+
isDirty: boolean;
|
|
1333
|
+
changes: readonly FormFieldChange[];
|
|
1334
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1335
|
+
getChanges: () => FormFieldChange[];
|
|
1336
|
+
isDirtyPath: (path: string) => boolean;
|
|
1337
|
+
}) => any;
|
|
1338
|
+
} & {
|
|
1339
|
+
'form.submit'?: (props: {
|
|
1340
|
+
text: string;
|
|
1341
|
+
title: string | undefined;
|
|
1342
|
+
description: string | undefined;
|
|
1343
|
+
data: TFormData;
|
|
1344
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1345
|
+
formError: string | undefined;
|
|
1346
|
+
disabled: boolean;
|
|
1347
|
+
loading: boolean;
|
|
1348
|
+
submitText: string;
|
|
1349
|
+
submit: () => void;
|
|
1350
|
+
reset: () => Promise<void>;
|
|
1351
|
+
clearErrors: () => void;
|
|
1352
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1353
|
+
dismissError: (path: string) => void;
|
|
1354
|
+
dismissFormError: () => void;
|
|
1355
|
+
formContext: TFormContext | undefined;
|
|
1356
|
+
isDirty: boolean;
|
|
1357
|
+
changes: readonly FormFieldChange[];
|
|
1358
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1359
|
+
getChanges: () => FormFieldChange[];
|
|
1360
|
+
isDirtyPath: (path: string) => boolean;
|
|
1361
|
+
}) => any;
|
|
1362
|
+
} & {
|
|
1363
|
+
'form.footer'?: (props: {
|
|
1364
|
+
title: string | undefined;
|
|
1365
|
+
description: string | undefined;
|
|
1366
|
+
data: TFormData;
|
|
1367
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1368
|
+
formError: string | undefined;
|
|
1369
|
+
disabled: boolean;
|
|
1370
|
+
loading: boolean;
|
|
1371
|
+
submitText: string;
|
|
1372
|
+
submit: () => void;
|
|
1373
|
+
reset: () => Promise<void>;
|
|
1374
|
+
clearErrors: () => void;
|
|
1375
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1376
|
+
dismissError: (path: string) => void;
|
|
1377
|
+
dismissFormError: () => void;
|
|
1378
|
+
formContext: TFormContext | undefined;
|
|
1379
|
+
isDirty: boolean;
|
|
1380
|
+
changes: readonly FormFieldChange[];
|
|
1381
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1382
|
+
getChanges: () => FormFieldChange[];
|
|
1383
|
+
isDirtyPath: (path: string) => boolean;
|
|
1384
|
+
}) => any;
|
|
1385
|
+
} & {
|
|
1386
|
+
'form.loading'?: (props: {
|
|
1387
|
+
title: string | undefined;
|
|
1388
|
+
description: string | undefined;
|
|
1389
|
+
data: TFormData;
|
|
1390
|
+
errors: Record<string, string | undefined> | undefined;
|
|
1391
|
+
formError: string | undefined;
|
|
1392
|
+
disabled: boolean;
|
|
1393
|
+
loading: boolean;
|
|
1394
|
+
submitText: string;
|
|
1395
|
+
submit: () => void;
|
|
1396
|
+
reset: () => Promise<void>;
|
|
1397
|
+
clearErrors: () => void;
|
|
1398
|
+
setErrors: (errors: Record<string, string>) => void;
|
|
1399
|
+
dismissError: (path: string) => void;
|
|
1400
|
+
dismissFormError: () => void;
|
|
1401
|
+
formContext: TFormContext | undefined;
|
|
1402
|
+
isDirty: boolean;
|
|
1403
|
+
changes: readonly FormFieldChange[];
|
|
1404
|
+
getPatch: (opts?: _atscript_ui0.FormDiffOptions) => Record<string, unknown>;
|
|
1405
|
+
getChanges: () => FormFieldChange[];
|
|
1406
|
+
isDirtyPath: (path: string) => boolean;
|
|
1407
|
+
}) => any;
|
|
1408
|
+
};
|
|
1409
|
+
emit: {
|
|
1410
|
+
(e: "submit", data: TFormData): void;
|
|
1411
|
+
(e: "error", errors: {
|
|
1412
|
+
path: string;
|
|
1413
|
+
message: string;
|
|
1414
|
+
}[]): void;
|
|
1415
|
+
(e: "action", name: string, data: TFormData): void;
|
|
1416
|
+
(e: "unsupported-action", name: string, data: TFormData): void;
|
|
1417
|
+
(e: "change", type: TAsChangeType, path: string, value: unknown, formData: TFormData): void;
|
|
1418
|
+
};
|
|
1419
|
+
}>) => vue.VNode & {
|
|
1420
|
+
__ctx?: Awaited<typeof __VLS_setup>;
|
|
1421
|
+
};
|
|
1422
|
+
declare const _default: typeof __VLS_export;
|
|
1423
|
+
type __VLS_PrettifyLocal<T> = (T extends any ? { [K in keyof T]: T[K] } : { [K in keyof T as K]: T[K] }) & {};
|
|
1424
|
+
//#endregion
|
|
1425
|
+
export { UseAsTupleReturn as $, UseAsLocaleReturn as A, focusNewFocusableAfter as B, useAsDualInput as C, createAsFormDef as Ct, UseAsDecimalOptions as D, useAsNumber as E, useAsTriStateCheckbox as F, useAsDropdown as G, AsNestedSectionsStore as H, UseAsOptionalAddFlowOptions as I, useAsValueHelp as J, UseAsValueHelpOptions as K, UseAsOptionalAddFlowReturn as L, useAsLocale as M, UseAsTriStateCheckboxOptions as N, UseAsDecimalReturn as O, UseAsTriStateCheckboxReturn as P, useAsUnion as Q, useAsOptionalAddFlow as R, UseAsDualInputReturn as S, createDefaultTypes as St, UseAsNumberReturn as T, provideAsNestedSectionsStore as U, useAsFocusFirstAfter as V, useAsNestedSectionsStore as W, useAsUnionVariant as X, formatIndexedLabelParts as Y, UseAsUnionReturn as Z, useAsPath as _, useAsField as _t, FormFieldChange$1 as a, useAsExternalErrors as at, useAsDate as b, TFormRule as bt, resetDefaultClientFactory as c, useAsForm as ct, useAsErrorDismiss as d, useAsFormPatch as dt, useAsTuple as et, UseAsDataReturn as f, TFormSubmitValidator as ft, UseAsPathReturn as g, UseAsFieldReturn as gt, useAsTypeMap as h, UseAsFieldOptions as ht, FormDiffOptions$1 as i, UseAsExternalErrorsReturn as it, provideAsLocale as j, useAsDecimal as k, setDefaultClientFactory as l, AsFormPatchHandle as lt, UseAsTypeMapReturn as m, useAsState as mt, _default as n, useAsArray as nt, FormRebaseOptions$1 as o, UseAsFormOptions as ot, useAsData as p, UseAsStateReturn as pt, UseAsValueHelpReturn as q, ClientFactory$1 as r, UseAsExternalErrorsOptions as rt, getDefaultClientFactory as s, UseAsFormReturn as st, Props as t, UseAsArrayReturn as tt, AsErrorDismiss as u, RebaseOntoResult as ut, UseAsDateOptions as v, TFormFieldCallbacks as vt, UseAsNumberOptions as w, UseAsDualInputOptions as x, TFormState as xt, UseAsDateReturn as y, TFormFieldRegistration as yt, focusFirstAfter as z };
|