@dynamicforms/vue-forms 3.0.0-alpha.1 → 3.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{plugin-uXEQYne6.js → plugin-Ds_2fb9G.js} +2 -2
- package/dist/chunks/{plugin-uXEQYne6.js.map → plugin-Ds_2fb9G.js.map} +1 -1
- package/dist/chunks/{registry-_vVZW3p9.js → registry-2GP2P-ie.js} +41 -41
- package/dist/chunks/registry-2GP2P-ie.js.map +1 -0
- package/dist/dynamicforms-vue-forms.js +578 -474
- package/dist/dynamicforms-vue-forms.js.map +1 -1
- package/dist/index.d.ts +87 -44
- package/package.json +4 -3
- package/readme.md +12 -9
- package/dist/chunks/registry-_vVZW3p9.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -117,10 +117,21 @@ declare type ActionExecutor = (field: FieldBase, supr: FieldActionExecute, ...pa
|
|
|
117
117
|
*/
|
|
118
118
|
export declare class ActionsMap {
|
|
119
119
|
/**
|
|
120
|
-
* Every action registered here, in registration order.
|
|
121
|
-
* so a run in progress finishes on the array it started with
|
|
120
|
+
* Every action registered here, in registration order. Registering and unregistering replace the array instead of
|
|
121
|
+
* modifying it, so a run in progress finishes on the array it started with, the change takes effect from the next
|
|
122
|
+
* trigger, and an array read through `registrations` never changes.
|
|
122
123
|
*/
|
|
123
124
|
private actions;
|
|
125
|
+
/**
|
|
126
|
+
* The registered actions, in registration order. The array is not modified later, so it records the
|
|
127
|
+
* registrations at the time of the read; `restore()` reinstates them.
|
|
128
|
+
*/
|
|
129
|
+
get registrations(): readonly FieldActionBase[];
|
|
130
|
+
/**
|
|
131
|
+
* Replaces the registered actions with `registrations`, an array `registrations` returned earlier. The order of
|
|
132
|
+
* the handlers and every duplicate registration are restored with it.
|
|
133
|
+
*/
|
|
134
|
+
restore(registrations: readonly FieldActionBase[]): void;
|
|
124
135
|
/**
|
|
125
136
|
* Registers `action`. It becomes the outermost handler of its identifier, or, if `before` is given, is inserted
|
|
126
137
|
* at the position of `before`, so `before` wraps it and calls it through `supr`. This adds an action to an
|
|
@@ -128,6 +139,8 @@ export declare class ActionsMap {
|
|
|
128
139
|
* same identifier, and a TypeError for an `ErrorPolicy` naming an origin another one registered here names.
|
|
129
140
|
*/
|
|
130
141
|
register(action: FieldActionBase, before?: FieldActionBase): void;
|
|
142
|
+
/** A copy of `actions` with `action` inserted at `index`. */
|
|
143
|
+
private static inserted;
|
|
131
144
|
/** Unregisters `action` and returns whether it was registered here. */
|
|
132
145
|
unregister(action: FieldActionBase): boolean;
|
|
133
146
|
/** True if any action is registered under `identifier`. */
|
|
@@ -253,16 +266,23 @@ declare class CompareTo<T = any> extends Validator {
|
|
|
253
266
|
*/
|
|
254
267
|
private readonly registrations;
|
|
255
268
|
/**
|
|
256
|
-
* The elements this validator has installed its listener on. A
|
|
257
|
-
*
|
|
258
|
-
* installs one listener, not N.
|
|
269
|
+
* The declarations of the elements this validator has installed its listener on. A registration goes into the map
|
|
270
|
+
* of the element's declaration, which every binding of it uses, so a list of N rows installs one listener, not N.
|
|
259
271
|
*/
|
|
260
272
|
private readonly listening;
|
|
261
273
|
/**
|
|
262
|
-
* The declarations of the fields this validator
|
|
274
|
+
* The declarations of the fields this validator is registered on. One entry covers every binding of such a
|
|
263
275
|
* field, so a change of a compared element finds the fields of its record without this set holding every row.
|
|
276
|
+
* They are held weakly: the listener on the compared element keeps this validator reachable, and a form dropped
|
|
277
|
+
* without unregistering the validator is released all the same.
|
|
264
278
|
*/
|
|
265
279
|
private readonly declarations;
|
|
280
|
+
/**
|
|
281
|
+
* The listener on the compared elements, one instance for all of them. It is removed when the validator is taken
|
|
282
|
+
* off its last declaration, or, once its declarations are collected, when an element it is registered on asks it
|
|
283
|
+
* to release itself.
|
|
284
|
+
*/
|
|
285
|
+
private readonly relay;
|
|
266
286
|
constructor(otherField: CompareToTarget, isValidComparison: (myValue: T, otherValue: T) => boolean, options?: ValidationErrorOptions);
|
|
267
287
|
/** The element `field` is compared against, within the record `field` belongs to. */
|
|
268
288
|
private resolve;
|
|
@@ -272,6 +292,8 @@ declare class CompareTo<T = any> extends Validator {
|
|
|
272
292
|
* declaration applies to that row; it re-runs only this validator, not the whole chain.
|
|
273
293
|
*/
|
|
274
294
|
private listenOn;
|
|
295
|
+
/** Removes the listener from every compared element; a rollback restores it and the record of the elements. */
|
|
296
|
+
private stopListening;
|
|
275
297
|
boundToBinding(binding: FieldBase): void;
|
|
276
298
|
private comparisonState;
|
|
277
299
|
protected newBindingState(): CompareToBindingState<T>;
|
|
@@ -304,9 +326,10 @@ export declare class ConditionalStatementAction extends ValueChangedAction {
|
|
|
304
326
|
private readonly statement;
|
|
305
327
|
private readonly conditionalExecutor;
|
|
306
328
|
/**
|
|
307
|
-
* The declarations of the elements this action
|
|
329
|
+
* The declarations of the elements this action is registered on. It holds declarations, not the elements, so one
|
|
308
330
|
* entry covers every row of a list; a result is applied to the element that corresponds to the declaration within
|
|
309
|
-
* the record the change happened in.
|
|
331
|
+
* the record the change happened in. They are held weakly: the relay on a field the statement reads keeps this
|
|
332
|
+
* action reachable, and a form dropped without unregistering the action is released all the same.
|
|
310
333
|
*/
|
|
311
334
|
private readonly declarations;
|
|
312
335
|
/**
|
|
@@ -318,13 +341,16 @@ export declare class ConditionalStatementAction extends ValueChangedAction {
|
|
|
318
341
|
constructor(statement: Statement, executorFn: ConditionalExecutorFn);
|
|
319
342
|
/**
|
|
320
343
|
* The listener on the fields the statement reads. The constructor installs it; it is removed when the action is
|
|
321
|
-
* taken off its last element and installed again when the action is next
|
|
344
|
+
* taken off its last element or its elements are collected, and installed again when the action is next
|
|
345
|
+
* registered.
|
|
322
346
|
*/
|
|
323
347
|
private readonly relay;
|
|
324
|
-
/** The number of elements the action is registered on; the relay is removed when it drops to zero. */
|
|
325
|
-
private registered;
|
|
326
348
|
private listening;
|
|
349
|
+
/** Whether the action has been registered on an element; until then the relay waits for its first element. */
|
|
350
|
+
private bound;
|
|
327
351
|
private listen;
|
|
352
|
+
/** Removes the relay from the fields the statement reads; a rollback restores it with the flag. */
|
|
353
|
+
private stopListening;
|
|
328
354
|
static get classIdentifier(): symbol;
|
|
329
355
|
get eager(): boolean;
|
|
330
356
|
boundToBinding(binding: FieldBase): void;
|
|
@@ -576,8 +602,6 @@ declare interface ElementSlots<T = any> {
|
|
|
576
602
|
parent: Container | undefined;
|
|
577
603
|
/** the name the containing Group holds this element under; undefined for a List row */
|
|
578
604
|
fieldName: string | undefined;
|
|
579
|
-
/** generation of the validators attached to the element; clearValidators() raises it */
|
|
580
|
-
validationEpoch: number;
|
|
581
605
|
/**
|
|
582
606
|
* The element's extended properties, typed by the element's X parameter. A write replaces the object instead of
|
|
583
607
|
* modifying it, so an effect that read the slot re-runs on the write, and a rollback restores the object the
|
|
@@ -631,15 +655,24 @@ export declare class EnabledChangingAction extends FieldActionBase {
|
|
|
631
655
|
execute(field: FieldBase, supr: FieldActionExecute, newValue: boolean, oldValue: boolean): boolean;
|
|
632
656
|
}
|
|
633
657
|
|
|
658
|
+
/**
|
|
659
|
+
* The namespace of the error codes this library declares. A code the library raises is `${ERROR_NAMESPACE}.<code>`,
|
|
660
|
+
* such as `vue-forms.required`.
|
|
661
|
+
*/
|
|
662
|
+
export declare const ERROR_NAMESPACE = "vue-forms";
|
|
663
|
+
|
|
634
664
|
/**
|
|
635
665
|
* The content of an error: what failed, the values it failed with, an English sentence describing it, and its
|
|
636
666
|
* origin. An error the application builds from a server's response has the same content, so a renderer converts
|
|
637
667
|
* validator and server errors to text with one function.
|
|
638
668
|
*/
|
|
639
669
|
export declare interface ErrorDescription {
|
|
640
|
-
/**
|
|
670
|
+
/**
|
|
671
|
+
* Machine-readable identifier of what failed: `<namespace>.<code>`, such as `vue-forms.min_value`. The namespace
|
|
672
|
+
* names the package that declared the code.
|
|
673
|
+
*/
|
|
641
674
|
readonly code: string;
|
|
642
|
-
/** The values of the failure, such as `minValue` for `min_value`. */
|
|
675
|
+
/** The values of the failure, such as `minValue` for `vue-forms.min_value`. */
|
|
643
676
|
readonly params: Readonly<Record<string, unknown>>;
|
|
644
677
|
/** The failure in English, plain text, with `params` substituted. */
|
|
645
678
|
readonly detail: string;
|
|
@@ -1112,10 +1145,7 @@ export declare abstract class FieldBase<T = any, X extends object = Extras> {
|
|
|
1112
1145
|
protected get boundActions(): ActionsMap | undefined;
|
|
1113
1146
|
/** Records that `binding` was made from this element, so a later registration can reach it. */
|
|
1114
1147
|
protected noteBinding(binding: FieldBase): void;
|
|
1115
|
-
/**
|
|
1116
|
-
* The live bindings made from this element's declaration, and the declaration itself. Dead references are removed
|
|
1117
|
-
* when found, so the set does not grow over the life of a long-lived declaration.
|
|
1118
|
-
*/
|
|
1148
|
+
/** The live bindings made from this element's declaration and the declaration; removes the dead references. */
|
|
1119
1149
|
protected get boundElements(): FieldBase[];
|
|
1120
1150
|
/**
|
|
1121
1151
|
* The map registrations go into: the declaration's. The map is created on the first registration and assigned to
|
|
@@ -1185,8 +1215,9 @@ export declare abstract class FieldBase<T = any, X extends object = Extras> {
|
|
|
1185
1215
|
* Makes this element the container of `child`: it sets the back-reference, records the name a Group holds the
|
|
1186
1216
|
* child under, and adds the child to the invalid count. An element belongs to one container at a time, so a
|
|
1187
1217
|
* child that already has a parent throws a TypeError; releaseChild() removes the link, after which the element
|
|
1188
|
-
* can be taken by another container.
|
|
1189
|
-
*
|
|
1218
|
+
* can be taken by another container. A container cannot take itself or a container above it, which also throws a
|
|
1219
|
+
* TypeError: the parent links would form a cycle, and a walk up them would not end. The child's state is private
|
|
1220
|
+
* to FieldBase, so a container writes the two slots through this method.
|
|
1190
1221
|
*/
|
|
1191
1222
|
protected takeChild(child: FieldBase, fieldName?: string): void;
|
|
1192
1223
|
/** Adds a child to this element's invalid count; a container calls it after setting the child's parent link. */
|
|
@@ -1399,19 +1430,19 @@ export declare abstract class FieldBase<T = any, X extends object = Extras> {
|
|
|
1399
1430
|
*/
|
|
1400
1431
|
unregisterAction(action: FieldActionBase): boolean;
|
|
1401
1432
|
/**
|
|
1402
|
-
*
|
|
1403
|
-
* registration is not in the state slots the snapshot covers, so it registers its own undo
|
|
1433
|
+
* Registers `action` on the declaration, binds it to the existing bindings and registers an undo for a rollback.
|
|
1434
|
+
* The registration is not in the state slots the snapshot covers, so it registers its own undo, before any call
|
|
1435
|
+
* that can throw: a registration that fails part way is undone with the transaction.
|
|
1436
|
+
*/
|
|
1437
|
+
private register;
|
|
1438
|
+
/**
|
|
1439
|
+
* Asks the actions of `actions` to release themselves if abandoned (see `ReleaseIfAbandoned`), if a minute or more
|
|
1440
|
+
* has passed since the last time. A map is checked only when an action is registered on it, with no timer.
|
|
1404
1441
|
*/
|
|
1405
|
-
private
|
|
1442
|
+
private releaseAbandoned;
|
|
1406
1443
|
triggerAction<T2 extends FieldActionBase>(actionClass: (abstract new (...args: any[]) => T2) & {
|
|
1407
1444
|
classIdentifier: symbol;
|
|
1408
1445
|
}, ...params: any[]): any;
|
|
1409
|
-
/**
|
|
1410
|
-
* Generation counter of the validators attached to this field. A Validator reads it when a run starts and drops
|
|
1411
|
-
* a result whose epoch no longer matches, so a validation still in flight when clearValidators() is called
|
|
1412
|
-
* cannot push an error onto a field that no longer has the validator that produced it.
|
|
1413
|
-
*/
|
|
1414
|
-
get [ValidationEpoch](): number;
|
|
1415
1446
|
clearValidators(): void;
|
|
1416
1447
|
}
|
|
1417
1448
|
|
|
@@ -1521,6 +1552,7 @@ declare namespace Form {
|
|
|
1521
1552
|
ListItemInput,
|
|
1522
1553
|
List,
|
|
1523
1554
|
NullableList,
|
|
1555
|
+
ERROR_NAMESPACE,
|
|
1524
1556
|
ErrorPolicies,
|
|
1525
1557
|
ErrorPolicy,
|
|
1526
1558
|
ErrorPolicyRule,
|
|
@@ -1591,6 +1623,8 @@ export declare class Group<T extends GenericFieldsInterface = GenericFieldsInter
|
|
|
1591
1623
|
private static setEntry;
|
|
1592
1624
|
/** Removes one entry from the member map. */
|
|
1593
1625
|
private static dropEntry;
|
|
1626
|
+
/** Replaces the entries of the member map with `entries`, in their order. */
|
|
1627
|
+
private static restoreEntries;
|
|
1594
1628
|
private static isValidFields;
|
|
1595
1629
|
/**
|
|
1596
1630
|
* Builds a group from plain data, so that its `fullValue` is `data`: a plain object becomes a `Group`, an array a
|
|
@@ -1727,7 +1761,7 @@ declare class InAllowedValues<T = any> extends Validator {
|
|
|
1727
1761
|
/**
|
|
1728
1762
|
* Installs `plugin` for every element, including the ones already built: a hook runs on the next write. A plugin
|
|
1729
1763
|
* installed twice runs twice. Returns a function that uninstalls it; values stored while it was installed are kept
|
|
1730
|
-
* as they are.
|
|
1764
|
+
* as they are. Where `setup` throws, the plugin is not installed and the exception is rethrown.
|
|
1731
1765
|
*/
|
|
1732
1766
|
export declare function installPlugin(plugin: Plugin_2): () => void;
|
|
1733
1767
|
|
|
@@ -2248,7 +2282,7 @@ declare class Transaction {
|
|
|
2248
2282
|
/**
|
|
2249
2283
|
* Registers work that runs after the transaction commits, and not at all if it is rolled back. An operation uses
|
|
2250
2284
|
* it to defer a step that cannot be undone (for example, cancelling work in flight) until its change is
|
|
2251
|
-
* committed.
|
|
2285
|
+
* committed. The work runs after the transaction is closed, so a write it makes opens a transaction of its own.
|
|
2252
2286
|
*/
|
|
2253
2287
|
whenCommitted(work: () => void): void;
|
|
2254
2288
|
/**
|
|
@@ -2273,6 +2307,12 @@ declare class Transaction {
|
|
|
2273
2307
|
* is dirty.
|
|
2274
2308
|
*/
|
|
2275
2309
|
commit(): void;
|
|
2310
|
+
/**
|
|
2311
|
+
* Runs the work registered with whenCommitted, then the `onCommit` hooks. It is called after the transaction is
|
|
2312
|
+
* closed, so a write made here opens a transaction of its own and is announced, and an exception does not roll
|
|
2313
|
+
* back the committed change. Every step runs; the first exception thrown is rethrown after the last one.
|
|
2314
|
+
*/
|
|
2315
|
+
settle(): void;
|
|
2276
2316
|
/**
|
|
2277
2317
|
* The dirty participants a pass visits, one bucket per nesting depth; within a depth they keep enrolment order.
|
|
2278
2318
|
* A nesting depth is a small integer, so bucketing replaces a comparison sort: a whole-list assignment enrols one
|
|
@@ -2356,9 +2396,6 @@ declare interface TxStructuralEvent {
|
|
|
2356
2396
|
index: number;
|
|
2357
2397
|
}
|
|
2358
2398
|
|
|
2359
|
-
/** Key of the `FieldBase` getter for the generation counter of its validators; the package does not export it. */
|
|
2360
|
-
declare const ValidationEpoch: unique symbol;
|
|
2361
|
-
|
|
2362
2399
|
/**
|
|
2363
2400
|
* An error on an element. It is data: the library does not render it. A renderer chooses the text for `code` and
|
|
2364
2401
|
* `params` and falls back to `detail`.
|
|
@@ -2369,8 +2406,8 @@ export declare class ValidationError implements ErrorDescription {
|
|
|
2369
2406
|
readonly detail: string;
|
|
2370
2407
|
private readonly statedOrigin?;
|
|
2371
2408
|
/**
|
|
2372
|
-
* @param code Machine-readable identifier of what failed,
|
|
2373
|
-
* @param params The values of the failure, such as `minValue` for `min_value`.
|
|
2409
|
+
* @param code Machine-readable identifier of what failed, `<namespace>.<code>`. Stored as given.
|
|
2410
|
+
* @param params The values of the failure, such as `minValue` for `vue-forms.min_value`.
|
|
2374
2411
|
* @param detail The failure in English, plain text. Stored as given.
|
|
2375
2412
|
* @param statedOrigin The origin of the error, if its author sets it; see `origin`.
|
|
2376
2413
|
*/
|
|
@@ -2394,11 +2431,14 @@ export declare class ValidationError implements ErrorDescription {
|
|
|
2394
2431
|
* renderer has a text for that code.
|
|
2395
2432
|
*/
|
|
2396
2433
|
declare type ValidationErrorOptions = {
|
|
2397
|
-
/**
|
|
2434
|
+
/**
|
|
2435
|
+
* The error's `code`, used as given. Defaults to the validator's own, such as `vue-forms.required`. The
|
|
2436
|
+
* application prefixes its own codes with a namespace of its own.
|
|
2437
|
+
*/
|
|
2398
2438
|
code?: string;
|
|
2399
2439
|
detail?: never;
|
|
2400
2440
|
} | {
|
|
2401
|
-
/** The error's `code
|
|
2441
|
+
/** The error's `code`, used as given. */
|
|
2402
2442
|
code: string;
|
|
2403
2443
|
/** The error's English `detail`, plain text. `{name}` placeholders are replaced with the error's `params`. */
|
|
2404
2444
|
detail?: string;
|
|
@@ -2440,13 +2480,15 @@ declare class Validator<T = any> extends ValueChangedAction {
|
|
|
2440
2480
|
* remaining validators. Otherwise the field would stay invalid on an error no validator removes.
|
|
2441
2481
|
*
|
|
2442
2482
|
* A run in flight over the field is cancelled when the removal is committed, not earlier: a rollback restores the
|
|
2443
|
-
* validator
|
|
2444
|
-
*
|
|
2483
|
+
* validator, and the run, still active, then applies its result. Cancelling at the removal would leave the field
|
|
2484
|
+
* valid over an unchecked value after a rollback. A run started after the removal, by registering the validator
|
|
2485
|
+
* again in the same transaction, is not cancelled.
|
|
2445
2486
|
*/
|
|
2446
2487
|
unregisterFrom(field: FieldBase): void;
|
|
2447
2488
|
/**
|
|
2448
|
-
* Cancels the asynchronous run in flight over `field`, if any. It is called
|
|
2449
|
-
*
|
|
2489
|
+
* Cancels the asynchronous run in flight over `field`, if any. It is called once the validator's removal from the
|
|
2490
|
+
* field is committed: the run number advances, so the run's result is discarded and its signal aborts. The other
|
|
2491
|
+
* validators of the field keep their runs.
|
|
2450
2492
|
*/
|
|
2451
2493
|
protected abandonRun(field: FieldBase): void;
|
|
2452
2494
|
/**
|
|
@@ -2463,7 +2505,8 @@ declare class Validator<T = any> extends ValueChangedAction {
|
|
|
2463
2505
|
protected newBindingState(): ValidatorBindingState;
|
|
2464
2506
|
/**
|
|
2465
2507
|
* Returns the error a built-in validator reports: `code` and `detail` from `options` if set, the validator's own
|
|
2466
|
-
* otherwise, with `params` substituted into the detail.
|
|
2508
|
+
* otherwise, with `params` substituted into the detail. Both codes are used as given: a built-in validator passes
|
|
2509
|
+
* its own code as `vue-forms.<code>`, and a subclass of the application passes a code in a namespace of its own.
|
|
2467
2510
|
*/
|
|
2468
2511
|
protected errorFor(options: ValidationErrorOptions | undefined, code: string, detail: string, params: Record<string, unknown>): ValidationError;
|
|
2469
2512
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamicforms/vue-forms",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "3.0.0-alpha.
|
|
4
|
+
"version": "3.0.0-alpha.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "Reactive forms and application state for Vue.js: validation, rules between fields, transactions and lists. UI-agnostic and TypeScript-first.",
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"build": "vite build",
|
|
29
29
|
"prepack": "npm run build",
|
|
30
30
|
"test": "vitest run --coverage",
|
|
31
|
-
"lint": "
|
|
32
|
-
"lint:ci": "eslint src && vue-tsc --noEmit",
|
|
31
|
+
"lint": "node scripts/lint.mjs",
|
|
33
32
|
"docs:dev": "npm run docs:dev -w docs",
|
|
34
33
|
"docs:build": "npm run docs:build -w docs",
|
|
35
34
|
"docs:preview": "npm run docs:preview -w docs"
|
|
@@ -77,6 +76,7 @@
|
|
|
77
76
|
"@vue/test-utils": "^2.2.4",
|
|
78
77
|
"@vue/tsconfig": "^0.7.0",
|
|
79
78
|
"baseline-browser-mapping": "^2.8.31",
|
|
79
|
+
"esbuild": "^0.28.2",
|
|
80
80
|
"eslint": "^10.4.0",
|
|
81
81
|
"eslint-config-prettier": "^10.1.8",
|
|
82
82
|
"eslint-config-velis": "^3.0.0",
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
"eslint-plugin-unicorn": "^73.0.0",
|
|
87
87
|
"eslint-plugin-vue": "^10.10.0",
|
|
88
88
|
"jsdom": "^26.0.0",
|
|
89
|
+
"markdownlint-cli2": "^0.18.1",
|
|
89
90
|
"prettier": "^3.9.6",
|
|
90
91
|
"rollup-plugin-visualizer": "^5.14.0",
|
|
91
92
|
"typescript": "^5",
|
package/readme.md
CHANGED
|
@@ -60,7 +60,8 @@ npm install @dynamicforms/vue-forms
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
The package is ESM-only and requires Node 22 or newer. A CommonJS consumer reaches it through `require()` of an ES
|
|
63
|
-
module, which Node supports without a flag from 22.12; on 22.0–22.11 it needs `--experimental-require-module`. Type
|
|
63
|
+
module, which Node supports without a flag from 22.12; on 22.0–22.11 it needs `--experimental-require-module`. Type
|
|
64
|
+
definitions ship with the build. The package ships no components and no styles.
|
|
64
65
|
|
|
65
66
|
## Basic Usage Example
|
|
66
67
|
|
|
@@ -185,7 +186,7 @@ import { Field, Group, Validators } from '@dynamicforms/vue-forms';
|
|
|
185
186
|
const validatedForm = new Group({
|
|
186
187
|
// Required field
|
|
187
188
|
username: new Field({
|
|
188
|
-
validators: [new Validators.Required({ code: 'username_required', detail: 'Username is required' })]
|
|
189
|
+
validators: [new Validators.Required({ code: 'app.username_required', detail: 'Username is required' })]
|
|
189
190
|
}),
|
|
190
191
|
|
|
191
192
|
// Email validation with pattern
|
|
@@ -193,7 +194,7 @@ const validatedForm = new Group({
|
|
|
193
194
|
validators: [
|
|
194
195
|
new Validators.Pattern(
|
|
195
196
|
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
|
196
|
-
{ code: 'invalid_email', detail: 'Please enter a valid email address' }
|
|
197
|
+
{ code: 'app.invalid_email', detail: 'Please enter a valid email address' }
|
|
197
198
|
)
|
|
198
199
|
]
|
|
199
200
|
}),
|
|
@@ -202,7 +203,7 @@ const validatedForm = new Group({
|
|
|
202
203
|
age: new Field({
|
|
203
204
|
value: 25,
|
|
204
205
|
validators: [
|
|
205
|
-
new Validators.ValueInRange(18, 100, { code: 'age_range', detail: 'Age must be between {minValue} and {maxValue}' })
|
|
206
|
+
new Validators.ValueInRange(18, 100, { code: 'app.age_range', detail: 'Age must be between {minValue} and {maxValue}' })
|
|
206
207
|
]
|
|
207
208
|
}),
|
|
208
209
|
|
|
@@ -216,7 +217,7 @@ const validatedForm = new Group({
|
|
|
216
217
|
// Text length validation
|
|
217
218
|
bio: new Field({
|
|
218
219
|
validators: [
|
|
219
|
-
new Validators.LengthInRange(10, 200, { code: 'bio_length', detail: 'Bio must be between 10 and 200 characters' })
|
|
220
|
+
new Validators.LengthInRange(10, 200, { code: 'app.bio_length', detail: 'Bio must be between 10 and 200 characters' })
|
|
220
221
|
]
|
|
221
222
|
})
|
|
222
223
|
});
|
|
@@ -227,10 +228,12 @@ invalid immediately. `field.touched` determines when the UI shows the errors. `R
|
|
|
227
228
|
measuring it, so a value of only spaces counts as empty; `new Validators.Required({ trim: false })` keeps spaces as
|
|
228
229
|
part of the value.
|
|
229
230
|
|
|
230
|
-
An error is data: a `code` (`required`, `pattern`, `min_length`, …), the `params` it
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
An error is data: a `code` (`vue-forms.required`, `vue-forms.pattern`, `vue-forms.min_length`, …), the `params` it
|
|
232
|
+
failed with, and an English `detail`. A code is `<namespace>.<code>`; the library's namespace is `vue-forms`,
|
|
233
|
+
exported as `ERROR_NAMESPACE`. The library does not render an error. The application, or a UI library such as
|
|
234
|
+
`@dynamicforms/vuetify-inputs`, converts it into text, translated by its code. A validator's last argument,
|
|
235
|
+
`{ code, detail }`, replaces the validator's default code and English detail; the library uses that code as given,
|
|
236
|
+
and the application prefixes its own codes with a namespace of its own.
|
|
234
237
|
|
|
235
238
|
A validation function may return a `Promise`; `field.validating` is `true` while it runs, and only the newest run
|
|
236
239
|
determines the result. [Asynchronous validation](https://docs.velis.si/dynamicforms/vue-forms/api/validators#asynchronous-validation)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-_vVZW3p9.js","names":[],"sources":["../../src/plugins/devtools/registry.ts"],"sourcesContent":["import { type ComponentInternalInstance, getCurrentInstance, getCurrentScope, onScopeDispose } from 'vue';\n\nimport type { FieldBase } from '../../field-base';\nimport type { PluginContext } from '../../plugins';\n\n/** Which elements the devtools list: every root element except the hidden ones, or only the described ones. */\nexport type DevtoolsRegistration = 'opt-out' | 'opt-in';\n\n/** What an application states about an element for the devtools. */\nexport interface StateDescription {\n /** The name the devtools show; defaults to the element's class and a number. */\n name?: string;\n /** The file the element is defined in; defaults to the file of the code that constructed it. */\n file?: string;\n}\n\n/** What the registry knows about one element. */\nexport interface Entry {\n id: string;\n element: WeakRef<FieldBase>;\n /** the stack at construction; its text is built on the first read, when the devtools show the entry */\n created?: Error;\n /** the component whose setup constructed the element */\n instance?: WeakRef<ComponentInternalInstance>;\n description: StateDescription;\n hidden: boolean;\n described: boolean;\n}\n\nconst entries = new Map<string, Entry>();\nconst byElement = new WeakMap<FieldBase, Entry>();\nlet nextId = 1;\nlet registration: DevtoolsRegistration = 'opt-out';\nlet enabled = true;\nlet changed: (() => void) | undefined;\nlet context: PluginContext | undefined;\n\n/** Records the context the devtools plugin received; it tells a binding or an item template from a root. */\nexport function useContext(installed: PluginContext): void {\n context = installed;\n}\n\n/** Called by the devtools plugin; runs after a change the devtools show. */\nexport function onRegistryChanged(listener: () => void): void {\n changed = listener;\n}\n\n/**\n * Records an element at construction: the component that constructs it and, where `location` is true, the stack\n * that leads to it.\n */\nexport function noteElement(element: FieldBase, location: boolean): void {\n let created: Error | undefined;\n if (location) {\n const limit = Error.stackTraceLimit;\n Error.stackTraceLimit = 20;\n created = new Error();\n Error.stackTraceLimit = limit;\n }\n const instance = getCurrentInstance();\n const entry: Entry = {\n id: String(nextId++),\n element: new WeakRef(element),\n created,\n instance: instance ? new WeakRef(instance) : undefined,\n description: {},\n hidden: false,\n described: false,\n };\n entries.set(entry.id, entry);\n byElement.set(element, entry);\n // state a component constructs is listed while the component is mounted: an element is collected only when the\n // garbage collector runs, which can be long after the component was unmounted\n if (instance && getCurrentScope()) {\n onScopeDispose(() => {\n entries.delete(entry.id);\n changed?.();\n });\n }\n}\n\nexport function describe(element: FieldBase, description: StateDescription): void {\n const entry = byElement.get(element);\n if (!entry) return;\n entry.description = { ...entry.description, ...description };\n entry.described = true;\n entry.hidden = false;\n // an element its component handed on before unmounting is listed again, as global state\n if (!entries.has(entry.id)) {\n entry.instance = undefined;\n entries.set(entry.id, entry);\n }\n changed?.();\n}\n\n/**\n * Drops the stack captured for an element a container took: a member is shown inside its container, and its own\n * file is shown again only if the container releases it.\n */\nexport function forgetLocation(element: FieldBase): void {\n const entry = byElement.get(element);\n if (entry) entry.created = undefined;\n}\n\nexport function setHidden(element: FieldBase, hidden: boolean): void {\n const entry = byElement.get(element);\n if (!entry) return;\n entry.hidden = hidden;\n changed?.();\n}\n\nexport function setRegistration(mode: DevtoolsRegistration): void {\n registration = mode;\n changed?.();\n}\n\n/** Lists nothing while `on` is false. */\nexport function setEnabled(on: boolean): void {\n enabled = on;\n changed?.();\n}\n\n/** Reports a committed change. */\nexport function noteChange(): void {\n changed?.();\n}\n\n/** The entry of an element, where it has one. */\nexport function entryOf(element: FieldBase): Entry | undefined {\n return byElement.get(element);\n}\n\nexport function entryById(id: string): Entry | undefined {\n return entries.get(id);\n}\n\n/**\n * The listed elements: alive, not held by a container, not a binding or an item template, not hidden, and in\n * opt-in mode described. Entries whose element was collected are dropped here. Nothing is listed while the devtools\n * are turned off.\n */\nexport function listed(): { entry: Entry; element: FieldBase }[] {\n const out: { entry: Entry; element: FieldBase }[] = [];\n if (!enabled) return out;\n entries.forEach((entry, id) => {\n const element = entry.element.deref();\n if (!element) {\n entries.delete(id);\n return;\n }\n if (entry.hidden || element.parent || context?.isInternal(element)) return;\n if (registration === 'opt-in' && !entry.described) return;\n out.push({ entry, element });\n });\n return out;\n}\n\n/**\n * The path prefix of the library's own files: `…/src/` where the source is served, or `…/dist/` where the build is.\n * Frames from it are skipped when the caller's file is looked up.\n */\nfunction libraryPrefix(): string {\n // the first frame of a stack taken here is this module, served from the library's source or from a chunk of its\n // build, which lives in dist/ beside the entry files\n const own = /(?:https?:\\/\\/[^/\\s]+|file:\\/\\/)?(\\/[^\\s?):]+\\.[cm]?[jt]s)/.exec(new Error().stack ?? '')?.[1] ?? '';\n if (own.includes('/src/plugins/devtools/')) return own.slice(0, own.indexOf('/src/') + 5);\n if (own.includes('/dist/')) return own.slice(0, own.lastIndexOf('/dist/') + 6);\n return own;\n}\n\n/** A frame of a stack: the function, where the stack names one, and the file, line and column. */\nexport interface StackFrame {\n name?: string;\n /** a path relative to the served root: Vite serves a project file at `/src/…` */\n file: string;\n line: number;\n column: number;\n}\n\n// a Chrome frame is ` at name (url:line:column)` or ` at url:line:column`; a Firefox and a Safari frame is\n// `name@url:line:column`\nconst chromeFrame = /^\\s*at (?:(.*?) \\()?(\\S+?):(\\d+):(\\d+)\\)?$/;\nconst firefoxFrame = /^(.*?)@(\\S+?):(\\d+):(\\d+)$/;\nconst framePath = /^(?:[a-z]+:\\/\\/[^/\\s]*)?(\\/[^\\s?]+\\.(?:[cm]?[jt]sx?|vue))(?:\\?\\S*)?$/;\n\n/**\n * The frames of `stack` outside the library and `node_modules`, outermost last. A frame without a URL of a script\n * or a `.vue` file is left out.\n */\nexport function callerFrames(stack: string | undefined, library = libraryPrefix()): StackFrame[] {\n const frames: StackFrame[] = [];\n for (const text of stack?.split('\\n') ?? []) {\n const match = chromeFrame.exec(text) ?? firefoxFrame.exec(text);\n const path = match && framePath.exec(match[2])?.[1];\n if (!path || path.startsWith(library) || path.includes('/node_modules/')) continue;\n frames.push({\n name: match[1] || undefined,\n file: path.replace(/^\\//, ''),\n line: Number(match[3]),\n column: Number(match[4]),\n });\n }\n return frames;\n}\n\n/** The file of the first frame of `stack` outside the library and `node_modules`; undefined where there is none. */\nexport function callerFile(stack: string | undefined, library = libraryPrefix()): string | undefined {\n return callerFrames(stack, library)[0]?.file;\n}\n\n/** The names of the components from the root of the app to `instance`, joined by ` > `. */\nexport function componentPath(instance: ComponentInternalInstance): string {\n const names: string[] = [];\n for (let at: ComponentInternalInstance | null = instance; at; at = at.parent) {\n const type = at.type as { name?: string; __name?: string; __file?: string };\n names.unshift(type.name ?? type.__name ?? type.__file?.split('/').pop() ?? 'Anonymous');\n }\n return names.join(' > ');\n}\n"],"mappings":"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"}
|