@optionfactory/fml 8.0.3 → 9.0.0-rc1

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.
Files changed (50) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +88 -0
  3. package/dist/client-errors.iife.js +30 -9
  4. package/dist/client-errors.iife.js.map +1 -1
  5. package/dist/client-errors.iife.min.js +1 -1
  6. package/dist/client-errors.iife.min.js.map +1 -1
  7. package/dist/custom-elements.json +1529 -435
  8. package/dist/fml.css +21 -10
  9. package/dist/fml.css.map +1 -1
  10. package/dist/fml.d.mts +3 -1322
  11. package/dist/fml.iife.js +5267 -2276
  12. package/dist/fml.iife.js.map +1 -1
  13. package/dist/fml.iife.min.js +1 -1
  14. package/dist/fml.iife.min.js.map +1 -1
  15. package/dist/fml.min.mjs +1 -1
  16. package/dist/fml.min.mjs.map +1 -1
  17. package/dist/fml.mjs +6 -8737
  18. package/dist/fml.mjs.map +1 -1
  19. package/dist/ftl.d.mts +430 -92
  20. package/dist/ftl.iife.js +1314 -809
  21. package/dist/ftl.iife.js.map +1 -1
  22. package/dist/ftl.iife.min.js +1 -1
  23. package/dist/ftl.iife.min.js.map +1 -1
  24. package/dist/ftl.min.mjs +1 -1
  25. package/dist/ftl.min.mjs.map +1 -1
  26. package/dist/ftl.mjs +1313 -810
  27. package/dist/ftl.mjs.map +1 -1
  28. package/dist/ful.css +21 -10
  29. package/dist/ful.css.map +1 -1
  30. package/dist/ful.d.mts +801 -252
  31. package/dist/ful.iife.js +3677 -1378
  32. package/dist/ful.iife.js.map +1 -1
  33. package/dist/ful.iife.min.js +1 -1
  34. package/dist/ful.iife.min.js.map +1 -1
  35. package/dist/ful.min.mjs +1 -1
  36. package/dist/ful.min.mjs.map +1 -1
  37. package/dist/ful.mjs +3666 -1378
  38. package/dist/ful.mjs.map +1 -1
  39. package/dist/httpc.d.mts +114 -19
  40. package/dist/httpc.iife.js +253 -83
  41. package/dist/httpc.iife.js.map +1 -1
  42. package/dist/httpc.iife.min.js +1 -1
  43. package/dist/httpc.iife.min.js.map +1 -1
  44. package/dist/httpc.min.mjs +1 -1
  45. package/dist/httpc.min.mjs.map +1 -1
  46. package/dist/httpc.mjs +250 -84
  47. package/dist/httpc.mjs.map +1 -1
  48. package/dist/vscode.html-custom-data.json +600 -58
  49. package/dist/web-types.json +1475 -380
  50. package/package.json +16 -8
package/dist/ftl.d.mts CHANGED
@@ -1,3 +1,34 @@
1
+ /**
2
+ * A Map bounded by entry count, evicting in insertion order: not an LRU (a hit
3
+ * does not refresh an entry), just a cap keeping unbounded key spaces (parsed
4
+ * expressions, compiled masks, formatter instances) from growing forever. The
5
+ * capacity is sized so eviction never happens on a sane page: hitting it means
6
+ * dynamically generated keys, where FIFO's worst case (evicting a hot entry)
7
+ * costs one recomputation.
8
+ */
9
+ declare class BoundedCache {
10
+ #private;
11
+ /** @param {number} max */
12
+ constructor(max: number);
13
+ /**
14
+ * The cached value for the key, computing and caching it on a miss. A
15
+ * computed null or undefined is cached like any value; a throwing compute
16
+ * caches nothing.
17
+ * @template K, V
18
+ * @param {K} key
19
+ * @param {(key: K) => V} compute
20
+ * @returns {V}
21
+ */
22
+ getOrCompute<K, V>(key: K, compute: (key: K) => V): V;
23
+ get size(): number;
24
+ }
25
+ /**
26
+ * The expression language: parsing to an ast, caching the parses, and
27
+ * interpreting one against a scope. Member access and calls are unfiltered, so
28
+ * an expression can do whatever the page's own javascript can. Expressions are
29
+ * written by the page author; untrusted data is passed in as data and never
30
+ * spliced into the expression text.
31
+ */
1
32
  declare class Expressions {
2
33
  #private;
3
34
  static MODE_EXPRESSION: symbol;
@@ -32,15 +63,29 @@ declare class Expressions {
32
63
  [x: string]: any;
33
64
  } | null | undefined, dataStack: any[], expression: string, mode?: (typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED) | null): any;
