@microsoft/fast-element 2.8.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 +16 -1
- package/CHANGELOG.md +10 -2
- package/dist/dts/components/element-controller.d.ts +28 -2
- package/dist/esm/components/element-controller.js +82 -19
- package/dist/esm/components/fast-element.js +15 -14
- package/dist/esm/polyfills.js +33 -0
- package/dist/fast-element.api.json +31 -0
- package/dist/fast-element.debug.js +130 -24
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +130 -24
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +28 -2
- package/docs/api-report.api.md +1 -0
- package/package.json +1 -1
package/CHANGELOG.json
CHANGED
|
@@ -2,7 +2,22 @@
|
|
|
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",
|
|
6
21
|
"version": "2.8.0",
|
|
7
22
|
"tag": "@microsoft/fast-element_v2.8.0",
|
|
8
23
|
"comments": {
|
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
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
|
+
|
|
7
15
|
## 2.8.0
|
|
8
16
|
|
|
9
|
-
Mon, 13 Oct 2025 00:
|
|
17
|
+
Mon, 13 Oct 2025 00:37:08 GMT
|
|
10
18
|
|
|
11
19
|
### Minor changes
|
|
12
20
|
|
|
@@ -241,18 +241,44 @@ export declare class HydratableElementController<TElement extends HTMLElement =
|
|
|
241
241
|
/**
|
|
242
242
|
* Lifecycle callbacks for hydration events
|
|
243
243
|
*/
|
|
244
|
-
|
|
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;
|
|
245
253
|
/**
|
|
246
254
|
* Configure lifecycle callbacks for hydration events
|
|
247
255
|
*/
|
|
248
256
|
static config(callbacks: HydrationControllerCallbacks): typeof HydratableElementController;
|
|
249
257
|
private static hydrationObserverHandler;
|
|
250
258
|
/**
|
|
251
|
-
* Checks
|
|
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
|
|
252
264
|
*/
|
|
253
265
|
private static checkHydrationComplete;
|
|
254
266
|
static forCustomElement(element: HTMLElement, override?: boolean): ElementController<HTMLElement>;
|
|
255
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;
|
|
256
282
|
disconnect(): void;
|
|
257
283
|
static install(): void;
|
|
258
284
|
}
|
|
@@ -591,6 +591,21 @@ 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
|
+
}
|
|
594
609
|
/**
|
|
595
610
|
* Configure lifecycle callbacks for hydration events
|
|
596
611
|
*/
|
|
@@ -600,17 +615,30 @@ export class HydratableElementController extends ElementController {
|
|
|
600
615
|
}
|
|
601
616
|
static hydrationObserverHandler(records) {
|
|
602
617
|
for (const record of records) {
|
|
603
|
-
|
|
604
|
-
|
|
618
|
+
if (!record.target.hasAttribute(deferHydrationAttribute)) {
|
|
619
|
+
HydratableElementController.hydrationObserver.unobserve(record.target);
|
|
620
|
+
record.target.$fastController.connect();
|
|
621
|
+
}
|
|
605
622
|
}
|
|
606
623
|
}
|
|
607
624
|
/**
|
|
608
|
-
* Checks
|
|
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
|
|
609
630
|
*/
|
|
610
|
-
static checkHydrationComplete() {
|
|
611
|
-
var _a, _b;
|
|
612
|
-
if (
|
|
613
|
-
|
|
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);
|
|
614
642
|
}
|
|
615
643
|
}
|
|
616
644
|
static forCustomElement(element, override) {
|
|
@@ -623,15 +651,17 @@ export class HydratableElementController extends ElementController {
|
|
|
623
651
|
return super.forCustomElement(element, override);
|
|
624
652
|
}
|
|
625
653
|
connect() {
|
|
626
|
-
var _a, _b, _c, _d, _e
|
|
654
|
+
var _a, _b, _c, _d, _e;
|
|
627
655
|
// Initialize needsHydration on first connect
|
|
628
|
-
|
|
629
|
-
this.needsHydration
|
|
630
|
-
|
|
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);
|
|
631
660
|
}
|
|
632
661
|
// If the `defer-hydration` attribute exists on the source,
|
|
633
662
|
// wait for it to be removed before continuing connection behavior.
|
|
634
663
|
if (this.source.hasAttribute(deferHydrationAttribute)) {
|
|
664
|
+
this.addHydratingInstance();
|
|
635
665
|
HydratableElementController.hydrationObserver.observe(this.source, {
|
|
636
666
|
attributeFilter: [deferHydrationAttribute],
|
|
637
667
|
});
|
|
@@ -643,20 +673,19 @@ export class HydratableElementController extends ElementController {
|
|
|
643
673
|
// class
|
|
644
674
|
if (!this.needsHydration) {
|
|
645
675
|
super.connect();
|
|
676
|
+
this.removeHydratingInstance();
|
|
646
677
|
return;
|
|
647
678
|
}
|
|
648
679
|
if (this.stage !== 3 /* Stages.disconnected */) {
|
|
649
680
|
return;
|
|
650
681
|
}
|
|
651
|
-
// Callback: Before hydration has started
|
|
652
|
-
(_b = (_a = HydratableElementController.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.elementWillHydrate) === null || _b === void 0 ? void 0 : _b.call(_a, this.definition.name);
|
|
653
682
|
this.stage = 0 /* Stages.connecting */;
|
|
654
683
|
this.bindObservables();
|
|
655
684
|
this.connectBehaviors();
|
|
656
|
-
const element = this.source;
|
|
657
|
-
const host = (_c = getShadowRoot(element)) !== null && _c !== void 0 ? _c : element;
|
|
658
685
|
if (this.template) {
|
|
659
686
|
if (isHydratable(this.template)) {
|
|
687
|
+
const element = this.source;
|
|
688
|
+
const host = (_d = getShadowRoot(element)) !== null && _d !== void 0 ? _d : element;
|
|
660
689
|
let firstChild = host.firstChild;
|
|
661
690
|
let lastChild = host.lastChild;
|
|
662
691
|
if (element.shadowRoot === null) {
|
|
@@ -671,7 +700,7 @@ export class HydratableElementController extends ElementController {
|
|
|
671
700
|
}
|
|
672
701
|
}
|
|
673
702
|
this.view = this.template.hydrate(firstChild, lastChild, element);
|
|
674
|
-
(
|
|
703
|
+
(_e = this.view) === null || _e === void 0 ? void 0 : _e.bind(this.source);
|
|
675
704
|
}
|
|
676
705
|
else {
|
|
677
706
|
this.renderTemplate(this.template);
|
|
@@ -681,11 +710,31 @@ export class HydratableElementController extends ElementController {
|
|
|
681
710
|
this.stage = 1 /* Stages.connected */;
|
|
682
711
|
this.source.removeAttribute(needsHydrationAttribute);
|
|
683
712
|
this.needsInitialization = this.needsHydration = false;
|
|
713
|
+
this.removeHydratingInstance();
|
|
684
714
|
Observable.notify(this, isConnectedPropertyName);
|
|
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);
|
|
685
726
|
// Callback: After hydration has finished
|
|
686
|
-
(
|
|
687
|
-
|
|
688
|
-
|
|
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
|
+
}
|
|
689
738
|
}
|
|
690
739
|
disconnect() {
|
|
691
740
|
super.disconnect();
|
|
@@ -696,3 +745,17 @@ export class HydratableElementController extends ElementController {
|
|
|
696
745
|
}
|
|
697
746
|
}
|
|
698
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();
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import { isFunction } from "../interfaces.js";
|
|
11
2
|
import { ElementController } from "./element-controller.js";
|
|
12
3
|
import { FASTElementDefinition, } from "./fast-definitions.js";
|
|
@@ -41,11 +32,21 @@ function compose(type, nameOrDef) {
|
|
|
41
32
|
return FASTElementDefinition.compose(this, type);
|
|
42
33
|
}
|
|
43
34
|
function defineAsync(type, nameOrDef) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
if (isFunction(type)) {
|
|
36
|
+
return new Promise(resolve => {
|
|
37
|
+
FASTElementDefinition.composeAsync(type, nameOrDef).then(value => {
|
|
38
|
+
resolve(value);
|
|
39
|
+
});
|
|
40
|
+
}).then(value => {
|
|
41
|
+
return value.define().type;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return new Promise(resolve => {
|
|
45
|
+
FASTElementDefinition.composeAsync(this, type).then(value => {
|
|
46
|
+
resolve(value);
|
|
47
|
+
});
|
|
48
|
+
}).then(value => {
|
|
49
|
+
return value.define().type;
|
|
49
50
|
});
|
|
50
51
|
}
|
|
51
52
|
function define(type, nameOrDef) {
|
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
|
+
})();
|
|
@@ -12593,6 +12593,37 @@
|
|
|
12593
12593
|
"isAbstract": false,
|
|
12594
12594
|
"name": "install"
|
|
12595
12595
|
},
|
|
12596
|
+
{
|
|
12597
|
+
"kind": "Property",
|
|
12598
|
+
"canonicalReference": "@microsoft/fast-element!HydratableElementController.lifecycleCallbacks:member",
|
|
12599
|
+
"docComment": "/**\n * Lifecycle callbacks for hydration events\n */\n",
|
|
12600
|
+
"excerptTokens": [
|
|
12601
|
+
{
|
|
12602
|
+
"kind": "Content",
|
|
12603
|
+
"text": "static lifecycleCallbacks?: "
|
|
12604
|
+
},
|
|
12605
|
+
{
|
|
12606
|
+
"kind": "Reference",
|
|
12607
|
+
"text": "HydrationControllerCallbacks",
|
|
12608
|
+
"canonicalReference": "@microsoft/fast-element!HydrationControllerCallbacks:interface"
|
|
12609
|
+
},
|
|
12610
|
+
{
|
|
12611
|
+
"kind": "Content",
|
|
12612
|
+
"text": ";"
|
|
12613
|
+
}
|
|
12614
|
+
],
|
|
12615
|
+
"isReadonly": false,
|
|
12616
|
+
"isOptional": true,
|
|
12617
|
+
"releaseTag": "Beta",
|
|
12618
|
+
"name": "lifecycleCallbacks",
|
|
12619
|
+
"propertyTypeTokenRange": {
|
|
12620
|
+
"startIndex": 1,
|
|
12621
|
+
"endIndex": 2
|
|
12622
|
+
},
|
|
12623
|
+
"isStatic": true,
|
|
12624
|
+
"isProtected": false,
|
|
12625
|
+
"isAbstract": false
|
|
12626
|
+
},
|
|
12596
12627
|
{
|
|
12597
12628
|
"kind": "Property",
|
|
12598
12629
|
"canonicalReference": "@microsoft/fast-element!HydratableElementController#needsHydration:member",
|
|
@@ -152,6 +152,39 @@ const noop = () => void 0;
|
|
|
152
152
|
result.globalThis = result;
|
|
153
153
|
}
|
|
154
154
|
})();
|
|
155
|
+
(function requestIdleCallbackPolyfill() {
|
|
156
|
+
if ("requestIdleCallback" in globalThis) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* A polyfill for requestIdleCallback that falls back to setTimeout.
|
|
161
|
+
*
|
|
162
|
+
* @param callback - The function to call when the browser is idle.
|
|
163
|
+
* @param options - Options object that may contain a timeout property.
|
|
164
|
+
* @returns An ID that can be used to cancel the callback.
|
|
165
|
+
* @public
|
|
166
|
+
*/
|
|
167
|
+
globalThis.requestIdleCallback = function requestIdleCallback(callback, options) {
|
|
168
|
+
const start = Date.now();
|
|
169
|
+
return setTimeout(() => {
|
|
170
|
+
callback({
|
|
171
|
+
didTimeout: (options === null || options === void 0 ? void 0 : options.timeout)
|
|
172
|
+
? Date.now() - start >= options.timeout
|
|
173
|
+
: false,
|
|
174
|
+
timeRemaining: () => 0,
|
|
175
|
+
});
|
|
176
|
+
}, 1);
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* A polyfill for cancelIdleCallback that falls back to clearTimeout.
|
|
180
|
+
*
|
|
181
|
+
* @param id - The ID of the callback to cancel.
|
|
182
|
+
* @public
|
|
183
|
+
*/
|
|
184
|
+
globalThis.cancelIdleCallback = function cancelIdleCallback(id) {
|
|
185
|
+
clearTimeout(id);
|
|
186
|
+
};
|
|
187
|
+
})();
|
|
155
188
|
|
|
156
189
|
// ensure FAST global - duplicated debug.ts
|
|
157
190
|
const propConfig = {
|
|
@@ -6023,6 +6056,21 @@ const needsHydrationAttribute = "needs-hydration";
|
|
|
6023
6056
|
* @beta
|
|
6024
6057
|
*/
|
|
6025
6058
|
class HydratableElementController extends ElementController {
|
|
6059
|
+
/**
|
|
6060
|
+
* Adds the current element instance to the hydrating instances map
|
|
6061
|
+
*/
|
|
6062
|
+
addHydratingInstance() {
|
|
6063
|
+
if (!HydratableElementController.hydratingInstances) {
|
|
6064
|
+
return;
|
|
6065
|
+
}
|
|
6066
|
+
const name = this.definition.name;
|
|
6067
|
+
let instances = HydratableElementController.hydratingInstances.get(name);
|
|
6068
|
+
if (!instances) {
|
|
6069
|
+
instances = new Set();
|
|
6070
|
+
HydratableElementController.hydratingInstances.set(name, instances);
|
|
6071
|
+
}
|
|
6072
|
+
instances.add(this.source);
|
|
6073
|
+
}
|
|
6026
6074
|
/**
|
|
6027
6075
|
* Configure lifecycle callbacks for hydration events
|
|
6028
6076
|
*/
|
|
@@ -6032,17 +6080,30 @@ class HydratableElementController extends ElementController {
|
|
|
6032
6080
|
}
|
|
6033
6081
|
static hydrationObserverHandler(records) {
|
|
6034
6082
|
for (const record of records) {
|
|
6035
|
-
|
|
6036
|
-
|
|
6083
|
+
if (!record.target.hasAttribute(deferHydrationAttribute)) {
|
|
6084
|
+
HydratableElementController.hydrationObserver.unobserve(record.target);
|
|
6085
|
+
record.target.$fastController.connect();
|
|
6086
|
+
}
|
|
6037
6087
|
}
|
|
6038
6088
|
}
|
|
6039
6089
|
/**
|
|
6040
|
-
* Checks
|
|
6090
|
+
* Checks to see if hydration is complete and if so, invokes the hydrationComplete callback.
|
|
6091
|
+
* Then resets the ElementController strategy to the default so that future elements
|
|
6092
|
+
* don't use the HydratableElementController.
|
|
6093
|
+
*
|
|
6094
|
+
* @param deadline - the idle deadline object
|
|
6041
6095
|
*/
|
|
6042
|
-
static checkHydrationComplete() {
|
|
6043
|
-
var _a, _b;
|
|
6044
|
-
if (
|
|
6045
|
-
|
|
6096
|
+
static checkHydrationComplete(deadline) {
|
|
6097
|
+
var _a, _b, _c;
|
|
6098
|
+
if (deadline.didTimeout) {
|
|
6099
|
+
HydratableElementController.idleCallbackId = requestIdleCallback(HydratableElementController.checkHydrationComplete, { timeout: 50 });
|
|
6100
|
+
return;
|
|
6101
|
+
}
|
|
6102
|
+
// If there are no more hydrating instances, invoke the hydrationComplete callback
|
|
6103
|
+
if (((_a = HydratableElementController.hydratingInstances) === null || _a === void 0 ? void 0 : _a.size) === 0) {
|
|
6104
|
+
(_c = (_b = HydratableElementController.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.hydrationComplete) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
6105
|
+
// Reset to the default strategy after hydration is complete
|
|
6106
|
+
ElementController.setStrategy(ElementController);
|
|
6046
6107
|
}
|
|
6047
6108
|
}
|
|
6048
6109
|
static forCustomElement(element, override) {
|
|
@@ -6055,15 +6116,17 @@ class HydratableElementController extends ElementController {
|
|
|
6055
6116
|
return super.forCustomElement(element, override);
|
|
6056
6117
|
}
|
|
6057
6118
|
connect() {
|
|
6058
|
-
var _a, _b, _c, _d, _e
|
|
6119
|
+
var _a, _b, _c, _d, _e;
|
|
6059
6120
|
// Initialize needsHydration on first connect
|
|
6060
|
-
|
|
6061
|
-
this.needsHydration
|
|
6062
|
-
|
|
6121
|
+
this.needsHydration =
|
|
6122
|
+
(_a = this.needsHydration) !== null && _a !== void 0 ? _a : this.source.getAttribute(needsHydrationAttribute) !== null;
|
|
6123
|
+
if (this.needsHydration) {
|
|
6124
|
+
(_c = (_b = HydratableElementController.lifecycleCallbacks) === null || _b === void 0 ? void 0 : _b.elementWillHydrate) === null || _c === void 0 ? void 0 : _c.call(_b, this.definition.name);
|
|
6063
6125
|
}
|
|
6064
6126
|
// If the `defer-hydration` attribute exists on the source,
|
|
6065
6127
|
// wait for it to be removed before continuing connection behavior.
|
|
6066
6128
|
if (this.source.hasAttribute(deferHydrationAttribute)) {
|
|
6129
|
+
this.addHydratingInstance();
|
|
6067
6130
|
HydratableElementController.hydrationObserver.observe(this.source, {
|
|
6068
6131
|
attributeFilter: [deferHydrationAttribute],
|
|
6069
6132
|
});
|
|
@@ -6075,20 +6138,19 @@ class HydratableElementController extends ElementController {
|
|
|
6075
6138
|
// class
|
|
6076
6139
|
if (!this.needsHydration) {
|
|
6077
6140
|
super.connect();
|
|
6141
|
+
this.removeHydratingInstance();
|
|
6078
6142
|
return;
|
|
6079
6143
|
}
|
|
6080
6144
|
if (this.stage !== 3 /* Stages.disconnected */) {
|
|
6081
6145
|
return;
|
|
6082
6146
|
}
|
|
6083
|
-
// Callback: Before hydration has started
|
|
6084
|
-
(_b = (_a = HydratableElementController.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.elementWillHydrate) === null || _b === void 0 ? void 0 : _b.call(_a, this.definition.name);
|
|
6085
6147
|
this.stage = 0 /* Stages.connecting */;
|
|
6086
6148
|
this.bindObservables();
|
|
6087
6149
|
this.connectBehaviors();
|
|
6088
|
-
const element = this.source;
|
|
6089
|
-
const host = (_c = getShadowRoot(element)) !== null && _c !== void 0 ? _c : element;
|
|
6090
6150
|
if (this.template) {
|
|
6091
6151
|
if (isHydratable(this.template)) {
|
|
6152
|
+
const element = this.source;
|
|
6153
|
+
const host = (_d = getShadowRoot(element)) !== null && _d !== void 0 ? _d : element;
|
|
6092
6154
|
let firstChild = host.firstChild;
|
|
6093
6155
|
let lastChild = host.lastChild;
|
|
6094
6156
|
if (element.shadowRoot === null) {
|
|
@@ -6103,7 +6165,7 @@ class HydratableElementController extends ElementController {
|
|
|
6103
6165
|
}
|
|
6104
6166
|
}
|
|
6105
6167
|
this.view = this.template.hydrate(firstChild, lastChild, element);
|
|
6106
|
-
(
|
|
6168
|
+
(_e = this.view) === null || _e === void 0 ? void 0 : _e.bind(this.source);
|
|
6107
6169
|
}
|
|
6108
6170
|
else {
|
|
6109
6171
|
this.renderTemplate(this.template);
|
|
@@ -6113,11 +6175,31 @@ class HydratableElementController extends ElementController {
|
|
|
6113
6175
|
this.stage = 1 /* Stages.connected */;
|
|
6114
6176
|
this.source.removeAttribute(needsHydrationAttribute);
|
|
6115
6177
|
this.needsInitialization = this.needsHydration = false;
|
|
6178
|
+
this.removeHydratingInstance();
|
|
6116
6179
|
Observable.notify(this, isConnectedPropertyName);
|
|
6180
|
+
}
|
|
6181
|
+
/**
|
|
6182
|
+
* Removes the current element instance from the hydrating instances map
|
|
6183
|
+
*/
|
|
6184
|
+
removeHydratingInstance() {
|
|
6185
|
+
var _a, _b;
|
|
6186
|
+
if (!HydratableElementController.hydratingInstances) {
|
|
6187
|
+
return;
|
|
6188
|
+
}
|
|
6189
|
+
const name = this.definition.name;
|
|
6190
|
+
const instances = HydratableElementController.hydratingInstances.get(name);
|
|
6117
6191
|
// Callback: After hydration has finished
|
|
6118
|
-
(
|
|
6119
|
-
|
|
6120
|
-
|
|
6192
|
+
(_b = (_a = HydratableElementController.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.elementDidHydrate) === null || _b === void 0 ? void 0 : _b.call(_a, this.definition.name);
|
|
6193
|
+
if (instances) {
|
|
6194
|
+
instances.delete(this.source);
|
|
6195
|
+
if (!instances.size) {
|
|
6196
|
+
HydratableElementController.hydratingInstances.delete(name);
|
|
6197
|
+
}
|
|
6198
|
+
if (HydratableElementController.idleCallbackId) {
|
|
6199
|
+
cancelIdleCallback(HydratableElementController.idleCallbackId);
|
|
6200
|
+
}
|
|
6201
|
+
HydratableElementController.idleCallbackId = requestIdleCallback(HydratableElementController.checkHydrationComplete, { timeout: 50 });
|
|
6202
|
+
}
|
|
6121
6203
|
}
|
|
6122
6204
|
disconnect() {
|
|
6123
6205
|
super.disconnect();
|
|
@@ -6128,6 +6210,20 @@ class HydratableElementController extends ElementController {
|
|
|
6128
6210
|
}
|
|
6129
6211
|
}
|
|
6130
6212
|
HydratableElementController.hydrationObserver = new UnobservableMutationObserver(HydratableElementController.hydrationObserverHandler);
|
|
6213
|
+
/**
|
|
6214
|
+
* An idle callback ID used to track hydration completion
|
|
6215
|
+
*/
|
|
6216
|
+
HydratableElementController.idleCallbackId = null;
|
|
6217
|
+
/**
|
|
6218
|
+
* A map of element instances by the name of the custom element they are
|
|
6219
|
+
* associated with. The key is the custom element name, and the value is the
|
|
6220
|
+
* instances of hydratable elements which currently need to be hydrated.
|
|
6221
|
+
*
|
|
6222
|
+
* When all of the instances in the set have been hydrated, the set is
|
|
6223
|
+
* cleared and removed from the map. If the map is empty, the
|
|
6224
|
+
* hydrationComplete callback is invoked.
|
|
6225
|
+
*/
|
|
6226
|
+
HydratableElementController.hydratingInstances = new Map();
|
|
6131
6227
|
|
|
6132
6228
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
6133
6229
|
function createFASTElement(BaseType) {
|
|
@@ -6160,11 +6256,21 @@ function compose(type, nameOrDef) {
|
|
|
6160
6256
|
return FASTElementDefinition.compose(this, type);
|
|
6161
6257
|
}
|
|
6162
6258
|
function defineAsync(type, nameOrDef) {
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6259
|
+
if (isFunction(type)) {
|
|
6260
|
+
return new Promise(resolve => {
|
|
6261
|
+
FASTElementDefinition.composeAsync(type, nameOrDef).then(value => {
|
|
6262
|
+
resolve(value);
|
|
6263
|
+
});
|
|
6264
|
+
}).then(value => {
|
|
6265
|
+
return value.define().type;
|
|
6266
|
+
});
|
|
6267
|
+
}
|
|
6268
|
+
return new Promise(resolve => {
|
|
6269
|
+
FASTElementDefinition.composeAsync(this, type).then(value => {
|
|
6270
|
+
resolve(value);
|
|
6271
|
+
});
|
|
6272
|
+
}).then(value => {
|
|
6273
|
+
return value.define().type;
|
|
6168
6274
|
});
|
|
6169
6275
|
}
|
|
6170
6276
|
function define(type, nameOrDef) {
|