@microsoft/fast-element 2.7.0 → 2.8.1
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/CHANGELOG.json +31 -1
- package/CHANGELOG.md +18 -2
- package/dist/dts/components/element-controller.d.ts +56 -0
- package/dist/dts/components/fast-definitions.d.ts +31 -2
- package/dist/dts/index.d.ts +2 -2
- package/dist/esm/components/element-controller.js +98 -14
- package/dist/esm/components/fast-definitions.js +17 -12
- package/dist/esm/index.js +1 -1
- package/dist/esm/polyfills.js +33 -0
- package/dist/esm/templating/view.js +23 -2
- package/dist/fast-element.api.json +431 -2
- package/dist/fast-element.debug.js +171 -28
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +171 -28
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +90 -2
- package/docs/api-report.api.md +23 -1
- package/package.json +1 -1
package/CHANGELOG.json
CHANGED
|
@@ -2,7 +2,37 @@
|
|
|
2
2
|
"name": "@microsoft/fast-element",
|
|
3
3
|
"entries": [
|
|
4
4
|
{
|
|
5
|
-
"date": "
|
|
5
|
+
"date": "Tue, 21 Oct 2025 16:17:03 GMT",
|
|
6
|
+
"version": "2.8.1",
|
|
7
|
+
"tag": "@microsoft/fast-element_v2.8.1",
|
|
8
|
+
"comments": {
|
|
9
|
+
"patch": [
|
|
10
|
+
{
|
|
11
|
+
"author": "863023+radium-v@users.noreply.github.com",
|
|
12
|
+
"package": "@microsoft/fast-element",
|
|
13
|
+
"commit": "d66ae6571c97341890e5320048fc1a3ef38dc5be",
|
|
14
|
+
"comment": "feat: add methods to track hydrating instances"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"date": "Mon, 13 Oct 2025 00:37:08 GMT",
|
|
21
|
+
"version": "2.8.0",
|
|
22
|
+
"tag": "@microsoft/fast-element_v2.8.0",
|
|
23
|
+
"comments": {
|
|
24
|
+
"minor": [
|
|
25
|
+
{
|
|
26
|
+
"author": "863023+radium-v@users.noreply.github.com",
|
|
27
|
+
"package": "@microsoft/fast-element",
|
|
28
|
+
"commit": "28a1d5dcae41f04e2ff8cb9114c312efb88fb1e1",
|
|
29
|
+
"comment": "[feat]: implement lifecycle callbacks for hydration and template events"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"date": "Wed, 20 Aug 2025 20:57:02 GMT",
|
|
6
36
|
"version": "2.7.0",
|
|
7
37
|
"tag": "@microsoft/fast-element_v2.7.0",
|
|
8
38
|
"comments": {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
# Change Log - @microsoft/fast-element
|
|
2
2
|
|
|
3
|
-
<!-- This log was last generated on
|
|
3
|
+
<!-- This log was last generated on Tue, 21 Oct 2025 16:17:03 GMT and should not be manually modified. -->
|
|
4
4
|
|
|
5
5
|
<!-- Start content -->
|
|
6
6
|
|
|
7
|
+
## 2.8.1
|
|
8
|
+
|
|
9
|
+
Tue, 21 Oct 2025 16:17:03 GMT
|
|
10
|
+
|
|
11
|
+
### Patches
|
|
12
|
+
|
|
13
|
+
- feat: add methods to track hydrating instances (863023+radium-v@users.noreply.github.com)
|
|
14
|
+
|
|
15
|
+
## 2.8.0
|
|
16
|
+
|
|
17
|
+
Mon, 13 Oct 2025 00:37:08 GMT
|
|
18
|
+
|
|
19
|
+
### Minor changes
|
|
20
|
+
|
|
21
|
+
- [feat]: implement lifecycle callbacks for hydration and template events (863023+radium-v@users.noreply.github.com)
|
|
22
|
+
|
|
7
23
|
## 2.7.0
|
|
8
24
|
|
|
9
|
-
Wed, 20 Aug 2025 20:
|
|
25
|
+
Wed, 20 Aug 2025 20:57:02 GMT
|
|
10
26
|
|
|
11
27
|
### Minor changes
|
|
12
28
|
|
|
@@ -206,6 +206,24 @@ export declare class StyleElementStrategy implements StyleStrategy {
|
|
|
206
206
|
}
|
|
207
207
|
export declare const deferHydrationAttribute = "defer-hydration";
|
|
208
208
|
export declare const needsHydrationAttribute = "needs-hydration";
|
|
209
|
+
/**
|
|
210
|
+
* Lifecycle callbacks for element hydration events
|
|
211
|
+
* @public
|
|
212
|
+
*/
|
|
213
|
+
export interface HydrationControllerCallbacks {
|
|
214
|
+
/**
|
|
215
|
+
* Called before hydration has started
|
|
216
|
+
*/
|
|
217
|
+
elementWillHydrate?(name: string): void;
|
|
218
|
+
/**
|
|
219
|
+
* Called after hydration has finished
|
|
220
|
+
*/
|
|
221
|
+
elementDidHydrate?(name: string): void;
|
|
222
|
+
/**
|
|
223
|
+
* Called after all elements have completed hydration
|
|
224
|
+
*/
|
|
225
|
+
hydrationComplete?(): void;
|
|
226
|
+
}
|
|
209
227
|
/**
|
|
210
228
|
* An ElementController capable of hydrating FAST elements from
|
|
211
229
|
* Declarative Shadow DOM.
|
|
@@ -220,9 +238,47 @@ export declare class HydratableElementController<TElement extends HTMLElement =
|
|
|
220
238
|
*/
|
|
221
239
|
protected needsHydration?: boolean;
|
|
222
240
|
private static hydrationObserver;
|
|
241
|
+
/**
|
|
242
|
+
* Lifecycle callbacks for hydration events
|
|
243
|
+
*/
|
|
244
|
+
static lifecycleCallbacks?: HydrationControllerCallbacks;
|
|
245
|
+
/**
|
|
246
|
+
* An idle callback ID used to track hydration completion
|
|
247
|
+
*/
|
|
248
|
+
private static idleCallbackId;
|
|
249
|
+
/**
|
|
250
|
+
* Adds the current element instance to the hydrating instances map
|
|
251
|
+
*/
|
|
252
|
+
private addHydratingInstance;
|
|
253
|
+
/**
|
|
254
|
+
* Configure lifecycle callbacks for hydration events
|
|
255
|
+
*/
|
|
256
|
+
static config(callbacks: HydrationControllerCallbacks): typeof HydratableElementController;
|
|
223
257
|
private static hydrationObserverHandler;
|
|
258
|
+
/**
|
|
259
|
+
* Checks to see if hydration is complete and if so, invokes the hydrationComplete callback.
|
|
260
|
+
* Then resets the ElementController strategy to the default so that future elements
|
|
261
|
+
* don't use the HydratableElementController.
|
|
262
|
+
*
|
|
263
|
+
* @param deadline - the idle deadline object
|
|
264
|
+
*/
|
|
265
|
+
private static checkHydrationComplete;
|
|
224
266
|
static forCustomElement(element: HTMLElement, override?: boolean): ElementController<HTMLElement>;
|
|
225
267
|
connect(): void;
|
|
268
|
+
/**
|
|
269
|
+
* A map of element instances by the name of the custom element they are
|
|
270
|
+
* associated with. The key is the custom element name, and the value is the
|
|
271
|
+
* instances of hydratable elements which currently need to be hydrated.
|
|
272
|
+
*
|
|
273
|
+
* When all of the instances in the set have been hydrated, the set is
|
|
274
|
+
* cleared and removed from the map. If the map is empty, the
|
|
275
|
+
* hydrationComplete callback is invoked.
|
|
276
|
+
*/
|
|
277
|
+
private static hydratingInstances?;
|
|
278
|
+
/**
|
|
279
|
+
* Removes the current element instance from the hydrating instances map
|
|
280
|
+
*/
|
|
281
|
+
private removeHydratingInstance;
|
|
226
282
|
disconnect(): void;
|
|
227
283
|
static install(): void;
|
|
228
284
|
}
|
|
@@ -22,10 +22,31 @@ export interface ShadowRootOptions extends ShadowRootInit {
|
|
|
22
22
|
registry?: CustomElementRegistry;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Values for the `templateOptions` property.
|
|
26
26
|
* @alpha
|
|
27
27
|
*/
|
|
28
|
-
export declare
|
|
28
|
+
export declare const TemplateOptions: {
|
|
29
|
+
readonly deferAndHydrate: "defer-and-hydrate";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Type for the `TemplateOptions` const enum.
|
|
33
|
+
* @alpha
|
|
34
|
+
*/
|
|
35
|
+
export declare type TemplateOptions = (typeof TemplateOptions)[keyof typeof TemplateOptions];
|
|
36
|
+
/**
|
|
37
|
+
* Lifecycle callbacks for template events.
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export interface TemplateLifecycleCallbacks {
|
|
41
|
+
/**
|
|
42
|
+
* Called after the template has been assigned to the definition
|
|
43
|
+
*/
|
|
44
|
+
templateDidUpdate?(name: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Called after the custom element has been defined
|
|
47
|
+
*/
|
|
48
|
+
elementDidDefine?(name: string): void;
|
|
49
|
+
}
|
|
29
50
|
/**
|
|
30
51
|
* Represents metadata configuration for a custom element.
|
|
31
52
|
* @public
|
|
@@ -69,6 +90,10 @@ export interface PartialFASTElementDefinition {
|
|
|
69
90
|
* If not provided, defaults to the global registry.
|
|
70
91
|
*/
|
|
71
92
|
readonly registry?: CustomElementRegistry;
|
|
93
|
+
/**
|
|
94
|
+
* Lifecycle callbacks for template events.
|
|
95
|
+
*/
|
|
96
|
+
readonly lifecycleCallbacks?: TemplateLifecycleCallbacks;
|
|
72
97
|
}
|
|
73
98
|
/**
|
|
74
99
|
* Defines metadata for a FASTElement.
|
|
@@ -125,6 +150,10 @@ export declare class FASTElementDefinition<TType extends Constructable<HTMLEleme
|
|
|
125
150
|
* The registry to register this component in by default.
|
|
126
151
|
*/
|
|
127
152
|
readonly registry: CustomElementRegistry;
|
|
153
|
+
/**
|
|
154
|
+
* Lifecycle callbacks for template events.
|
|
155
|
+
*/
|
|
156
|
+
readonly lifecycleCallbacks?: TemplateLifecycleCallbacks;
|
|
128
157
|
/**
|
|
129
158
|
* The definition has been registered to the FAST element registry.
|
|
130
159
|
*/
|
package/dist/dts/index.d.ts
CHANGED
|
@@ -29,6 +29,6 @@ export { ElementView, HTMLView, SyntheticView, View, HydratableView, HydrationBi
|
|
|
29
29
|
export { elements, ElementsFilter, NodeBehaviorOptions, NodeObservationDirective, } from "./templating/node-observation.js";
|
|
30
30
|
export { render, RenderBehavior, RenderDirective } from "./templating/render.js";
|
|
31
31
|
export { customElement, FASTElement } from "./components/fast-element.js";
|
|
32
|
-
export { FASTElementDefinition, PartialFASTElementDefinition, ShadowRootOptions, fastElementRegistry, TemplateOptions, TypeRegistry, } from "./components/fast-definitions.js";
|
|
32
|
+
export { FASTElementDefinition, PartialFASTElementDefinition, ShadowRootOptions, fastElementRegistry, TemplateOptions, TypeRegistry, type TemplateLifecycleCallbacks, } from "./components/fast-definitions.js";
|
|
33
33
|
export { attr, AttributeConfiguration, AttributeDefinition, AttributeMode, booleanConverter, DecoratorAttributeConfiguration, nullableBooleanConverter, nullableNumberConverter, ValueConverter, } from "./components/attributes.js";
|
|
34
|
-
export { ElementController, ElementControllerStrategy, HydratableElementController, } from "./components/element-controller.js";
|
|
34
|
+
export { ElementController, ElementControllerStrategy, HydratableElementController, type HydrationControllerCallbacks, } from "./components/element-controller.js";
|
|
@@ -4,7 +4,7 @@ import { ExecutionContext, Observable, SourceLifetime, } from "../observation/ob
|
|
|
4
4
|
import { FAST, makeSerializationNoop } from "../platform.js";
|
|
5
5
|
import { ElementStyles } from "../styles/element-styles.js";
|
|
6
6
|
import { UnobservableMutationObserver } from "../utilities.js";
|
|
7
|
-
import { FASTElementDefinition } from "./fast-definitions.js";
|
|
7
|
+
import { FASTElementDefinition, TemplateOptions, } from "./fast-definitions.js";
|
|
8
8
|
import { HydrationMarkup, isHydratable } from "./hydration.js";
|
|
9
9
|
const defaultEventOptions = {
|
|
10
10
|
bubbles: true,
|
|
@@ -591,32 +591,77 @@ export const needsHydrationAttribute = "needs-hydration";
|
|
|
591
591
|
* @beta
|
|
592
592
|
*/
|
|
593
593
|
export class HydratableElementController extends ElementController {
|
|
594
|
+
/**
|
|
595
|
+
* Adds the current element instance to the hydrating instances map
|
|
596
|
+
*/
|
|
597
|
+
addHydratingInstance() {
|
|
598
|
+
if (!HydratableElementController.hydratingInstances) {
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
const name = this.definition.name;
|
|
602
|
+
let instances = HydratableElementController.hydratingInstances.get(name);
|
|
603
|
+
if (!instances) {
|
|
604
|
+
instances = new Set();
|
|
605
|
+
HydratableElementController.hydratingInstances.set(name, instances);
|
|
606
|
+
}
|
|
607
|
+
instances.add(this.source);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Configure lifecycle callbacks for hydration events
|
|
611
|
+
*/
|
|
612
|
+
static config(callbacks) {
|
|
613
|
+
HydratableElementController.lifecycleCallbacks = callbacks;
|
|
614
|
+
return this;
|
|
615
|
+
}
|
|
594
616
|
static hydrationObserverHandler(records) {
|
|
595
617
|
for (const record of records) {
|
|
596
|
-
|
|
597
|
-
|
|
618
|
+
if (!record.target.hasAttribute(deferHydrationAttribute)) {
|
|
619
|
+
HydratableElementController.hydrationObserver.unobserve(record.target);
|
|
620
|
+
record.target.$fastController.connect();
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Checks to see if hydration is complete and if so, invokes the hydrationComplete callback.
|
|
626
|
+
* Then resets the ElementController strategy to the default so that future elements
|
|
627
|
+
* don't use the HydratableElementController.
|
|
628
|
+
*
|
|
629
|
+
* @param deadline - the idle deadline object
|
|
630
|
+
*/
|
|
631
|
+
static checkHydrationComplete(deadline) {
|
|
632
|
+
var _a, _b, _c;
|
|
633
|
+
if (deadline.didTimeout) {
|
|
634
|
+
HydratableElementController.idleCallbackId = requestIdleCallback(HydratableElementController.checkHydrationComplete, { timeout: 50 });
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
// If there are no more hydrating instances, invoke the hydrationComplete callback
|
|
638
|
+
if (((_a = HydratableElementController.hydratingInstances) === null || _a === void 0 ? void 0 : _a.size) === 0) {
|
|
639
|
+
(_c = (_b = HydratableElementController.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.hydrationComplete) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
640
|
+
// Reset to the default strategy after hydration is complete
|
|
641
|
+
ElementController.setStrategy(ElementController);
|
|
598
642
|
}
|
|
599
643
|
}
|
|
600
644
|
static forCustomElement(element, override) {
|
|
601
645
|
const definition = FASTElementDefinition.getForInstance(element);
|
|
602
|
-
if (definition
|
|
603
|
-
definition.templateOptions === "defer-and-hydrate" &&
|
|
646
|
+
if ((definition === null || definition === void 0 ? void 0 : definition.templateOptions) === TemplateOptions.deferAndHydrate &&
|
|
604
647
|
!definition.template) {
|
|
605
|
-
element.
|
|
606
|
-
element.
|
|
648
|
+
element.toggleAttribute(deferHydrationAttribute, true);
|
|
649
|
+
element.toggleAttribute(needsHydrationAttribute, true);
|
|
607
650
|
}
|
|
608
651
|
return super.forCustomElement(element, override);
|
|
609
652
|
}
|
|
610
653
|
connect() {
|
|
611
|
-
var _a, _b;
|
|
654
|
+
var _a, _b, _c, _d, _e;
|
|
612
655
|
// Initialize needsHydration on first connect
|
|
613
|
-
|
|
614
|
-
this.needsHydration
|
|
615
|
-
|
|
656
|
+
this.needsHydration =
|
|
657
|
+
(_a = this.needsHydration) !== null && _a !== void 0 ? _a : this.source.getAttribute(needsHydrationAttribute) !== null;
|
|
658
|
+
if (this.needsHydration) {
|
|
659
|
+
(_c = (_b = HydratableElementController.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.elementWillHydrate) === null || _c === void 0 ? void 0 : _c.call(_b, this.definition.name);
|
|
616
660
|
}
|
|
617
661
|
// If the `defer-hydration` attribute exists on the source,
|
|
618
662
|
// wait for it to be removed before continuing connection behavior.
|
|
619
663
|
if (this.source.hasAttribute(deferHydrationAttribute)) {
|
|
664
|
+
this.addHydratingInstance();
|
|
620
665
|
HydratableElementController.hydrationObserver.observe(this.source, {
|
|
621
666
|
attributeFilter: [deferHydrationAttribute],
|
|
622
667
|
});
|
|
@@ -628,6 +673,7 @@ export class HydratableElementController extends ElementController {
|
|
|
628
673
|
// class
|
|
629
674
|
if (!this.needsHydration) {
|
|
630
675
|
super.connect();
|
|
676
|
+
this.removeHydratingInstance();
|
|
631
677
|
return;
|
|
632
678
|
}
|
|
633
679
|
if (this.stage !== 3 /* Stages.disconnected */) {
|
|
@@ -636,10 +682,10 @@ export class HydratableElementController extends ElementController {
|
|
|
636
682
|
this.stage = 0 /* Stages.connecting */;
|
|
637
683
|
this.bindObservables();
|
|
638
684
|
this.connectBehaviors();
|
|
639
|
-
const element = this.source;
|
|
640
|
-
const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
|
|
641
685
|
if (this.template) {
|
|
642
686
|
if (isHydratable(this.template)) {
|
|
687
|
+
const element = this.source;
|
|
688
|
+
const host = (_d = getShadowRoot(element)) !== null && _d !== void 0 ? _d : element;
|
|
643
689
|
let firstChild = host.firstChild;
|
|
644
690
|
let lastChild = host.lastChild;
|
|
645
691
|
if (element.shadowRoot === null) {
|
|
@@ -654,7 +700,7 @@ export class HydratableElementController extends ElementController {
|
|
|
654
700
|
}
|
|
655
701
|
}
|
|
656
702
|
this.view = this.template.hydrate(firstChild, lastChild, element);
|
|
657
|
-
(
|
|
703
|
+
(_e = this.view) === null || _e === void 0 ? void 0 : _e.bind(this.source);
|
|
658
704
|
}
|
|
659
705
|
else {
|
|
660
706
|
this.renderTemplate(this.template);
|
|
@@ -664,8 +710,32 @@ export class HydratableElementController extends ElementController {
|
|
|
664
710
|
this.stage = 1 /* Stages.connected */;
|
|
665
711
|
this.source.removeAttribute(needsHydrationAttribute);
|
|
666
712
|
this.needsInitialization = this.needsHydration = false;
|
|
713
|
+
this.removeHydratingInstance();
|
|
667
714
|
Observable.notify(this, isConnectedPropertyName);
|
|
668
715
|
}
|
|
716
|
+
/**
|
|
717
|
+
* Removes the current element instance from the hydrating instances map
|
|
718
|
+
*/
|
|
719
|
+
removeHydratingInstance() {
|
|
720
|
+
var _a, _b;
|
|
721
|
+
if (!HydratableElementController.hydratingInstances) {
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const name = this.definition.name;
|
|
725
|
+
const instances = HydratableElementController.hydratingInstances.get(name);
|
|
726
|
+
// Callback: After hydration has finished
|
|
727
|
+
(_b = (_a = HydratableElementController.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.elementDidHydrate) === null || _b === void 0 ? void 0 : _b.call(_a, this.definition.name);
|
|
728
|
+
if (instances) {
|
|
729
|
+
instances.delete(this.source);
|
|
730
|
+
if (!instances.size) {
|
|
731
|
+
HydratableElementController.hydratingInstances.delete(name);
|
|
732
|
+
}
|
|
733
|
+
if (HydratableElementController.idleCallbackId) {
|
|
734
|
+
cancelIdleCallback(HydratableElementController.idleCallbackId);
|
|
735
|
+
}
|
|
736
|
+
HydratableElementController.idleCallbackId = requestIdleCallback(HydratableElementController.checkHydrationComplete, { timeout: 50 });
|
|
737
|
+
}
|
|
738
|
+
}
|
|
669
739
|
disconnect() {
|
|
670
740
|
super.disconnect();
|
|
671
741
|
HydratableElementController.hydrationObserver.unobserve(this.source);
|
|
@@ -675,3 +745,17 @@ export class HydratableElementController extends ElementController {
|
|
|
675
745
|
}
|
|
676
746
|
}
|
|
677
747
|
HydratableElementController.hydrationObserver = new UnobservableMutationObserver(HydratableElementController.hydrationObserverHandler);
|
|
748
|
+
/**
|
|
749
|
+
* An idle callback ID used to track hydration completion
|
|
750
|
+
*/
|
|
751
|
+
HydratableElementController.idleCallbackId = null;
|
|
752
|
+
/**
|
|
753
|
+
* A map of element instances by the name of the custom element they are
|
|
754
|
+
* associated with. The key is the custom element name, and the value is the
|
|
755
|
+
* instances of hydratable elements which currently need to be hydrated.
|
|
756
|
+
*
|
|
757
|
+
* When all of the instances in the set have been hydrated, the set is
|
|
758
|
+
* cleared and removed from the map. If the map is empty, the
|
|
759
|
+
* hydrationComplete callback is invoked.
|
|
760
|
+
*/
|
|
761
|
+
HydratableElementController.hydratingInstances = new Map();
|
|
@@ -21,6 +21,13 @@ const fastElementBaseTypes = new Set();
|
|
|
21
21
|
* @internal
|
|
22
22
|
*/
|
|
23
23
|
export const fastElementRegistry = FAST.getById(KernelServiceId.elementRegistry, () => createTypeRegistry());
|
|
24
|
+
/**
|
|
25
|
+
* Values for the `templateOptions` property.
|
|
26
|
+
* @alpha
|
|
27
|
+
*/
|
|
28
|
+
export const TemplateOptions = {
|
|
29
|
+
deferAndHydrate: "defer-and-hydrate",
|
|
30
|
+
};
|
|
24
31
|
/**
|
|
25
32
|
* Defines metadata for a FASTElement.
|
|
26
33
|
* @public
|
|
@@ -84,10 +91,12 @@ export class FASTElementDefinition {
|
|
|
84
91
|
* This operation is idempotent per registry.
|
|
85
92
|
*/
|
|
86
93
|
define(registry = this.registry) {
|
|
94
|
+
var _b, _c;
|
|
87
95
|
const type = this.type;
|
|
88
96
|
if (!registry.get(this.name)) {
|
|
89
97
|
this.platformDefined = true;
|
|
90
98
|
registry.define(this.name, type, this.elementOptions);
|
|
99
|
+
(_c = (_b = this.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.elementDidDefine) === null || _c === void 0 ? void 0 : _c.call(_b, this.name);
|
|
91
100
|
}
|
|
92
101
|
return this;
|
|
93
102
|
}
|
|
@@ -128,15 +137,13 @@ export class FASTElementDefinition {
|
|
|
128
137
|
}, nameOrDef));
|
|
129
138
|
}
|
|
130
139
|
const definition = new FASTElementDefinition(type, nameOrDef);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
resolve(definition);
|
|
139
|
-
});
|
|
140
|
+
Observable.getNotifier(definition).subscribe({
|
|
141
|
+
handleChange: () => {
|
|
142
|
+
var _b, _c;
|
|
143
|
+
(_c = (_b = definition.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.templateDidUpdate) === null || _c === void 0 ? void 0 : _c.call(_b, definition.name);
|
|
144
|
+
resolve(definition);
|
|
145
|
+
},
|
|
146
|
+
}, "template");
|
|
140
147
|
});
|
|
141
148
|
}
|
|
142
149
|
}
|
|
@@ -165,9 +172,7 @@ FASTElementDefinition.registerAsync = (name) => __awaiter(void 0, void 0, void 0
|
|
|
165
172
|
if (FASTElementDefinition.isRegistered[name]) {
|
|
166
173
|
resolve(FASTElementDefinition.isRegistered[name]);
|
|
167
174
|
}
|
|
168
|
-
Observable.getNotifier(FASTElementDefinition.isRegistered).subscribe({
|
|
169
|
-
handleChange: () => resolve(FASTElementDefinition.isRegistered[name]),
|
|
170
|
-
}, name);
|
|
175
|
+
Observable.getNotifier(FASTElementDefinition.isRegistered).subscribe({ handleChange: () => resolve(FASTElementDefinition.isRegistered[name]) }, name);
|
|
171
176
|
});
|
|
172
177
|
});
|
|
173
178
|
Observable.defineProperty(FASTElementDefinition.prototype, "template");
|
package/dist/esm/index.js
CHANGED
|
@@ -34,6 +34,6 @@ export { elements, NodeObservationDirective, } from "./templating/node-observati
|
|
|
34
34
|
export { render, RenderBehavior, RenderDirective } from "./templating/render.js";
|
|
35
35
|
// Components
|
|
36
36
|
export { customElement, FASTElement } from "./components/fast-element.js";
|
|
37
|
-
export { FASTElementDefinition, fastElementRegistry, } from "./components/fast-definitions.js";
|
|
37
|
+
export { FASTElementDefinition, fastElementRegistry, TemplateOptions, } from "./components/fast-definitions.js";
|
|
38
38
|
export { attr, AttributeConfiguration, AttributeDefinition, booleanConverter, nullableBooleanConverter, nullableNumberConverter, } from "./components/attributes.js";
|
|
39
39
|
export { ElementController, HydratableElementController, } from "./components/element-controller.js";
|
package/dist/esm/polyfills.js
CHANGED
|
@@ -25,3 +25,36 @@
|
|
|
25
25
|
result.globalThis = result;
|
|
26
26
|
}
|
|
27
27
|
})();
|
|
28
|
+
(function requestIdleCallbackPolyfill() {
|
|
29
|
+
if ("requestIdleCallback" in globalThis) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A polyfill for requestIdleCallback that falls back to setTimeout.
|
|
34
|
+
*
|
|
35
|
+
* @param callback - The function to call when the browser is idle.
|
|
36
|
+
* @param options - Options object that may contain a timeout property.
|
|
37
|
+
* @returns An ID that can be used to cancel the callback.
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
globalThis.requestIdleCallback = function requestIdleCallback(callback, options) {
|
|
41
|
+
const start = Date.now();
|
|
42
|
+
return setTimeout(() => {
|
|
43
|
+
callback({
|
|
44
|
+
didTimeout: (options === null || options === void 0 ? void 0 : options.timeout)
|
|
45
|
+
? Date.now() - start >= options.timeout
|
|
46
|
+
: false,
|
|
47
|
+
timeRemaining: () => 0,
|
|
48
|
+
});
|
|
49
|
+
}, 1);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* A polyfill for cancelIdleCallback that falls back to clearTimeout.
|
|
53
|
+
*
|
|
54
|
+
* @param id - The ID of the callback to cancel.
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
globalThis.cancelIdleCallback = function cancelIdleCallback(id) {
|
|
58
|
+
clearTimeout(id);
|
|
59
|
+
};
|
|
60
|
+
})();
|
|
@@ -360,7 +360,7 @@ export class HydrationView extends DefaultExecutionContext {
|
|
|
360
360
|
fragment.appendChild(end);
|
|
361
361
|
}
|
|
362
362
|
bind(source, context = this) {
|
|
363
|
-
var _b
|
|
363
|
+
var _b;
|
|
364
364
|
if (this.hydrationStage !== HydrationStage.hydrated) {
|
|
365
365
|
this._hydrationStage = HydrationStage.hydrating;
|
|
366
366
|
}
|
|
@@ -404,7 +404,28 @@ export class HydrationView extends DefaultExecutionContext {
|
|
|
404
404
|
if (typeof templateString !== "string") {
|
|
405
405
|
templateString = templateString.innerHTML;
|
|
406
406
|
}
|
|
407
|
-
|
|
407
|
+
const hostElement = ((_b = this.firstChild) === null || _b === void 0 ? void 0 : _b.getRootNode())
|
|
408
|
+
.host;
|
|
409
|
+
const hostName = (hostElement === null || hostElement === void 0 ? void 0 : hostElement.nodeName) || "unknown";
|
|
410
|
+
const factoryInfo = factory;
|
|
411
|
+
// Build detailed error message
|
|
412
|
+
const details = [
|
|
413
|
+
`HydrationView was unable to successfully target bindings inside "<${hostName.toLowerCase()}>".`,
|
|
414
|
+
`\nMismatch Details:`,
|
|
415
|
+
` - Expected target node ID: "${factory.targetNodeId}"`,
|
|
416
|
+
` - Available target IDs: [${Object.keys(this.targets).join(", ") || "none"}]`,
|
|
417
|
+
];
|
|
418
|
+
if (factory.targetTagName) {
|
|
419
|
+
details.push(` - Expected tag name: "${factory.targetTagName}"`);
|
|
420
|
+
}
|
|
421
|
+
if (factoryInfo.sourceAspect) {
|
|
422
|
+
details.push(` - Source aspect: "${factoryInfo.sourceAspect}"`);
|
|
423
|
+
}
|
|
424
|
+
if (factoryInfo.aspectType !== undefined) {
|
|
425
|
+
details.push(` - Aspect type: ${factoryInfo.aspectType}`);
|
|
426
|
+
}
|
|
427
|
+
details.push(`\nThis usually means:`, ` 1. The server-rendered HTML doesn't match the client template`, ` 2. The hydration markers are missing or corrupted`, ` 3. The DOM structure was modified before hydration`, `\nTemplate: ${templateString.slice(0, 200)}${templateString.length > 200 ? "..." : ""}`);
|
|
428
|
+
throw new HydrationBindingError(details.join("\n"), factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
|
|
408
429
|
}
|
|
409
430
|
}
|
|
410
431
|
}
|