34
65
  }
66
+ /**
67
+ * A scope: the modules that `#name:fn()` resolves against and the data stack
68
+ * that a bare identifier resolves against, as a single value. Adding an overlay
69
+ * returns a new evaluator instead of modifying this one, so a template can add
70
+ * data for one subtree without affecting the rest of the render.
71
+ */
35
72
  declare class ExpressionEvaluator {
36
73
  #private;
37
74
  constructor(modules: any, dataStack: any);
38
75
  withModule(name: any, value: any): ExpressionEvaluator;
39
76
  withOverlay(...data: any[]): ExpressionEvaluator;
40
- evaluate(expression: any, mode: any): any;
77
+ /**
78
+ * Resolves a name against the data stack, with no parse round trip: the
79
+ * lookup a template's bare identifier makes, for an imperative caller.
80
+ * @param {string} name
81
+ */
82
+ resolve(name: string): any;
83
+ /** Evaluates an expression against this scope. */
41
84
  evaluateExpression(expression: any): any;
42
- evaluateTemplated(expression: any): any;
85
+ /** Evaluates a templated text, the `{{ }}` form, against this scope. */
86
+ evaluateTemplated(text: any): any;
43
87
  }
88
+ /** Creates and inspects the DocumentFragments a Template renders into. */
44
89
  declare class Fragments {
45
90
  /**
46
91
  * Creates a DocumentFragment from an string.
@@ -49,7 +94,9 @@ declare class Fragments {
49
94
  */
50
95
  static fromHtml(...html: string[]): DocumentFragment;
51
96
  /**
52
- * Creates a string representation (HTML) of a DocumentFragment.
97
+ * Creates a string representation (HTML) of a DocumentFragment, consuming it:
98
+ * the nodes are moved out, not copied, and the fragment is left empty. Pass
99
+ * `fragment.cloneNode(true)` to keep the original usable.
53
100
  * @param {DocumentFragment} fragment
54
101
  * @returns {string} the html
55
102
  */
@@ -73,6 +120,7 @@ declare class Fragments {
73
120
  */
74
121
  static fromChildNodes(el: Node): DocumentFragment;
75
122
  }
123
+ /** Attribute reads and writes where a nullish value removes the attribute instead of setting it to the string 'null'. */
76
124
  declare class Attributes {
77
125
  static id: number;
78
126
  /**
@@ -96,19 +144,6 @@ declare class Attributes {
96
144
  * @param {Element} to
97
145
  */
98
146
  static forward(prefix: string, from: Element, to: Element): void;
99
- /**
100
- * Changes the presence of an attribute.
101
- * @param {Element} el
102
- * @param {string} attr
103
- * @param {boolean} value
104
- */
105
- static toggle(el: Element, attr: string, value: boolean): void;
106
- /**
107
- * Changes the presence of an attribute based on its current state.
108
- * @param {Element} el
109
- * @param {string} attr
110
- */
111
- static flip(el: Element, attr: string): void;
112
147
  /**
113
148
  * Sets the value of an attribute. nullish values remove the attribute.
114
149
  * @param {Element} el
@@ -117,6 +152,12 @@ declare class Attributes {
117
152
  */
118
153
  static set(el: Element, attr: string, value: string | null | undefined): void;
119
154
  }
155
+ /**
156
+ * Reads an element's light-dom slots: the named `<template slot=…>` and
157
+ * `[slot=…]` children are removed and collected by name, and the remaining
158
+ * children become the default slot. fml renders into the light dom, so this
159
+ * replaces the slotting a shadow root would do.
160
+ */
120
161
  declare class LightSlots {
121
162
  /**
122
163
  * Extracts light slots from an element. For non default slots in a template tag, the content is extracted.
@@ -128,6 +169,7 @@ declare class LightSlots {
128
169
  };
129
170
  static slotFromNode(el: any): any;
130
171
  }
172
+ /** Waits for the parser and for the document, for elements that upgrade before their own markup is complete. */
131
173
  declare class Nodes {
132
174
  /**
133
175
  * Checks if an element is already parsed.
@@ -135,6 +177,35 @@ declare class Nodes {
135
177
  * @returns
136
178
  */
137
179
  static isParsed(el: Element): boolean;
180
+ /**
181
+ * Waits for the document's DOMContentLoaded, resolving immediately when
182
+ * that moment already passed. 'interactive' alone cannot tell a document
183
+ * still waiting for deferred scripts (the event comes, however late) from
184
+ * a module imported past it (the event is gone): the two events order
185
+ * themselves, DOMContentLoaded always precedes load, so racing the two
186
+ * resolves with DCL whenever it is still coming and with load otherwise,
187
+ * never early.
188
+ */
189
+ static waitDomContentLoaded(doc: any): Promise<any>;
190
+ /**
191
+ * Waits for the element's closing tag to be parsed: one MutationObserver
192
+ * resolves once the element, or any of its ancestors, gains a next sibling,
193
+ * which is the parser having moved past this subtree. The document's
194
+ * DOMContentLoaded is the deadline. Resolves immediately for an element
195
+ * that is already parsed.
196
+ *
197
+ * Every ancestor is watched, not only the parent, because that is what the
198
+ * predicate reads: an element last among its siblings becomes parsed when
199
+ * an ancestor gains one, and a childList observer on the parent never sees
200
+ * that. Formatted markup usually hides the difference, the whitespace
201
+ * before a closing tag being a text node the parent does gain, so the gap
202
+ * shows on whitespace-free markup, where the wait fell back to the
203
+ * deadline. One observer takes many targets, so the cost is one observe()
204
+ * per level, and it is disconnected at the first checkpoint past the
205
+ * element either way.
206
+ * @param {any} el
207
+ * @returns {Promise<any>}
208
+ */
138
209
  static waitParsed(el: any): Promise<any>;
139
210
  /**
140
211
  * Returns the first child of the element element (if exists) matching the selector.
@@ -151,6 +222,12 @@ declare class Nodes {
151
222
  */
152
223
  static queryChildrenAll(el: Element, selector: string): Element[];
153
224
  }
225
+ /**
226
+ * A compiled fragment together with the scope it renders in. Both are
227
+ * immutable: adding data or replacing the scope returns a new Template, so one
228
+ * piece of compiled markup can be rendered against any number of scopes and a
229
+ * registry can reuse a single template for every element that requests it.
230
+ */
154
231
  declare class Template {
155
232
  #private;
156
233
  /**
@@ -194,29 +271,17 @@ declare class Template {
194
271
  [k: string]: any;
195
272
  } | null, ...data: any[]): Template;
196
273
  /**
197
- * Creates a template.
274
+ * Creates a template: a fragment plus the scope it renders in.
198
275
  * @param {DocumentFragment} fragment
199
- * @param {{ [x: string]: any; } | null | undefined} modules
200
- * @param {any[]} dataStack
201
- */
202
- constructor(fragment: DocumentFragment, modules: {
203
- [x: string]: any;
204
- } | null | undefined, dataStack: any[]);
205
- /**
206
- * Creates a new Template replacing the modules and dataStack from a context.
207
- * @param {{modules: { [x: string]: any; } | null | undefined, data: any[]}} context
276
+ * @param {ExpressionEvaluator} evaluator the modules and data stack the expressions resolve against
208
277
  */
209
- withContext({ modules, data }: {
210
- modules: {
211
- [x: string]: any;
212
- } | null | undefined;
213
- data: any[];
214
- }): Template;
278
+ constructor(fragment: DocumentFragment, evaluator: ExpressionEvaluator);
215
279
  /**
216
- * Creates a new Template replacing the modules and dataStack from a registry.
217
- * @param any registry
280
+ * Creates a new Template rendering in another scope: the one way to rebind
281
+ * a compiled template to a registry's modules and data.
282
+ * @param {ExpressionEvaluator} evaluator
218
283
  */
219
- withContextFrom(registry: any): Template;
284
+ withEvaluator(evaluator: ExpressionEvaluator): Template;
220
285
  /**
221
286
  * Creates a new Template replacing the fragment.
222
287
  * @param {DocumentFragment} fragment
@@ -230,31 +295,25 @@ declare class Template {
230
295
  withModule(name: string | null, value: {
231
296
  [k: string]: any;
232
297
  }): Template;
233
- /**
234
- * Creates a new Template replacing the modules.
235
- * @param {{ [x: string]: any; }?} modules
236
- */
237
- withModules(modules: {
238
- [x: string]: any;
239
- } | null): Template;
240
- /**
241
- * Creates a new Template replacing the data stack.
242
- * @param {any[]} dataStack the dataStack
243
- */
244
- withData(dataStack: any[]): Template;
245
298
  /**
246
299
  * Creates a new Template with new a data overlay added to the stack.
247
300
  * @param {...*} data
248
301
  */
249
302
  withOverlay(...data: any[]): Template;
250
303
  /**
251
- * Evaluates an expression using the configured modules and data.
304
+ * Evaluates an expression in this template's scope, widened by the overlays.
252
305
  * @param {string} expression
253
- * @param {(typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED)?} [mode]
254
306
  * @param {...*} data
255
307
  * @returns the evaluated expression result
256
308
  */
257
- evaluate(expression: string, mode?: (typeof Expressions.MODE_EXPRESSION | typeof Expressions.MODE_TEMPLATED) | null, ...data: any[]): any;
309
+ evaluateExpression(expression: string, ...data: any[]): any;
310
+ /**
311
+ * Evaluates a templated text, the `{{ }}` form, in this template's scope.
312
+ * @param {string} text
313
+ * @param {...*} data
314
+ * @returns the parts the text evaluates to
315
+ */
316
+ evaluateTemplated(text: string, ...data: any[]): any;
258
317
  /**
259
318
  * Returns an expression evaluator with bound modules and dataStack.
260
319
  */
@@ -275,48 +334,208 @@ declare class Template {
275
334
  */
276
335
  appendTo(el: Element): void;
277
336
  /**
278
- * Renders this template appending the resulting fragment to the first Element maching the selector, if exists.
337
+ * Renders this template on the first Element matching the selector (replacing children), if exists.
279
338
  * @param {string} selector
280
339
  */
281
340
  renderToSelector(selector: string): void;
282
341
  /**
283
- * Renders this template appending the resulting fragment to the Element maching the selector, if exists.
342
+ * Renders this template appending the resulting fragment to the Element matching the selector, if exists.
284
343
  * @param {string} selector
285
344
  */
286
345
  appendToSelector(selector: string): void;
287
346
  }
347
+ /**
348
+ * A render failure, one frame per nesting level. Each frame names the node it
349
+ * failed on and what was being evaluated there, so the chain reads as the path
350
+ * from the template's root down to the offending expression. The frame carries
351
+ * the node's identification only, an open tag rather than its whole subtree:
352
+ * the markup is serialized on demand through `html`, and the live node stays on
353
+ * `node`, so a failure costs no clone and a nested failure does not embed the
354
+ * page in its own message.
355
+ */
288
356
  declare class RenderError extends Error {
289
357
  #private;
290
- node: any;
358
+ /**
359
+ * How many frames a chain keeps. The innermost are the specific ones, so a
360
+ * deeper nesting drops the outer context rather than the failure site: three
361
+ * frames name the offending node and the two levels that hold it, which is
362
+ * the path a reader follows without the page arriving with it.
363
+ */
364
+ static FRAMES: number;
365
+ /** true when the budget dropped the outer frames of this chain */
366
+ truncated: boolean;
367
+ /**
368
+ * Frames a failure, unless the chain already spent its budget: then the
369
+ * cause travels on, marked so a report can say the outer context was
370
+ * dropped.
371
+ */
372
+ static wrap(message: any, nodeOrFragment: any, cause: any): RenderError;
291
373
  constructor(message: any, nodeOrFragment: any, cause: any);
374
+ /** How many frames this chain carries, this one included. */
375
+ get depth(): any;
376
+ /** The node the render failed on, live: it keeps its place in the fragment being built. */
377
+ get node(): any;
378
+ /** The node's markup, serialized when asked for rather than on every failure. */
379
+ get html(): string;
380
+ /**
381
+ * What identifies a node in a frame: an element by its open tag, a text node
382
+ * by its source, a fragment by the open tags of the elements it holds.
383
+ */
384
+ static describe(nodeOrFragment: any): any;
292
385
  static stringify(nodeOrFragment: any): string;
293
386
  }
387
+ /**
388
+ * The page's single source of truth for elements, modules, data, components
389
+ * and attribute mappers. Elements defined before configure() are deferred and
390
+ * defined by it; from then on every defineElement takes effect immediately.
391
+ * The exported `registry` singleton is the page's own; a `new Registry()` is a
392
+ * separate instance, and Rendering and the ftl:ready machinery wait on the
393
+ * singleton alone.
394
+ */
294
395
  declare class Registry {
295
396
  #private;
296
- defineElement(tag: any, klass: any): this;
297
- defineModule(name: any, value: any): this;
298
- defineModules(ms: any): this;
299
- defineComponent(name: any, value: any): this;
397
+ /**
398
+ * Registers a custom element under its tag: the class is augmented with its
399
+ * BITS (observed attributes, mappers, templates) and handed to the platform.
400
+ * Before configure() the definition is deferred, so import order never
401
+ * matters.
402
+ * @param {string} tag
403
+ * @param {*} klass a ParsedElement subclass
404
+ */
405
+ defineElement(tag: string, klass: any): this;
406
+ /**
407
+ * The attribute declarations a class composes along its inheritance chain,
408
+ * base first: `observed` stay live after the upgrade and drive the property
409
+ * `propertyOf` names, `attributes` are the configuration read once at it and
410
+ * drive no property at all. A subclass's entry for a name overrides its
411
+ * ancestors', so a base class declares what every subclass keeps observing
412
+ * (a protocol attribute such as Field's disabled claim) and a leaf refines a
413
+ * mapping, or moves a name's position, without repeating the whole list.
414
+ *
415
+ * The walk stops where the platform's own class hierarchy begins: no earlier
416
+ * stop can work, since a registered ancestor carries an own BITS of its own,
417
+ * and nothing above the elements declares anything.
418
+ *
419
+ * Everything deriving a component's attribute vocabulary reads it here, so
420
+ * the runtime and whatever documents it cannot walk the chain differently.
421
+ * @param {*} klass a ParsedElement subclass
422
+ * @returns {{ observed: string[], attributes: string[] }}
423
+ */
424
+ static declarationsOf(klass: any): {
425
+ observed: string[];
426
+ attributes: string[];
427
+ };
428
+ /**
429
+ * The property an observed attribute drives, by the platform's own
430
+ * dash-to-camel rule: the one `dataset` applies, so `clear-invalid-on-change`
431
+ * would reach `clearInvalidOnChange` the way `data-clear-invalid-on-change`
432
+ * reaches `dataset.clearInvalidOnChange`. A single-word name is returned
433
+ * unchanged, which is what every observed attribute in the library is.
434
+ *
435
+ * It exists because the observed tier is the one that becomes properties:
436
+ * without it an attribute could only be observed if its name happened to be
437
+ * a usable identifier, which is why every multiword observed attribute here
438
+ * used to be squashed into one word while the configuration tier, which
439
+ * never becomes a property, spelled the same idea with a dash.
440
+ *
441
+ * Only this direction is mapped. A property never derives its attribute: a
442
+ * setter reflects through `reflectTo`, naming the attribute it writes.
443
+ * @param {string} attribute
444
+ * @returns {string}
445
+ */
446
+ static propertyOf(attribute: string): string;
447
+ /**
448
+ * Merges one module under its name, its functions resolving as
449
+ * `#name:fn`; an empty name merges a whole map, whose keys resolve bare,
450
+ * as `#fn`.
451
+ * @param {string} name
452
+ * @param {object} value
453
+ */
454
+ defineModule(name: string, value: object): this;
455
+ /**
456
+ * Replaces the whole module map.
457
+ * @param {object} ms
458
+ */
459
+ defineModules(ms: object): this;
460
+ /**
461
+ * Registers a named component (a loader, a response mapper), fetched back
462
+ * through component().
463
+ * @param {string} name
464
+ * @param {*} value
465
+ */
466
+ defineComponent(name: string, value: any): this;
467
+ /**
468
+ * Replaces the data stack the templates evaluate over.
469
+ * @param {...any} data
470
+ */
300
471
  defineData(...data: any[]): this;
472
+ /**
473
+ * Appends to the data stack, the later entry winning a shared name.
474
+ * @param {...any} data
475
+ */
301
476
  defineOverlay(...data: any[]): this;
302
- defineMapper(k: any, v: any): this;
303
- plugin(p: any): this;
477
+ /**
478
+ * Registers a custom attribute mapper type, available to every later
479
+ * `name:type` declaration.
480
+ * @param {string} k
481
+ * @param {{ unmarshal(str: string|null, name: string, el: Element): any, marshal(value: any, name: string, el: Element): string|null }} v
482
+ */
483
+ defineMapper(k: string, v: {
484
+ unmarshal(str: string | null, name: string, el: Element): any;
485
+ marshal(value: any, name: string, el: Element): string | null;
486
+ }): this;
487
+ /**
488
+ * Hands the registry over to the plugin's configure.
489
+ * @param {{ configure(registry: Registry): void }} p
490
+ */
491
+ plugin(p: {
492
+ configure(registry: Registry): void;
493
+ }): this;
494
+ /**
495
+ * Defines every element deferred so far; from then on, defineElement takes
496
+ * effect immediately.
497
+ */
304
498
  configure(): this;
305
- get upgrades(): MapIterator<[any, any]>;
306
- context(): {
307
- modules: any;
308
- data: any[];
309
- };
499
+ /**
500
+ * Waits for the queued upgrades the filter accepts, rejecting with the first
501
+ * that failed: the rejecting barrier Rendering is a facade over.
502
+ * @param {(el: Element) => boolean} accept
503
+ */
504
+ settle(accept: (el: Element) => boolean): Promise<void>;
505
+ /** The pending upgrade of one element, undefined when it is not queued. */
506
+ whenUpgraded(el: any): any;
507
+ /** The elements whose upgrade is still pending, in queue order. */
508
+ pending(): any[];
509
+ /**
510
+ * Waits for the page's readiness: the same moment the ftl:ready event is
511
+ * dispatched at, resolving immediately when that moment already passed.
512
+ * @returns {Promise<void>}
513
+ */
514
+ ready(): Promise<void>;
515
+ /**
516
+ * The scope every template on this registry renders in: the modules and the
517
+ * data stack, as one value. Replaced whenever either is defined, so a holder
518
+ * of an older one keeps rendering against what it was handed.
519
+ */
310
520
  evaluator(): ExpressionEvaluator;
521
+ /** The component registered under the name, undefined when none is. */
311
522
  component(name: any): any;
312
523
  }
313
524
  declare const registry: Registry;
525
+ /** The Template factories, each bound to the page registry's scope. */
526
+ /** The Template factories bound to the page's own registry: the same four sources, with its modules and data already applied. */
314
527
  declare class Templates {
315
528
  static fromHtml(html: any): Template;
316
529
  static fromSelector(selector: any): Template;
317
530
  static fromTemplate(templateEl: any): Template;
318
531
  static fromFragment(fragment: any): Template;
319
532
  }
533
+ /**
534
+ * Awaitable rendering barriers over the registry's upgrade queue. These are
535
+ * the rejecting waits: a failed upgrade among the awaited components rejects
536
+ * the wait, where registry.ready() only ever means the queue drained and
537
+ * leaves a failed component to its own unhandled-rejection report.
538
+ */
320
539
  declare class Rendering {
321
540
  static waitFor(el: any): Promise<void>;
322
541
  static waitForChildren(el: any): Promise<void>;
@@ -335,51 +554,170 @@ export type Mapper = {
335
554
  declare class ParsedElement extends HTMLElement {
336
555
  #private;
337
556
  static BITS: {
557
+ registry: Registry;
338
558
  enqueue: (el: any) => void;
339
559
  SLOTS: boolean;
340
- OBSERVED: never[];
560
+ /** @type {object|undefined} */
561
+ CONFIG: object | undefined;
562
+ /** @type {string[]} */
563
+ OBSERVED: string[];
564
+ /** @type {string[]} */
565
+ DECLARED: string[];
341
566
  /** @type {Record<string, Mapper>} */
342
567
  ATTR_TO_MAPPER: Record<string, Mapper>;
568
+ /** @type {Record<string, string>} */
569
+ ATTR_TO_PROPERTY: Record<string, string>;
343
570
  TEMPLATES: {};
344
571
  };
345
- static get observedAttributes(): never[];
572
+ static get observedAttributes(): string[];
573
+ constructor();
574
+ /**
575
+ * The platform's window into the element's own state. The base attaches it
576
+ * for every element, so a subclass never calls attachInternals itself: the
577
+ * platform allows it once, and a second call throws. Form association is a
578
+ * property of the definition rather than of who attached, so a subclass
579
+ * declaring `static formAssociated` still gets the form apis here.
580
+ *
581
+ * A subclass must not redeclare it: a class field with no initializer
582
+ * assigns undefined after super() returns, which would wipe it.
583
+ */
584
+ internals: ElementInternals;
346
585
  unmarshal(attr: any, str: any): any;
347
586
  marshal(attr: any, value: any): string | null;
348
587
  /**
349
588
  * @param {string} [name] - The name of the template target, defaults to 'default'
350
589
  */
351
- template(name?: string): any;
590
+ /** The registry that defined this element, the page's own for an undefined one. */
591
+ get _registry(): Registry;
592
+ /**
593
+ * The component registered under the name on this element's registry, the
594
+ * one every ful loader and mapper resolves through.
595
+ * @param {string} name
596
+ */
597
+ component(name: string): any;
598
+ template(name: any): any;
352
599
  connectedCallback(): void;
353
600
  attributeChangedCallback(attr: any, oldValue: any, newValue: any): void;
354
601
  /**
355
- * The disabled protocol follows the semantics of a native form control:
356
- *
357
- * - the `disabled` attribute on the host is the field's own claim, and nothing
358
- * but its author ever writes or removes it, in markup or through the property.
359
- * The framework never claims on the form's behalf, so there is nothing to
360
- * unclaim and nothing to lose: a field declared disabled inside a disabled
361
- * `<fieldset>` stays disabled when the fieldset comes back, exactly like a
362
- * native input keeps its attribute.
363
- * - the effective state is the claim OR a disabled fieldset ancestry, which the
364
- * platform maintains on its own: `:disabled` matches both, a disabled field is
365
- * left out of the submitted values, and the inner native controls are reached
366
- * by the ancestry as descendants of the fieldset.
367
- * - the `disabled` property reflects the claim only, like a native input's: a
368
- * field disabled by its ancestry reads `false` while `matches(':disabled')`
369
- * tells the effective state. Un-claiming inside a disabled fieldset cannot
370
- * enable the field.
371
- * - the inner controls mirror the claim and nothing else: the ancestry state is
372
- * never written anywhere, so it can never go stale, and the browser composes
373
- * the two on its own when it disables and re-enables a fieldset's descendants.
602
+ * Upgrades once: reads the declared attributes, keeps the observed half open
603
+ * to writes made while the render is pending, applies them to the properties
604
+ * when the render returns, and only then lets an attribute write forward.
374
605
  *
375
- * Because of this, formDisabledCallback carries nothing the framework needs to
376
- * apply, and the protocol does not define it.
606
+ * An observed attribute drives the property the registry's `propertyOf`
607
+ * names, so a hyphenated attribute is authored with its dashes and read as
608
+ * a camelCase property. A single-word attribute is its own property name,
609
+ * which is what every observed attribute in the library is.
377
610
  */
378
611
  upgrade(): Promise<void>;
379
- render(c: any): void;
380
- reflect(fn: any): void;
381
- reflectTo(attr: any, value: any): void;
612
+ /**
613
+ * Renders the element from its slots alone: it builds the dom its setters
614
+ * drive, and the base applies the declared state onto the properties as
615
+ * soon as it returns. A render needing a declared value while it builds
616
+ * reads it through `declared(name)`. The slots are undefined for an element
617
+ * declaring no slots.
618
+ * @param {{ slots: any }} c
619
+ */
620
+ render(c: {
621
+ slots: any;
622
+ }): void;
623
+ /**
624
+ * The declared value of an attribute, unmarshalled through its mapper.
625
+ *
626
+ * A `static attributes` name is the configuration tier: read once when the
627
+ * upgrade starts and answered unchanged for the element's life, so a later
628
+ * attribute write does not quietly change how the element behaves. An
629
+ * observed name answers the snapshot while the render is pending, kept
630
+ * open to attribute writes landing in that window, and the live attribute
631
+ * afterwards, the property being live by then.
632
+ *
633
+ * The snapshot exists rather than a read of the dom because an element may
634
+ * write its own observed attributes while it renders, whether a reflection
635
+ * or a value the platform normalizes on the way in, and what the author
636
+ * declared is what the base applies, not what the render left behind.
637
+ * @param {string} name
638
+ */
639
+ declared(name: string): any;
640
+ /** Whether the element's render completed: the moment its properties went live. */
641
+ get rendered(): boolean;
642
+ /**
643
+ * Projects a property back onto its observed attribute, marshalled through
644
+ * the mapper the attribute was declared with: the one place a property
645
+ * reaches its attribute, so a setter never has to know how its own type
646
+ * serializes.
647
+ *
648
+ * A value the attribute already carries is not written at all, so reflecting
649
+ * what an attribute write just delivered ends there rather than looping, and
650
+ * only the attribute being written is muted while it happens.
651
+ * @param {string} attr
652
+ * @param {any} value
653
+ */
654
+ reflectTo(attr: string, value: any): void;
655
+ }
656
+ export type Messages = Record<string, string | Record<string, string>>;
657
+ export type Receiver = {
658
+ l10n?: Messages;
659
+ locale?: string;
660
+ };
661
+ /**
662
+ * The translations as a template module: `#l10n:t()` for messages, plus date,
663
+ * number and bytes formatting in the page's locale. The template form and the
664
+ * imperative `of()` facade both resolve through the registry's scope, so they
665
+ * always produce the same result for the same key.
666
+ */
667
+ declare class Localization {
668
+ /**
669
+ * Resolves a message from the translations and interpolates its arguments.
670
+ * A single plain object argument interpolates named placeholders
671
+ * ({name}); anything else interpolates positional ones ({0}).
672
+ * A plural leaf selects its form through Intl.PluralRules over the
673
+ * numeric {count} named argument.
674
+ *
675
+ * @param {string} key
676
+ * @param {...any} args
677
+ * @this {Receiver}
678
+ * @returns {string} the message, or the key itself when the translations do not carry it
679
+ */
680
+ static t(this: Receiver, key: string, ...args: any[]): string;
681
+ /**
682
+ * Formats a date through Intl.DateTimeFormat in the receiver's locale.
683
+ *
684
+ * @param {Date | number} value
685
+ * @param {Intl.DateTimeFormatOptions} [options]
686
+ * @this {Receiver}
687
+ */
688
+ static date(this: Receiver, value: Date | number, options?: Intl.DateTimeFormatOptions): any;
689
+ /**
690
+ * Formats a number through Intl.NumberFormat in the receiver's locale.
691
+ *
692
+ * @param {number} value
693
+ * @param {Intl.NumberFormatOptions} [options]
694
+ * @this {Receiver}
695
+ */
696
+ static number(this: Receiver, value: number, options?: Intl.NumberFormatOptions): any;
697
+ /**
698
+ * Formats a byte size with binary thresholds and literal unit suffixes:
699
+ * the digits honor the locale, the units are the near-universal KiB/MiB/GiB.
700
+ * A size exactly on a threshold takes the larger unit: 1024 is 1KiB.
701
+ *
702
+ * @param {number} value
703
+ * @this {Receiver}
704
+ */
705
+ static bytes(this: Receiver, value: number): string;
706
+ /**
707
+ * An imperative facade over the module functions, resolving the translations
708
+ * and the locale from the registry overlays on every call.
709
+ *
710
+ * @param {{ locale?: string }} [overrides] an explicit locale, winning over the registry one
711
+ */
712
+ static of(overrides?: {
713
+ locale?: string;
714
+ }): {
715
+ t: (...args: any[]) => any;
716
+ date: (...args: any[]) => any;
717
+ number: (...args: any[]) => any;
718
+ bytes: (...args: any[]) => any;
719
+ };
382
720
  }
383
- export { Attributes, ExpressionEvaluator, Expressions, Fragments, LightSlots, Nodes, ParsedElement, Registry, RenderError, Rendering, Template, Templates, registry };
721
+ export { Attributes, BoundedCache, ExpressionEvaluator, Expressions, Fragments, LightSlots, Localization, Nodes, ParsedElement, Registry, RenderError, Rendering, Template, Templates, registry };
384
722
 
385
723
  export as namespace ftl;