@vaadin/hilla-lit-form 24.4.0-alpha1

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.
@@ -0,0 +1,6 @@
1
+ import { commands, extensions } from '../../../.lintstagedrc.js';
2
+
3
+ export default {
4
+ [`src/**/*.{${extensions}}`]: commands,
5
+ [`test/**/*.{${extensions}}`]: commands,
6
+ };
package/Binder.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { type BinderConfiguration, BinderRoot } from './BinderRoot.js';
2
+ import type { AbstractModel, DetachedModelConstructor, Value } from './Models.js';
3
+ /**
4
+ * A Binder controls all aspects of a single form.
5
+ * Typically, it is used to get and set the form value,
6
+ * access the form model, validate, reset, and submit the form.
7
+ *
8
+ * @typeParam T - Type of the value that binds to a form
9
+ * @typeParam M - Type of the model that describes the structure of the value
10
+ */
11
+ export declare class Binder<M extends AbstractModel> extends BinderRoot<M> {
12
+ readonly ['constructor']: Omit<typeof Binder<M>, 'constructor'>;
13
+ context: Element;
14
+ /**
15
+ *
16
+ * @param context - The form view component instance to update.
17
+ * @param Model - The constructor (the class reference) of the form model. The Binder instantiates the top-level model
18
+ * @param config - The options object, which can be used to config the onChange and onSubmit callbacks.
19
+ *
20
+ * ```
21
+ * binder = new Binder(orderView, OrderModel);
22
+ * or
23
+ * binder = new Binder(orderView, OrderModel, {onSubmit: async (order) => {endpoint.save(order)}});
24
+ * ```
25
+ */
26
+ constructor(context: Element, Model: DetachedModelConstructor<M>, config?: BinderConfiguration<Value<M>>);
27
+ }
28
+ //# sourceMappingURL=Binder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Binder.d.ts","sourceRoot":"","sources":["src/Binder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,mBAAmB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAwB,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAElF;;;;;;;GAOG;AACH,qBAAa,MAAM,CAAC,CAAC,SAAS,aAAa,CAAE,SAAQ,UAAU,CAAC,CAAC,CAAC;IAChE,SAAiB,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAExE,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;;;;;;;;OAWG;gBACS,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CAczG"}
package/Binder.js ADDED
@@ -0,0 +1,29 @@
1
+ import { BinderRoot } from "./BinderRoot.js";
2
+ class Binder extends BinderRoot {
3
+ context;
4
+ /**
5
+ *
6
+ * @param context - The form view component instance to update.
7
+ * @param Model - The constructor (the class reference) of the form model. The Binder instantiates the top-level model
8
+ * @param config - The options object, which can be used to config the onChange and onSubmit callbacks.
9
+ *
10
+ * ```
11
+ * binder = new Binder(orderView, OrderModel);
12
+ * or
13
+ * binder = new Binder(orderView, OrderModel, {onSubmit: async (order) => {endpoint.save(order)}});
14
+ * ```
15
+ */
16
+ constructor(context, Model, config) {
17
+ const changeCallback = config?.onChange ?? (typeof context.requestUpdate === "function" ? () => context.requestUpdate() : void 0);
18
+ super(Model, {
19
+ ...config ?? {},
20
+ onChange: changeCallback,
21
+ context
22
+ });
23
+ this.context = context;
24
+ }
25
+ }
26
+ export {
27
+ Binder
28
+ };
29
+ //# sourceMappingURL=Binder.js.map
package/Binder.js.map ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["src/Binder.ts"],
4
+ "sourcesContent": ["import type { LitElement } from 'lit';\nimport { type BinderConfiguration, BinderRoot } from './BinderRoot.js';\nimport type { AbstractModel, DetachedModelConstructor, Value } from './Models.js';\n\n/**\n * A Binder controls all aspects of a single form.\n * Typically, it is used to get and set the form value,\n * access the form model, validate, reset, and submit the form.\n *\n * @typeParam T - Type of the value that binds to a form\n * @typeParam M - Type of the model that describes the structure of the value\n */\nexport class Binder<M extends AbstractModel> extends BinderRoot<M> {\n declare readonly ['constructor']: Omit<typeof Binder<M>, 'constructor'>;\n\n context: Element;\n\n /**\n *\n * @param context - The form view component instance to update.\n * @param Model - The constructor (the class reference) of the form model. The Binder instantiates the top-level model\n * @param config - The options object, which can be used to config the onChange and onSubmit callbacks.\n *\n * ```\n * binder = new Binder(orderView, OrderModel);\n * or\n * binder = new Binder(orderView, OrderModel, {onSubmit: async (order) => {endpoint.save(order)}});\n * ```\n */\n constructor(context: Element, Model: DetachedModelConstructor<M>, config?: BinderConfiguration<Value<M>>) {\n const changeCallback =\n config?.onChange ??\n (typeof (context as LitElement).requestUpdate === 'function'\n ? () => (context as LitElement).requestUpdate()\n : undefined);\n\n super(Model, {\n ...(config ?? {}),\n onChange: changeCallback,\n context,\n });\n this.context = context;\n }\n}\n"],
5
+ "mappings": "AACA,SAAmC,kBAAkB;AAW9C,MAAM,eAAwC,WAAc;AAAA,EAGjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,YAAY,SAAkB,OAAoC,QAAwC;AACxG,UAAM,iBACJ,QAAQ,aACP,OAAQ,QAAuB,kBAAkB,aAC9C,MAAO,QAAuB,cAAc,IAC5C;AAEN,UAAM,OAAO;AAAA,MACX,GAAI,UAAU,CAAC;AAAA,MACf,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AACD,SAAK,UAAU;AAAA,EACjB;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,123 @@
1
+ import type { BinderRoot } from './BinderRoot.js';
2
+ import { AbstractModel, type ArrayItemModel, type Value } from './Models.js';
3
+ import type { ClassStaticProperties } from './types.js';
4
+ import type { Validator, ValueError } from './Validation.js';
5
+ import { _validity } from './Validity.js';
6
+ export declare const _updateValidation: unique symbol;
7
+ export declare const _update: unique symbol;
8
+ export declare const _setErrorsWithDescendants: unique symbol;
9
+ export declare const _clearValidation: unique symbol;
10
+ export declare function getBinderNode<M extends AbstractModel>(model: M): BinderNode<M>;
11
+ export declare const CHANGED: Event;
12
+ /**
13
+ * The BinderNode\<M\> class provides the form binding related APIs
14
+ * with respect to a particular model instance.
15
+ *
16
+ * Structurally, model instances form a tree, in which the object
17
+ * and array models have child nodes of field and array item model
18
+ * instances.
19
+ */
20
+ export declare class BinderNode<M extends AbstractModel = AbstractModel> extends EventTarget {
21
+ #private;
22
+ readonly ['constructor']: ClassStaticProperties<typeof BinderNode<M>>;
23
+ readonly model: M;
24
+ /**
25
+ * The validity state read from the bound element, if any. Represents the
26
+ * HTML element internal validation.
27
+ *
28
+ * For elements with `validity.valid === false`, the value in the
29
+ * bound element is considered as invalid.
30
+ */
31
+ [_validity]?: ValidityState;
32
+ constructor(model: M);
33
+ /**
34
+ * The binder for the top-level model.
35
+ */
36
+ get binder(): BinderRoot;
37
+ /**
38
+ * The default value related to the model
39
+ */
40
+ get defaultValue(): Value<M> | undefined;
41
+ /**
42
+ * True if the current value is different from the defaultValue.
43
+ */
44
+ get dirty(): boolean;
45
+ /**
46
+ * The combined array of all errors for this node’s model and all its nested
47
+ * models
48
+ */
49
+ get errors(): readonly ValueError[];
50
+ /**
51
+ * Indicates if there is any error for the node's model.
52
+ */
53
+ get invalid(): boolean;
54
+ /**
55
+ * The name generated from the model structure, used to set the name
56
+ * attribute on the field components.
57
+ */
58
+ get name(): string;
59
+ /**
60
+ * The array of validation errors directly related with the model.
61
+ */
62
+ get ownErrors(): ReadonlyArray<ValueError<Value<M>>>;
63
+ /**
64
+ * The parent node, if this binder node corresponds to a nested model,
65
+ * otherwise undefined for the top-level binder.
66
+ */
67
+ get parent(): BinderNode | undefined;
68
+ /**
69
+ * True if the value is required to be non-empty.
70
+ */
71
+ get required(): boolean;
72
+ /**
73
+ * The array of validators for the model. The default value is defined in the
74
+ * model.
75
+ */
76
+ get validators(): ReadonlyArray<Validator<Value<M>>>;
77
+ set validators(validators: ReadonlyArray<Validator<Value<M>>>);
78
+ /**
79
+ * The current value related to the model
80
+ */
81
+ get value(): Value<M> | undefined;
82
+ set value(value: Value<M> | undefined);
83
+ /**
84
+ * True if the bound field was ever focused and blurred by the user.
85
+ */
86
+ get visited(): boolean;
87
+ set visited(v: boolean);
88
+ /**
89
+ * A helper method to add a validator
90
+ *
91
+ * @param validator - a validator
92
+ */
93
+ addValidator(validator: Validator<Value<M>>): void;
94
+ /**
95
+ * Append an item to the array value.
96
+ *
97
+ * Requires the context model to be an array reference.
98
+ *
99
+ * @param item - optional new item value, an empty item is
100
+ * appended if the argument is omitted
101
+ */
102
+ appendItem(item?: Value<ArrayItemModel<M>>): void;
103
+ /**
104
+ * Returns a binder node for the nested model instance.
105
+ *
106
+ * @param model - The nested model instance
107
+ */
108
+ for<N extends AbstractModel>(model: N): BinderNode<N>;
109
+ prependItem(item?: Value<ArrayItemModel<M>>): void;
110
+ removeSelf(): void;
111
+ /**
112
+ * Runs all validation callbacks potentially affecting this
113
+ * or any nested model. Returns the combined array of all
114
+ * errors as in the errors property.
115
+ */
116
+ validate(): Promise<readonly ValueError[]>;
117
+ protected [_clearValidation](): boolean;
118
+ protected [_setErrorsWithDescendants](errors?: readonly ValueError[]): void;
119
+ protected [_update](_?: Value<M>): void;
120
+ protected [_updateValidation](): Promise<void>;
121
+ initializeValue(forceInitialize?: boolean): void;
122
+ }
123
+ //# sourceMappingURL=BinderNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BinderNode.d.ts","sourceRoot":"","sources":["src/BinderNode.ts"],"names":[],"mappings":"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"}
package/BinderNode.js ADDED
@@ -0,0 +1,414 @@
1
+ import {
2
+ _createEmptyItemValue,
3
+ _key,
4
+ _parent,
5
+ _validators,
6
+ AbstractModel,
7
+ ArrayModel,
8
+ getObjectModelOwnAndParentGetters,
9
+ ObjectModel
10
+ } from "./Models.js";
11
+ import { ValidityStateValidator } from "./Validators.js";
12
+ import { _validity } from "./Validity.js";
13
+ const _updateValidation = Symbol("updateValidation");
14
+ const _update = Symbol("update");
15
+ const _setErrorsWithDescendants = Symbol("setErrorsWithDescendants");
16
+ const _clearValidation = Symbol("clearValidation");
17
+ const nodes = /* @__PURE__ */ new WeakMap();
18
+ function getBinderNode(model) {
19
+ let node = nodes.get(model);
20
+ if (!node) {
21
+ node = new BinderNode(model);
22
+ nodes.set(model, node);
23
+ }
24
+ return node;
25
+ }
26
+ function getErrorPropertyName(valueError) {
27
+ return typeof valueError.property === "string" ? valueError.property : getBinderNode(valueError.property).name;
28
+ }
29
+ function updateObjectOrArrayKey(model, value, key, keyValue) {
30
+ if (model instanceof ObjectModel) {
31
+ return {
32
+ ...value,
33
+ [key]: keyValue
34
+ };
35
+ }
36
+ if (keyValue === void 0) {
37
+ throw new TypeError("Unexpected undefined value");
38
+ }
39
+ if (model instanceof ArrayModel) {
40
+ const array = value.slice();
41
+ array[key] = keyValue;
42
+ return array;
43
+ }
44
+ throw new TypeError(`Unknown model type ${model.constructor.name}`);
45
+ }
46
+ const CHANGED = new Event("binder-node-changed");
47
+ class NotArrayModelError extends Error {
48
+ constructor() {
49
+ super("The model does not represent array");
50
+ }
51
+ }
52
+ class NotArrayItemModelError extends Error {
53
+ constructor() {
54
+ super("The model does not represent array item");
55
+ }
56
+ }
57
+ const defaultArrayItemCache = /* @__PURE__ */ new WeakMap();
58
+ class BinderNode extends EventTarget {
59
+ model;
60
+ /**
61
+ * The validity state read from the bound element, if any. Represents the
62
+ * HTML element internal validation.
63
+ *
64
+ * For elements with `validity.valid === false`, the value in the
65
+ * bound element is considered as invalid.
66
+ */
67
+ [_validity];
68
+ #ownErrors;
69
+ #validators;
70
+ #validityStateValidator;
71
+ #visited = false;
72
+ constructor(model) {
73
+ super();
74
+ this.model = model;
75
+ nodes.set(model, this);
76
+ this.#validityStateValidator = new ValidityStateValidator();
77
+ this.#validators = model[_validators];
78
+ if (this.constructor === BinderNode) {
79
+ this.initializeValue();
80
+ }
81
+ }
82
+ /**
83
+ * The binder for the top-level model.
84
+ */
85
+ get binder() {
86
+ const binder = this.parent?.binder;
87
+ if (!binder) {
88
+ throw new TypeError("BinderNode is detached");
89
+ }
90
+ return binder;
91
+ }
92
+ /**
93
+ * The default value related to the model
94
+ */
95
+ get defaultValue() {
96
+ const key = this.model[_key];
97
+ const parentDefaultValue = this.parent.defaultValue;
98
+ if (this.#isArrayItem() && !(key in parentDefaultValue)) {
99
+ if (defaultArrayItemCache.has(this.parent)) {
100
+ return defaultArrayItemCache.get(this.parent);
101
+ }
102
+ const value = this.model.constructor.createEmptyValue();
103
+ defaultArrayItemCache.set(this.parent, value);
104
+ return value;
105
+ }
106
+ return parentDefaultValue[key];
107
+ }
108
+ /**
109
+ * True if the current value is different from the defaultValue.
110
+ */
111
+ get dirty() {
112
+ return this.value !== this.defaultValue;
113
+ }
114
+ /**
115
+ * The combined array of all errors for this node’s model and all its nested
116
+ * models
117
+ */
118
+ get errors() {
119
+ return [...Array.from(this.#getChildBinderNodes(), (node) => node.errors).flat(), ...this.ownErrors];
120
+ }
121
+ /**
122
+ * Indicates if there is any error for the node's model.
123
+ */
124
+ get invalid() {
125
+ return this.errors.length > 0;
126
+ }
127
+ /**
128
+ * The name generated from the model structure, used to set the name
129
+ * attribute on the field components.
130
+ */
131
+ get name() {
132
+ let { model } = this;
133
+ let name = "";
134
+ while (model[_parent] instanceof AbstractModel) {
135
+ name = `${String(model[_key])}${name ? `.${name}` : ""}`;
136
+ model = model[_parent];
137
+ }
138
+ return name;
139
+ }
140
+ /**
141
+ * The array of validation errors directly related with the model.
142
+ */
143
+ get ownErrors() {
144
+ return this.#ownErrors ? this.#ownErrors : [];
145
+ }
146
+ /**
147
+ * The parent node, if this binder node corresponds to a nested model,
148
+ * otherwise undefined for the top-level binder.
149
+ */
150
+ get parent() {
151
+ const modelParent = this.model[_parent];
152
+ return modelParent instanceof AbstractModel ? getBinderNode(modelParent) : void 0;
153
+ }
154
+ /**
155
+ * True if the value is required to be non-empty.
156
+ */
157
+ get required() {
158
+ return this.#validators.some((validator) => validator.impliesRequired);
159
+ }
160
+ /**
161
+ * The array of validators for the model. The default value is defined in the
162
+ * model.
163
+ */
164
+ get validators() {
165
+ return this.#validators;
166
+ }
167
+ set validators(validators) {
168
+ this.#validators = validators;
169
+ this.dispatchEvent(CHANGED);
170
+ }
171
+ /**
172
+ * The current value related to the model
173
+ */
174
+ get value() {
175
+ if (!this.parent) {
176
+ return void 0;
177
+ }
178
+ let { value } = this.parent;
179
+ if (value === void 0) {
180
+ this.parent.initializeValue(true);
181
+ ({ value } = this.parent);
182
+ }
183
+ const key = this.model[_key];
184
+ return value[key];
185
+ }
186
+ set value(value) {
187
+ this.initializeValue();
188
+ this.#setValueState(value, void 0);
189
+ }
190
+ /**
191
+ * True if the bound field was ever focused and blurred by the user.
192
+ */
193
+ get visited() {
194
+ return this.#visited;
195
+ }
196
+ set visited(v) {
197
+ if (this.#visited !== v) {
198
+ this.#visited = v;
199
+ this[_updateValidation]().catch(() => {
200
+ });
201
+ this.dispatchEvent(CHANGED);
202
+ }
203
+ }
204
+ /**
205
+ * A helper method to add a validator
206
+ *
207
+ * @param validator - a validator
208
+ */
209
+ addValidator(validator) {
210
+ this.validators = [...this.#validators, validator];
211
+ this.dispatchEvent(CHANGED);
212
+ }
213
+ /**
214
+ * Append an item to the array value.
215
+ *
216
+ * Requires the context model to be an array reference.
217
+ *
218
+ * @param item - optional new item value, an empty item is
219
+ * appended if the argument is omitted
220
+ */
221
+ appendItem(item) {
222
+ if (this.#isArray()) {
223
+ const itemValueOrEmptyValue = item ?? this.model[_createEmptyItemValue]();
224
+ const newValue = [...this.value ?? [], itemValueOrEmptyValue];
225
+ const newDefaultValue = [...this.defaultValue ?? [], itemValueOrEmptyValue];
226
+ this.#setValueState(newValue, newDefaultValue);
227
+ } else {
228
+ throw new NotArrayModelError();
229
+ }
230
+ }
231
+ /**
232
+ * Returns a binder node for the nested model instance.
233
+ *
234
+ * @param model - The nested model instance
235
+ */
236
+ for(model) {
237
+ const binderNode = getBinderNode(model);
238
+ if (binderNode.binder !== this.binder) {
239
+ throw new Error("Unknown binder");
240
+ }
241
+ return binderNode;
242
+ }
243
+ prependItem(item) {
244
+ if (this.#isArray()) {
245
+ const itemValueOrEmptyValue = item ?? this.model[_createEmptyItemValue]();
246
+ const newValue = [itemValueOrEmptyValue, ...this.value ?? []];
247
+ const newDefaultValue = [itemValueOrEmptyValue, ...this.defaultValue ?? []];
248
+ this.#setValueState(newValue, newDefaultValue);
249
+ } else {
250
+ throw new NotArrayModelError();
251
+ }
252
+ }
253
+ removeSelf() {
254
+ if (this.#isArrayItem()) {
255
+ const newValue = (this.parent.value ?? []).filter((_, i) => i !== this.model[_key]);
256
+ const newDefaultValue = (this.parent.defaultValue ?? []).filter((_, i) => i !== this.model[_key]);
257
+ this.parent.#setValueState(newValue, newDefaultValue);
258
+ } else {
259
+ throw new NotArrayItemModelError();
260
+ }
261
+ }
262
+ /**
263
+ * Runs all validation callbacks potentially affecting this
264
+ * or any nested model. Returns the combined array of all
265
+ * errors as in the errors property.
266
+ */
267
+ async validate() {
268
+ const errors = await Promise.all([
269
+ ...this.#requestValidationOfDescendants(),
270
+ ...this.#requestValidationWithAncestors()
271
+ ]).then((arr) => arr.flat());
272
+ this[_setErrorsWithDescendants](errors.length ? errors : void 0);
273
+ this[_update]();
274
+ return errors;
275
+ }
276
+ [_clearValidation]() {
277
+ if (this.#visited) {
278
+ this.#visited = false;
279
+ this.dispatchEvent(CHANGED);
280
+ }
281
+ let needsUpdate = false;
282
+ if (this.#ownErrors) {
283
+ this.#ownErrors = void 0;
284
+ needsUpdate = true;
285
+ this.dispatchEvent(CHANGED);
286
+ }
287
+ if ([...this.#getChildBinderNodes()].filter((childBinderNode) => childBinderNode[_clearValidation]()).length > 0) {
288
+ needsUpdate = true;
289
+ }
290
+ return needsUpdate;
291
+ }
292
+ [_setErrorsWithDescendants](errors) {
293
+ const { name } = this;
294
+ const ownErrors = errors ? errors.filter((valueError) => getErrorPropertyName(valueError) === name) : void 0;
295
+ const relatedErrors = errors ? errors.filter((valueError) => getErrorPropertyName(valueError).startsWith(name)) : void 0;
296
+ this.#ownErrors = ownErrors;
297
+ for (const childBinderNode of this.#getChildBinderNodes()) {
298
+ childBinderNode[_setErrorsWithDescendants](relatedErrors);
299
+ }
300
+ this.dispatchEvent(CHANGED);
301
+ }
302
+ [_update](_) {
303
+ if (this.parent) {
304
+ this.parent[_update]();
305
+ }
306
+ }
307
+ async [_updateValidation]() {
308
+ if (this.#visited) {
309
+ await this.validate();
310
+ } else if (this.dirty || this.invalid) {
311
+ await Promise.all(
312
+ [...this.#getChildBinderNodes()].map(async (childBinderNode) => childBinderNode[_updateValidation]())
313
+ );
314
+ }
315
+ }
316
+ *#getChildBinderNodes() {
317
+ if (this.value === void 0 || this.defaultValue === void 0) {
318
+ return;
319
+ }
320
+ if (this.#isObject()) {
321
+ for (const [, getter] of getObjectModelOwnAndParentGetters(this.model)) {
322
+ const childModel = getter.call(this.model);
323
+ if (childModel[_key] in this.defaultValue) {
324
+ yield getBinderNode(childModel);
325
+ }
326
+ }
327
+ } else if (this.#isArray()) {
328
+ for (const childBinderNode of this.model) {
329
+ yield childBinderNode;
330
+ }
331
+ }
332
+ }
333
+ #isArray() {
334
+ return this.model instanceof ArrayModel;
335
+ }
336
+ #isArrayItem() {
337
+ return this.model[_parent] instanceof ArrayModel;
338
+ }
339
+ #isObject() {
340
+ return this.model instanceof ObjectModel;
341
+ }
342
+ *#requestValidationOfDescendants() {
343
+ for (const node of this.#getChildBinderNodes()) {
344
+ yield* node.#runOwnValidators();
345
+ yield* node.#requestValidationOfDescendants();
346
+ }
347
+ }
348
+ *#requestValidationWithAncestors() {
349
+ yield* this.#runOwnValidators();
350
+ if (this.parent) {
351
+ yield* this.parent.#requestValidationWithAncestors();
352
+ }
353
+ }
354
+ *#runOwnValidators() {
355
+ const hasInvalidState = this[_validity] && !this[_validity].valid;
356
+ const hasBadInput = !!this[_validity]?.badInput;
357
+ if (hasInvalidState && !hasBadInput || !hasInvalidState) {
358
+ for (const validator of this.#validators) {
359
+ yield this.binder.requestValidation(this.model, validator);
360
+ }
361
+ }
362
+ if (hasInvalidState) {
363
+ yield this.binder.requestValidation(this.model, this.#validityStateValidator);
364
+ }
365
+ }
366
+ initializeValue(forceInitialize = false) {
367
+ if (this.parent && (this.parent.value === void 0 || this.parent.defaultValue === void 0)) {
368
+ this.parent.initializeValue(true);
369
+ }
370
+ const key = this.model[_key];
371
+ let value = this.parent ? this.parent.value[this.model[_key]] : void 0;
372
+ const defaultValue = this.parent ? this.parent.defaultValue[this.model[_key]] : void 0;
373
+ if (value === void 0) {
374
+ if (forceInitialize || !this.parent) {
375
+ value = this.model.constructor.createEmptyValue();
376
+ this.#setValueState(value, defaultValue === void 0 ? value : defaultValue);
377
+ } else if (this.parent.model instanceof ObjectModel && !(key in (this.parent.value || {}))) {
378
+ this.#setValueState(void 0, defaultValue === void 0 ? value : defaultValue);
379
+ }
380
+ }
381
+ }
382
+ #setValueState(value, defaultValue) {
383
+ const { parent } = this;
384
+ if (parent) {
385
+ const key = this.model[_key];
386
+ const parentValue = updateObjectOrArrayKey(parent.model, parent.value, key, value);
387
+ const keepPristine = value === defaultValue && parent.value === parent.defaultValue;
388
+ if (keepPristine) {
389
+ parent.#setValueState(parentValue, parentValue);
390
+ } else if (defaultValue !== void 0) {
391
+ const parentDefaultValue = updateObjectOrArrayKey(parent.model, parent.defaultValue, key, defaultValue);
392
+ parent.#setValueState(parentValue, parentDefaultValue);
393
+ } else {
394
+ parent.#setValueState(parentValue, void 0);
395
+ }
396
+ } else {
397
+ const binder = this;
398
+ if (defaultValue !== void 0) {
399
+ binder.defaultValue = defaultValue;
400
+ }
401
+ binder.value = value;
402
+ }
403
+ }
404
+ }
405
+ export {
406
+ BinderNode,
407
+ CHANGED,
408
+ _clearValidation,
409
+ _setErrorsWithDescendants,
410
+ _update,
411
+ _updateValidation,
412
+ getBinderNode
413
+ };
414
+ //# sourceMappingURL=BinderNode.js.map