regor 1.4.4 → 1.4.6
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/README.md +127 -0
- package/dist/regor.d.ts +76 -0
- package/dist/regor.es2015.cjs.js +256 -45
- package/dist/regor.es2015.cjs.prod.js +3 -3
- package/dist/regor.es2015.esm.js +256 -45
- package/dist/regor.es2015.esm.prod.js +3 -3
- package/dist/regor.es2015.iife.js +256 -45
- package/dist/regor.es2015.iife.prod.js +3 -3
- package/dist/regor.es2019.cjs.js +256 -45
- package/dist/regor.es2019.cjs.prod.js +3 -3
- package/dist/regor.es2019.esm.js +256 -45
- package/dist/regor.es2019.esm.prod.js +3 -3
- package/dist/regor.es2019.iife.js +256 -45
- package/dist/regor.es2019.iife.prod.js +3 -3
- package/dist/regor.es2022.cjs.js +249 -40
- package/dist/regor.es2022.cjs.prod.js +3 -3
- package/dist/regor.es2022.esm.js +249 -40
- package/dist/regor.es2022.esm.prod.js +3 -3
- package/dist/regor.es2022.iife.js +249 -40
- package/dist/regor.es2022.iife.prod.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,132 @@ HTML:
|
|
|
97
97
|
</div>
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
+
## Component Props Validation
|
|
101
|
+
|
|
102
|
+
Regor components can validate incoming props at runtime inside `context(head)`.
|
|
103
|
+
|
|
104
|
+
This is opt-in and local to the component author:
|
|
105
|
+
|
|
106
|
+
- it does not change `defineComponent(...)`
|
|
107
|
+
- it validates only the keys you list
|
|
108
|
+
- it throws immediately on the first invalid prop
|
|
109
|
+
- it does not coerce values
|
|
110
|
+
- it does not mutate `head.props`
|
|
111
|
+
|
|
112
|
+
Use `head.validateProps(...)` together with `pval`:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import { defineComponent, html, pval } from 'regor'
|
|
116
|
+
|
|
117
|
+
type EditorCard = {
|
|
118
|
+
title: string
|
|
119
|
+
count?: number
|
|
120
|
+
mode: 'create' | 'edit'
|
|
121
|
+
summary?: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const editorCard = defineComponent<EditorCard>(
|
|
125
|
+
html`<article>{{ summary }}</article>`,
|
|
126
|
+
{
|
|
127
|
+
props: ['title', 'count', 'mode'],
|
|
128
|
+
context: (head) => {
|
|
129
|
+
head.validateProps({
|
|
130
|
+
title: pval.isString,
|
|
131
|
+
count: pval.optional(pval.isNumber),
|
|
132
|
+
mode: pval.oneOf(['create', 'edit'] as const),
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
...head.props,
|
|
137
|
+
summary: `${head.props.title}:${head.props.mode}:${head.props.count ?? 'none'}`,
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Built-in validators
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import { pval } from 'regor'
|
|
148
|
+
|
|
149
|
+
pval.isString
|
|
150
|
+
pval.isNumber
|
|
151
|
+
pval.isBoolean
|
|
152
|
+
pval.isClass(MyClass)
|
|
153
|
+
pval.optional(pval.isString)
|
|
154
|
+
pval.nullable(pval.isNumber)
|
|
155
|
+
pval.oneOf(['create', 'edit'] as const)
|
|
156
|
+
pval.arrayOf(pval.isString)
|
|
157
|
+
pval.shape({ title: pval.isString, count: pval.isNumber })
|
|
158
|
+
pval.refOf(pval.isString)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Dynamic bindings and refs
|
|
162
|
+
|
|
163
|
+
Single-prop dynamic bindings like `:title="titleRef"` flow into component props as refs.
|
|
164
|
+
When validating those runtime values, use `pval.refOf(...)`:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
type CardProps = {
|
|
168
|
+
title: Ref<string>
|
|
169
|
+
summary?: string
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const card = defineComponent<CardProps>(html`<h3>{{ summary }}</h3>`, {
|
|
173
|
+
props: ['title'],
|
|
174
|
+
context: (head) => {
|
|
175
|
+
head.validateProps({
|
|
176
|
+
title: pval.refOf(pval.isString),
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
...head.props,
|
|
181
|
+
summary: head.props.title(),
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
})
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
For object-style `:context="{ ... }"` values, validate the plain runtime shape directly:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
head.validateProps({
|
|
191
|
+
meta: pval.shape({
|
|
192
|
+
slug: pval.isString,
|
|
193
|
+
}),
|
|
194
|
+
})
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Custom validators
|
|
198
|
+
|
|
199
|
+
Users can provide their own validators as long as they match the `PropValidator<T>` signature:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { type PropValidator } from 'regor'
|
|
203
|
+
|
|
204
|
+
const isNonEmptyString: PropValidator<string> = (value, name) => {
|
|
205
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
206
|
+
throw new Error(`Invalid prop "${name}": expected non-empty string.`)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
head.validateProps({
|
|
211
|
+
title: isNonEmptyString,
|
|
212
|
+
})
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Custom validators can also use the third `head` argument:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
const startsWithPrefix: PropValidator<string> = (value, name, head) => {
|
|
219
|
+
const ctx = head.requireContext(AppServices)
|
|
220
|
+
if (typeof value !== 'string' || !value.startsWith(ctx.prefix)) {
|
|
221
|
+
throw new Error(`Invalid prop "${name}": expected prefixed value.`)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
100
226
|
## Table Templates and Components
|
|
101
227
|
|
|
102
228
|
Regor preprocesses table-related templates to keep markup valid when using
|
|
@@ -223,6 +349,7 @@ These directives empower you to create dynamic and interactive user interfaces,
|
|
|
223
349
|
|
|
224
350
|
- **`createApp`** Similar to Vue's `createApp`, it initializes a Regor application instance.
|
|
225
351
|
- **`defineComponent`** Creates a Regor component instance.
|
|
352
|
+
- **`pval`** Built-in component prop validators used with `head.validateProps(...)`.
|
|
226
353
|
- **`toFragment`** Converts a JSON template to a document fragment.
|
|
227
354
|
- **`toJsonTemplate`** Converts a DOM element to a JSON template.
|
|
228
355
|
|
package/dist/regor.d.ts
CHANGED
|
@@ -1,5 +1,58 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Assertion-style runtime validator used by `head.validateProps(...)`.
|
|
5
|
+
*
|
|
6
|
+
* A validator should throw when the value is invalid and return normally when
|
|
7
|
+
* the value satisfies the expected runtime contract.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam TValue - Value type asserted by the validator when it succeeds.
|
|
10
|
+
* @param value - Raw incoming prop value.
|
|
11
|
+
* @param name - Prop name or nested path currently being validated.
|
|
12
|
+
* @param head - Current component head, useful for context-aware validation.
|
|
13
|
+
*/
|
|
14
|
+
export type PropValidator<TValue = unknown> = (value: unknown, name: string, head: ComponentHead<any>) => asserts value is TValue;
|
|
15
|
+
export type ValidationSchemaLike = Record<string, PropValidator<any>>;
|
|
16
|
+
/**
|
|
17
|
+
* Validation schema shape suggested by `ComponentHead<T>.props`.
|
|
18
|
+
*
|
|
19
|
+
* Every key is optional so component authors can validate only the subset they
|
|
20
|
+
* care about. Editor completion is still driven by the known prop keys.
|
|
21
|
+
*/
|
|
22
|
+
export type PropValidationSchemaFor<TProps extends object> = {
|
|
23
|
+
[TKey in keyof TProps]?: PropValidator<TProps[TKey]>;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Infers the asserted value types from a validation schema.
|
|
27
|
+
*
|
|
28
|
+
* Keys whose values are not validators are ignored.
|
|
29
|
+
*/
|
|
30
|
+
export type InferPropValidationSchema<TSchema extends Record<string, unknown>> = {
|
|
31
|
+
[TKey in keyof TSchema as TSchema[TKey] extends PropValidator<any> ? TKey : never]: TSchema[TKey] extends PropValidator<infer TValue> ? TValue : never;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Built-in prop-validator namespace used with `head.validateProps(...)`.
|
|
35
|
+
*
|
|
36
|
+
* Example:
|
|
37
|
+
* ```ts
|
|
38
|
+
* head.validateProps({
|
|
39
|
+
* title: pval.isString,
|
|
40
|
+
* count: pval.optional(pval.isNumber),
|
|
41
|
+
* })
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare const pval: {
|
|
45
|
+
readonly isString: PropValidator<string>;
|
|
46
|
+
readonly isNumber: PropValidator<number>;
|
|
47
|
+
readonly isBoolean: PropValidator<boolean>;
|
|
48
|
+
readonly isClass: <TValue extends object>(ctor: abstract new (...args: any[]) => TValue) => PropValidator<TValue>;
|
|
49
|
+
readonly optional: <TValue>(validator: PropValidator<TValue>) => PropValidator<TValue | undefined>;
|
|
50
|
+
readonly nullable: <TValue>(validator: PropValidator<TValue>) => PropValidator<TValue | null>;
|
|
51
|
+
readonly oneOf: <const TValue extends readonly unknown[]>(values: TValue) => PropValidator<TValue[number]>;
|
|
52
|
+
readonly arrayOf: <TValue>(validator: PropValidator<TValue>) => PropValidator<TValue[]>;
|
|
53
|
+
readonly shape: <TSchema extends ValidationSchemaLike>(schema: TSchema) => PropValidator<InferPropValidationSchema<TSchema>>;
|
|
54
|
+
readonly refOf: <TValue>(validator: PropValidator<TValue>) => PropValidator<AnyRef>;
|
|
55
|
+
};
|
|
3
56
|
export type ContextClass<TValue extends object> = abstract new (...args: never[]) => TValue;
|
|
4
57
|
/**
|
|
5
58
|
* Runtime metadata passed to a component's `context(head)` factory.
|
|
@@ -170,6 +223,29 @@ export declare class ComponentHead<TContext extends IRegorContext | object = IRe
|
|
|
170
223
|
* @throws Error when no matching instance exists at the requested occurrence.
|
|
171
224
|
*/
|
|
172
225
|
requireContext<TValue extends object>(constructor: ContextClass<TValue>, occurrence?: number): TValue;
|
|
226
|
+
/**
|
|
227
|
+
* Validates selected incoming props using assertion-style validators.
|
|
228
|
+
*
|
|
229
|
+
* Only keys listed in `schema` are checked. Validation throws immediately
|
|
230
|
+
* on the first invalid prop and does not mutate `head.props`.
|
|
231
|
+
*
|
|
232
|
+
* The schema is keyed from `head.props`, so editor completion can suggest
|
|
233
|
+
* known prop names while still allowing you to validate only a subset.
|
|
234
|
+
*
|
|
235
|
+
* Validators typically come from `pval`, but custom user validators are also
|
|
236
|
+
* supported.
|
|
237
|
+
*
|
|
238
|
+
* Example:
|
|
239
|
+
* ```ts
|
|
240
|
+
* head.validateProps({
|
|
241
|
+
* title: pval.isString,
|
|
242
|
+
* count: pval.optional(pval.isNumber),
|
|
243
|
+
* })
|
|
244
|
+
* ```
|
|
245
|
+
*
|
|
246
|
+
* @param schema - Validators to apply to selected incoming props.
|
|
247
|
+
*/
|
|
248
|
+
validateProps<TSchema extends PropValidationSchemaFor<TContext>>(schema: TSchema): asserts this is ComponentHead<TContext & InferPropValidationSchema<TSchema>>;
|
|
173
249
|
/**
|
|
174
250
|
* Unmounts this component instance by removing nodes between `start` and `end`
|
|
175
251
|
* and calling unmount lifecycle handlers for captured contexts.
|
package/dist/regor.es2015.cjs.js
CHANGED
|
@@ -87,6 +87,7 @@ __export(index_exports, {
|
|
|
87
87
|
onUnmounted: () => onUnmounted,
|
|
88
88
|
pause: () => pause,
|
|
89
89
|
persist: () => persist,
|
|
90
|
+
pval: () => pval,
|
|
90
91
|
raw: () => raw,
|
|
91
92
|
ref: () => ref,
|
|
92
93
|
removeNode: () => removeNode,
|
|
@@ -418,6 +419,37 @@ var ComponentHead = class {
|
|
|
418
419
|
`${constructor} was not found in the context stack at occurrence ${occurrence}.`
|
|
419
420
|
);
|
|
420
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* Validates selected incoming props using assertion-style validators.
|
|
424
|
+
*
|
|
425
|
+
* Only keys listed in `schema` are checked. Validation throws immediately
|
|
426
|
+
* on the first invalid prop and does not mutate `head.props`.
|
|
427
|
+
*
|
|
428
|
+
* The schema is keyed from `head.props`, so editor completion can suggest
|
|
429
|
+
* known prop names while still allowing you to validate only a subset.
|
|
430
|
+
*
|
|
431
|
+
* Validators typically come from `pval`, but custom user validators are also
|
|
432
|
+
* supported.
|
|
433
|
+
*
|
|
434
|
+
* Example:
|
|
435
|
+
* ```ts
|
|
436
|
+
* head.validateProps({
|
|
437
|
+
* title: pval.isString,
|
|
438
|
+
* count: pval.optional(pval.isNumber),
|
|
439
|
+
* })
|
|
440
|
+
* ```
|
|
441
|
+
*
|
|
442
|
+
* @param schema - Validators to apply to selected incoming props.
|
|
443
|
+
*/
|
|
444
|
+
validateProps(schema) {
|
|
445
|
+
const props = this.props;
|
|
446
|
+
for (const name in schema) {
|
|
447
|
+
const validator = schema[name];
|
|
448
|
+
if (!validator) continue;
|
|
449
|
+
const validateProp = validator;
|
|
450
|
+
validateProp(props[name], name, this);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
421
453
|
/**
|
|
422
454
|
* Unmounts this component instance by removing nodes between `start` and `end`
|
|
423
455
|
* and calling unmount lifecycle handlers for captured contexts.
|
|
@@ -566,10 +598,13 @@ var IfBinder = class {
|
|
|
566
598
|
}
|
|
567
599
|
__bindAll(element) {
|
|
568
600
|
const isIfElement = element.hasAttribute(this.__if);
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
601
|
+
if (isIfElement) this.__bind(element);
|
|
602
|
+
this.__binder.__componentBinder.__forEachBindableDescendant(
|
|
603
|
+
element,
|
|
604
|
+
(el) => {
|
|
605
|
+
if (el.hasAttribute(this.__if)) this.__bind(el);
|
|
606
|
+
}
|
|
607
|
+
);
|
|
573
608
|
return isIfElement;
|
|
574
609
|
}
|
|
575
610
|
__isProcessedOrMark(el) {
|
|
@@ -1361,8 +1396,16 @@ var ComponentBinder = class {
|
|
|
1361
1396
|
}
|
|
1362
1397
|
return false;
|
|
1363
1398
|
}
|
|
1399
|
+
__isNamedSlotTemplateShortcut(node) {
|
|
1400
|
+
if (!isTemplate(node)) return false;
|
|
1401
|
+
const attributeNames = node.getAttributeNames();
|
|
1402
|
+
if (node.hasAttribute("name")) return true;
|
|
1403
|
+
return attributeNames.some((x) => x.startsWith("#"));
|
|
1404
|
+
}
|
|
1405
|
+
__isDefaultSlotTemplateShortcut(node) {
|
|
1406
|
+
return isTemplate(node) && node.getAttributeNames().length === 0;
|
|
1407
|
+
}
|
|
1364
1408
|
__unwrapComponents(element) {
|
|
1365
|
-
var _a;
|
|
1366
1409
|
const binder = this.__binder;
|
|
1367
1410
|
const parser = binder.__parser;
|
|
1368
1411
|
const registeredComponents = binder.__config.__components;
|
|
@@ -1371,16 +1414,9 @@ var ComponentBinder = class {
|
|
|
1371
1414
|
return;
|
|
1372
1415
|
}
|
|
1373
1416
|
const contextComponents = parser.__getComponents();
|
|
1374
|
-
const
|
|
1375
|
-
const registeredSelector = this.__getRegisteredComponentSelector(registeredComponents);
|
|
1376
|
-
const selector = [
|
|
1377
|
-
...registeredSelector ? [registeredSelector] : [],
|
|
1378
|
-
...contextComponentSelectors,
|
|
1379
|
-
...contextComponentSelectors.map(hyphenate)
|
|
1380
|
-
].join(",");
|
|
1417
|
+
const selector = this.__getComponentSelector();
|
|
1381
1418
|
if (isNullOrWhitespace(selector)) return;
|
|
1382
|
-
const
|
|
1383
|
-
const components = ((_a = element.matches) == null ? void 0 : _a.call(element, selector)) ? [element, ...list] : list;
|
|
1419
|
+
const components = this.__collectTopLevelComponentHosts(element, selector);
|
|
1384
1420
|
for (const component of components) {
|
|
1385
1421
|
if (component.hasAttribute(binder.__pre)) continue;
|
|
1386
1422
|
const parent = component.parentNode;
|
|
@@ -1454,7 +1490,7 @@ var ComponentBinder = class {
|
|
|
1454
1490
|
};
|
|
1455
1491
|
const capturedContext = [...parser.__capture()];
|
|
1456
1492
|
const createComponentCtx = () => {
|
|
1457
|
-
var
|
|
1493
|
+
var _a;
|
|
1458
1494
|
const props = getProps(component, capturedContext);
|
|
1459
1495
|
const head2 = new ComponentHead(
|
|
1460
1496
|
props,
|
|
@@ -1464,8 +1500,8 @@ var ComponentBinder = class {
|
|
|
1464
1500
|
endOfComponent
|
|
1465
1501
|
);
|
|
1466
1502
|
const componentCtx2 = useScope(() => {
|
|
1467
|
-
var
|
|
1468
|
-
return (
|
|
1503
|
+
var _a2;
|
|
1504
|
+
return (_a2 = registeredComponent.context(head2)) != null ? _a2 : {};
|
|
1469
1505
|
}).context;
|
|
1470
1506
|
if (head2.autoProps) {
|
|
1471
1507
|
for (const [key, propsValue] of Object.entries(props)) {
|
|
@@ -1489,7 +1525,7 @@ var ComponentBinder = class {
|
|
|
1489
1525
|
}
|
|
1490
1526
|
} else componentCtx2[key] = propsValue;
|
|
1491
1527
|
}
|
|
1492
|
-
(
|
|
1528
|
+
(_a = head2.onAutoPropsAssigned) == null ? void 0 : _a.call(head2);
|
|
1493
1529
|
}
|
|
1494
1530
|
return { componentCtx: componentCtx2, head: head2 };
|
|
1495
1531
|
};
|
|
@@ -1498,6 +1534,7 @@ var ComponentBinder = class {
|
|
|
1498
1534
|
const len = childNodes.length;
|
|
1499
1535
|
const isEmptyComponent = component.childNodes.length === 0;
|
|
1500
1536
|
const expandSlot = (slot) => {
|
|
1537
|
+
var _a;
|
|
1501
1538
|
const parent2 = slot.parentElement;
|
|
1502
1539
|
let name = slot.name;
|
|
1503
1540
|
if (isNullOrWhitespace(name)) {
|
|
@@ -1527,9 +1564,12 @@ var ComponentBinder = class {
|
|
|
1527
1564
|
`template[name='${name}'], template[\\#${name}]`
|
|
1528
1565
|
);
|
|
1529
1566
|
if (!compTemplate && name === "default") {
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1567
|
+
const unnamedTemplates = component.querySelectorAll(
|
|
1568
|
+
"template:not([name])"
|
|
1569
|
+
);
|
|
1570
|
+
compTemplate = (_a = [...unnamedTemplates].find(
|
|
1571
|
+
(x) => this.__isDefaultSlotTemplateShortcut(x)
|
|
1572
|
+
)) != null ? _a : null;
|
|
1533
1573
|
}
|
|
1534
1574
|
const createSwitchContext = (childNodes2) => {
|
|
1535
1575
|
if (!head.enableSwitch) return;
|
|
@@ -1565,7 +1605,7 @@ var ComponentBinder = class {
|
|
|
1565
1605
|
return;
|
|
1566
1606
|
}
|
|
1567
1607
|
const childNodes2 = [...getChildNodes(component)].filter(
|
|
1568
|
-
(x) => !
|
|
1608
|
+
(x) => !this.__isNamedSlotTemplateShortcut(x)
|
|
1569
1609
|
);
|
|
1570
1610
|
for (const slotChild of childNodes2) {
|
|
1571
1611
|
parent2.insertBefore(slotChild, slot);
|
|
@@ -1651,6 +1691,65 @@ var ComponentBinder = class {
|
|
|
1651
1691
|
parser.__scoped(capturedContext, bindComponent);
|
|
1652
1692
|
}
|
|
1653
1693
|
}
|
|
1694
|
+
__getComponentSelector() {
|
|
1695
|
+
const binder = this.__binder;
|
|
1696
|
+
const parser = binder.__parser;
|
|
1697
|
+
const registeredComponents = binder.__config.__components;
|
|
1698
|
+
const contextComponentSelectors = parser.__getComponentSelectors();
|
|
1699
|
+
const registeredSelector = this.__getRegisteredComponentSelector(registeredComponents);
|
|
1700
|
+
return [
|
|
1701
|
+
...registeredSelector ? [registeredSelector] : [],
|
|
1702
|
+
...contextComponentSelectors,
|
|
1703
|
+
...contextComponentSelectors.map(hyphenate)
|
|
1704
|
+
].join(",");
|
|
1705
|
+
}
|
|
1706
|
+
__collectTopLevelComponentHosts(root, selector) {
|
|
1707
|
+
var _a;
|
|
1708
|
+
const result = [];
|
|
1709
|
+
if (isNullOrWhitespace(selector)) return result;
|
|
1710
|
+
if ((_a = root.matches) == null ? void 0 : _a.call(root, selector)) return [root];
|
|
1711
|
+
const stack = this.__getChildElements(root).reverse();
|
|
1712
|
+
while (stack.length > 0) {
|
|
1713
|
+
const current = stack.pop();
|
|
1714
|
+
if (current.matches(selector)) {
|
|
1715
|
+
result.push(current);
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1718
|
+
stack.push(...this.__getChildElements(current).reverse());
|
|
1719
|
+
}
|
|
1720
|
+
return result;
|
|
1721
|
+
}
|
|
1722
|
+
__forEachBindableDescendant(root, action) {
|
|
1723
|
+
const selector = this.__getComponentSelector();
|
|
1724
|
+
const stack = this.__getChildElements(root).reverse();
|
|
1725
|
+
while (stack.length > 0) {
|
|
1726
|
+
const current = stack.pop();
|
|
1727
|
+
action(current);
|
|
1728
|
+
if (!isNullOrWhitespace(selector) && current.matches(selector)) continue;
|
|
1729
|
+
stack.push(...this.__getChildElements(current).reverse());
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
__getChildElements(root) {
|
|
1733
|
+
const children = root == null ? void 0 : root.children;
|
|
1734
|
+
if ((children == null ? void 0 : children.length) != null) {
|
|
1735
|
+
const result = [];
|
|
1736
|
+
for (let i = 0; i < children.length; ++i) {
|
|
1737
|
+
const child = children[i];
|
|
1738
|
+
if (isElement(child)) result.push(child);
|
|
1739
|
+
}
|
|
1740
|
+
return result;
|
|
1741
|
+
}
|
|
1742
|
+
const childNodes = root == null ? void 0 : root.childNodes;
|
|
1743
|
+
if ((childNodes == null ? void 0 : childNodes.length) != null) {
|
|
1744
|
+
const result = [];
|
|
1745
|
+
for (let i = 0; i < childNodes.length; ++i) {
|
|
1746
|
+
const child = childNodes[i];
|
|
1747
|
+
if (isElement(child)) result.push(child);
|
|
1748
|
+
}
|
|
1749
|
+
return result;
|
|
1750
|
+
}
|
|
1751
|
+
return [];
|
|
1752
|
+
}
|
|
1654
1753
|
};
|
|
1655
1754
|
|
|
1656
1755
|
// src/bind/DirectiveCollector.ts
|
|
@@ -1743,10 +1842,10 @@ var DirectiveCollector = class {
|
|
|
1743
1842
|
};
|
|
1744
1843
|
processNode(element);
|
|
1745
1844
|
if (!isRecursive || !element.firstElementChild) return map;
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
processNode
|
|
1749
|
-
|
|
1845
|
+
this.__binder.__componentBinder.__forEachBindableDescendant(
|
|
1846
|
+
element,
|
|
1847
|
+
processNode
|
|
1848
|
+
);
|
|
1750
1849
|
return map;
|
|
1751
1850
|
}
|
|
1752
1851
|
};
|
|
@@ -1764,17 +1863,19 @@ var DynamicBinder = class {
|
|
|
1764
1863
|
constructor(binder) {
|
|
1765
1864
|
__publicField(this, "__binder");
|
|
1766
1865
|
__publicField(this, "__is");
|
|
1767
|
-
__publicField(this, "__isSelector");
|
|
1768
1866
|
this.__binder = binder;
|
|
1769
1867
|
this.__is = binder.__config.__builtInNames.is;
|
|
1770
|
-
this.__isSelector = toSelector(this.__is) + ", [is]";
|
|
1771
1868
|
}
|
|
1772
1869
|
__bindAll(element) {
|
|
1773
1870
|
const isComponentElement = element.hasAttribute(this.__is);
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1871
|
+
if (isComponentElement || element.hasAttribute("is"))
|
|
1872
|
+
this.__bind(element);
|
|
1873
|
+
this.__binder.__componentBinder.__forEachBindableDescendant(
|
|
1874
|
+
element,
|
|
1875
|
+
(el) => {
|
|
1876
|
+
if (el.hasAttribute(this.__is) || el.hasAttribute("is")) this.__bind(el);
|
|
1877
|
+
}
|
|
1878
|
+
);
|
|
1778
1879
|
return isComponentElement;
|
|
1779
1880
|
}
|
|
1780
1881
|
__bind(el) {
|
|
@@ -2251,10 +2352,13 @@ var _ForBinder = class _ForBinder {
|
|
|
2251
2352
|
}
|
|
2252
2353
|
__bindAll(element) {
|
|
2253
2354
|
const isForElement = element.hasAttribute(this.__for);
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2355
|
+
if (isForElement) this.__bindFor(element);
|
|
2356
|
+
this.__binder.__componentBinder.__forEachBindableDescendant(
|
|
2357
|
+
element,
|
|
2358
|
+
(el) => {
|
|
2359
|
+
if (el.hasAttribute(this.__for)) this.__bindFor(el);
|
|
2360
|
+
}
|
|
2361
|
+
);
|
|
2258
2362
|
return isForElement;
|
|
2259
2363
|
}
|
|
2260
2364
|
__isProcessedOrMark(el) {
|
|
@@ -2931,11 +3035,11 @@ var patchAttribute = (el, key, value, previousKey) => {
|
|
|
2931
3035
|
}
|
|
2932
3036
|
return;
|
|
2933
3037
|
}
|
|
2934
|
-
const
|
|
2935
|
-
if (isNullOrUndefined(value) ||
|
|
3038
|
+
const isBoolean2 = key in booleanAttributes;
|
|
3039
|
+
if (isNullOrUndefined(value) || isBoolean2 && !includeBooleanAttr(value)) {
|
|
2936
3040
|
el.removeAttribute(key);
|
|
2937
3041
|
} else {
|
|
2938
|
-
el.setAttribute(key,
|
|
3042
|
+
el.setAttribute(key, isBoolean2 ? "" : value);
|
|
2939
3043
|
}
|
|
2940
3044
|
};
|
|
2941
3045
|
|
|
@@ -3185,7 +3289,7 @@ var decimalSeparators = /[.,' ·٫]/;
|
|
|
3185
3289
|
var handleInputAndTextArea = (el, flags, getModelRef, parsedValue) => {
|
|
3186
3290
|
const isLazy = flags.lazy;
|
|
3187
3291
|
const eventType = isLazy ? "change" : "input";
|
|
3188
|
-
const
|
|
3292
|
+
const isNumber2 = isNumberInput(el);
|
|
3189
3293
|
const trimmer = () => {
|
|
3190
3294
|
if (!flags.trim && !getFlags(parsedValue()[1]).trim) return;
|
|
3191
3295
|
el.value = el.value.trim();
|
|
@@ -3215,7 +3319,7 @@ var handleInputAndTextArea = (el, flags, getModelRef, parsedValue) => {
|
|
|
3215
3319
|
if (!target || target.composing) return;
|
|
3216
3320
|
let value = target.value;
|
|
3217
3321
|
const flags2 = getFlags(parsedValue()[1]);
|
|
3218
|
-
if (
|
|
3322
|
+
if (isNumber2 || flags2.number || flags2.int) {
|
|
3219
3323
|
if (flags2.int) {
|
|
3220
3324
|
value = parseInt(value);
|
|
3221
3325
|
} else {
|
|
@@ -4530,12 +4634,12 @@ var Jsep = class {
|
|
|
4530
4634
|
this.__gobbleSpaces();
|
|
4531
4635
|
let ch = this.__code;
|
|
4532
4636
|
while (ch === PERIOD_CODE || ch === OBRACK_CODE || ch === OPAREN_CODE || ch === QUMARK_CODE) {
|
|
4533
|
-
let
|
|
4637
|
+
let optional2;
|
|
4534
4638
|
if (ch === QUMARK_CODE) {
|
|
4535
4639
|
if (this.__expr.charCodeAt(this.__index + 1) !== PERIOD_CODE) {
|
|
4536
4640
|
break;
|
|
4537
4641
|
}
|
|
4538
|
-
|
|
4642
|
+
optional2 = true;
|
|
4539
4643
|
this.__index += 2;
|
|
4540
4644
|
this.__gobbleSpaces();
|
|
4541
4645
|
ch = this.__code;
|
|
@@ -4561,7 +4665,7 @@ var Jsep = class {
|
|
|
4561
4665
|
callee: node
|
|
4562
4666
|
};
|
|
4563
4667
|
} else {
|
|
4564
|
-
if (
|
|
4668
|
+
if (optional2) {
|
|
4565
4669
|
this.__index--;
|
|
4566
4670
|
}
|
|
4567
4671
|
this.__gobbleSpaces();
|
|
@@ -4572,7 +4676,7 @@ var Jsep = class {
|
|
|
4572
4676
|
property: this.__gobbleIdentifier()
|
|
4573
4677
|
};
|
|
4574
4678
|
}
|
|
4575
|
-
if (
|
|
4679
|
+
if (optional2) {
|
|
4576
4680
|
node.optional = true;
|
|
4577
4681
|
}
|
|
4578
4682
|
this.__gobbleSpaces();
|
|
@@ -6102,6 +6206,113 @@ var defineComponent = (template, options = {}) => {
|
|
|
6102
6206
|
};
|
|
6103
6207
|
};
|
|
6104
6208
|
|
|
6209
|
+
// src/app/propValidators.ts
|
|
6210
|
+
var fail = (name, message) => {
|
|
6211
|
+
throw new Error(`Invalid prop "${name}": ${message}.`);
|
|
6212
|
+
};
|
|
6213
|
+
var describeValue = (value) => {
|
|
6214
|
+
var _a;
|
|
6215
|
+
if (value === null) return "null";
|
|
6216
|
+
if (value === void 0) return "undefined";
|
|
6217
|
+
if (typeof value === "string") return "string";
|
|
6218
|
+
if (typeof value === "number") return "number";
|
|
6219
|
+
if (typeof value === "boolean") return "boolean";
|
|
6220
|
+
if (typeof value === "bigint") return "bigint";
|
|
6221
|
+
if (typeof value === "symbol") return "symbol";
|
|
6222
|
+
if (typeof value === "function") return "function";
|
|
6223
|
+
if (isArray(value)) return "array";
|
|
6224
|
+
if (value instanceof Date) return "Date";
|
|
6225
|
+
if (value instanceof RegExp) return "RegExp";
|
|
6226
|
+
if (value instanceof Map) return "Map";
|
|
6227
|
+
if (value instanceof Set) return "Set";
|
|
6228
|
+
const ctorName = (_a = value == null ? void 0 : value.constructor) == null ? void 0 : _a.name;
|
|
6229
|
+
return ctorName && ctorName !== "Object" ? ctorName : "object";
|
|
6230
|
+
};
|
|
6231
|
+
var formatLiteral = (value) => {
|
|
6232
|
+
if (typeof value === "string") return `"${value}"`;
|
|
6233
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
6234
|
+
return String(value);
|
|
6235
|
+
}
|
|
6236
|
+
if (value === null) return "null";
|
|
6237
|
+
if (value === void 0) return "undefined";
|
|
6238
|
+
return describeValue(value);
|
|
6239
|
+
};
|
|
6240
|
+
var isString2 = (value, name) => {
|
|
6241
|
+
if (typeof value !== "string") fail(name, "expected string");
|
|
6242
|
+
};
|
|
6243
|
+
var isNumber = (value, name) => {
|
|
6244
|
+
if (typeof value !== "number") fail(name, "expected number");
|
|
6245
|
+
};
|
|
6246
|
+
var isBoolean = (value, name) => {
|
|
6247
|
+
if (typeof value !== "boolean") fail(name, "expected boolean");
|
|
6248
|
+
};
|
|
6249
|
+
var isClass = (ctor) => {
|
|
6250
|
+
return (value, name) => {
|
|
6251
|
+
if (!(value instanceof ctor)) {
|
|
6252
|
+
fail(name, `expected instance of ${ctor.name || "provided class"}`);
|
|
6253
|
+
}
|
|
6254
|
+
};
|
|
6255
|
+
};
|
|
6256
|
+
var optional = (validator) => {
|
|
6257
|
+
return (value, name, head) => {
|
|
6258
|
+
if (value === void 0) return;
|
|
6259
|
+
validator(value, name, head);
|
|
6260
|
+
};
|
|
6261
|
+
};
|
|
6262
|
+
var nullable = (validator) => {
|
|
6263
|
+
return (value, name, head) => {
|
|
6264
|
+
if (value === null) return;
|
|
6265
|
+
validator(value, name, head);
|
|
6266
|
+
};
|
|
6267
|
+
};
|
|
6268
|
+
var oneOf = (values) => {
|
|
6269
|
+
return (value, name) => {
|
|
6270
|
+
if (values.includes(value)) return;
|
|
6271
|
+
fail(
|
|
6272
|
+
name,
|
|
6273
|
+
`expected one of ${values.map((x) => formatLiteral(x)).join(", ")}`
|
|
6274
|
+
);
|
|
6275
|
+
};
|
|
6276
|
+
};
|
|
6277
|
+
var arrayOf = (validator) => {
|
|
6278
|
+
return (value, name, head) => {
|
|
6279
|
+
if (!isArray(value)) fail(name, "expected array");
|
|
6280
|
+
const items = value;
|
|
6281
|
+
for (let i = 0; i < items.length; ++i) {
|
|
6282
|
+
validator(items[i], `${name}[${i}]`, head);
|
|
6283
|
+
}
|
|
6284
|
+
};
|
|
6285
|
+
};
|
|
6286
|
+
var shape = (schema) => {
|
|
6287
|
+
return (value, name, head) => {
|
|
6288
|
+
if (!isObject(value)) fail(name, "expected object");
|
|
6289
|
+
const record = value;
|
|
6290
|
+
for (const key in schema) {
|
|
6291
|
+
const validator = schema[key];
|
|
6292
|
+
validator(record[key], `${name}.${key}`, head);
|
|
6293
|
+
}
|
|
6294
|
+
};
|
|
6295
|
+
};
|
|
6296
|
+
var refOf = (validator) => {
|
|
6297
|
+
return (value, name, head) => {
|
|
6298
|
+
if (!isRef(value)) fail(name, "expected ref");
|
|
6299
|
+
const refValue = value;
|
|
6300
|
+
validator(refValue(), `${name}.value`, head);
|
|
6301
|
+
};
|
|
6302
|
+
};
|
|
6303
|
+
var pval = {
|
|
6304
|
+
isString: isString2,
|
|
6305
|
+
isNumber,
|
|
6306
|
+
isBoolean,
|
|
6307
|
+
isClass,
|
|
6308
|
+
optional,
|
|
6309
|
+
nullable,
|
|
6310
|
+
oneOf,
|
|
6311
|
+
arrayOf,
|
|
6312
|
+
shape,
|
|
6313
|
+
refOf
|
|
6314
|
+
};
|
|
6315
|
+
|
|
6105
6316
|
// src/composition/ContextRegistry.ts
|
|
6106
6317
|
var ContextRegistry = class {
|
|
6107
6318
|
constructor() {
|