@microsoft/fast-html 1.0.0-alpha.3 → 1.0.0-alpha.31
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 +255 -18
- package/dist/dts/components/element.d.ts +10 -0
- package/dist/dts/components/index.d.ts +3 -1
- package/dist/dts/components/observer-map.d.ts +26 -0
- package/dist/dts/components/schema.d.ts +144 -0
- package/dist/dts/components/template.d.ts +83 -7
- package/dist/dts/components/utilities.d.ts +109 -18
- package/dist/dts/fixtures/lifecycle-callbacks/lifecycle-callbacks.spec.d.ts +1 -0
- package/dist/dts/fixtures/lifecycle-callbacks/main.d.ts +5 -0
- package/dist/dts/fixtures/observer-map/main.d.ts +1 -0
- package/dist/dts/fixtures/observer-map/observer-map.spec.d.ts +1 -0
- package/dist/dts/index.d.ts +1 -1
- package/dist/esm/components/element.js +28 -0
- package/dist/esm/components/index.js +3 -1
- package/dist/esm/components/observer-map.js +53 -0
- package/dist/esm/components/observer-map.spec.js +19 -0
- package/dist/esm/components/schema.js +250 -0
- package/dist/esm/components/schema.spec.js +485 -0
- package/dist/esm/components/template.js +199 -111
- package/dist/esm/components/utilities.js +741 -43
- package/dist/esm/components/utilities.spec.js +317 -44
- package/dist/esm/fixtures/attribute/main.js +3 -2
- package/dist/esm/fixtures/binding/binding.spec.js +6 -0
- package/dist/esm/fixtures/binding/main.js +13 -2
- package/dist/esm/fixtures/children/children.spec.js +4 -0
- package/dist/esm/fixtures/children/main.js +3 -2
- package/dist/esm/fixtures/dot-syntax/dot-syntax.spec.js +109 -2
- package/dist/esm/fixtures/dot-syntax/main.js +30 -4
- package/dist/esm/fixtures/event/event.spec.js +28 -5
- package/dist/esm/fixtures/event/main.js +21 -5
- package/dist/esm/fixtures/lifecycle-callbacks/lifecycle-callbacks.spec.js +166 -0
- package/dist/esm/fixtures/lifecycle-callbacks/main.js +126 -0
- package/dist/esm/fixtures/observer-map/main.js +375 -0
- package/dist/esm/fixtures/observer-map/observer-map.spec.js +251 -0
- package/dist/esm/fixtures/ref/main.js +3 -2
- package/dist/esm/fixtures/ref/ref.spec.js +2 -6
- package/dist/esm/fixtures/repeat/main.js +27 -2
- package/dist/esm/fixtures/repeat/repeat.spec.js +16 -6
- package/dist/esm/fixtures/slotted/main.js +15 -4
- package/dist/esm/fixtures/slotted/slotted.spec.js +18 -19
- package/dist/esm/fixtures/when/main.js +139 -2
- package/dist/esm/fixtures/when/when.spec.js +64 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/fast-html.api.json +333 -0
- package/dist/fast-html.d.ts +282 -6
- package/dist/fast-html.untrimmed.d.ts +282 -6
- package/package.json +12 -7
- package/rules/attribute-directives.yml +38 -0
- package/rules/call-expression-with-event-argument.yml +41 -0
- package/rules/member-expression.yml +33 -0
- package/rules/tag-function-to-template-literal.yml +16 -0
- package/dist/esm/fixtures/partial/main.js +0 -31
- package/dist/esm/fixtures/partial/partial.spec.js +0 -14
- /package/dist/dts/{fixtures/partial/main.d.ts → components/observer-map.spec.d.ts} +0 -0
- /package/dist/dts/{fixtures/partial/partial.spec.d.ts → components/schema.spec.d.ts} +0 -0
|
@@ -1,16 +1,42 @@
|
|
|
1
|
-
import { TemplateElement } from "@microsoft/fast-html";
|
|
2
1
|
import { FASTElement } from "@microsoft/fast-element";
|
|
2
|
+
import { RenderableFASTElement, TemplateElement } from "@microsoft/fast-html";
|
|
3
3
|
class TestElement extends FASTElement {
|
|
4
4
|
constructor() {
|
|
5
5
|
super(...arguments);
|
|
6
6
|
this.object = {
|
|
7
|
-
|
|
7
|
+
b: "bar",
|
|
8
|
+
a: {
|
|
9
|
+
b2: {
|
|
10
|
+
c: "FOO",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
this.handleBClick = () => {
|
|
15
|
+
this.object.b = "Hello";
|
|
16
|
+
};
|
|
17
|
+
this.handleAB1Click = () => {
|
|
18
|
+
if (this.object.a) {
|
|
19
|
+
this.object.a.b1 = "World";
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
this.object.a = {
|
|
23
|
+
b1: "World",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
this.handleAB2CClick = () => {
|
|
28
|
+
this.object.a.b2.c = "Pluto";
|
|
8
29
|
};
|
|
9
30
|
}
|
|
10
31
|
}
|
|
11
|
-
TestElement.
|
|
32
|
+
RenderableFASTElement(TestElement).defineAsync({
|
|
12
33
|
name: "test-element",
|
|
34
|
+
templateOptions: "defer-and-hydrate",
|
|
13
35
|
});
|
|
14
|
-
TemplateElement.
|
|
36
|
+
TemplateElement.options({
|
|
37
|
+
"test-element": {
|
|
38
|
+
observerMap: "all",
|
|
39
|
+
},
|
|
40
|
+
}).define({
|
|
15
41
|
name: "f-template",
|
|
16
42
|
});
|
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { expect, test } from "@playwright/test";
|
|
3
3
|
test.describe("f-template", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
-
test("create an event attribute", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("create an event attribute without arguments", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
5
|
yield page.goto("/event");
|
|
6
6
|
const customElement = yield page.locator("test-element");
|
|
7
|
-
let
|
|
8
|
-
yield page.on("console", msg =>
|
|
9
|
-
yield customElement.locator("button").click();
|
|
10
|
-
expect(
|
|
7
|
+
let message;
|
|
8
|
+
yield page.on("console", msg => message = msg.text());
|
|
9
|
+
yield customElement.locator("button").nth(0).click();
|
|
10
|
+
expect(message).toEqual("no args");
|
|
11
|
+
}));
|
|
12
|
+
test("create an event attribute with an event argument", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13
|
+
yield page.goto("/event");
|
|
14
|
+
const customElement = yield page.locator("test-element");
|
|
15
|
+
let message;
|
|
16
|
+
yield page.on("console", msg => message = msg.text());
|
|
17
|
+
yield customElement.locator("button").nth(1).click();
|
|
18
|
+
expect(message).toEqual("click");
|
|
19
|
+
}));
|
|
20
|
+
test("create an event attribute with an attribute argument", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
|
+
yield page.goto("/event");
|
|
22
|
+
const customElement = yield page.locator("test-element");
|
|
23
|
+
let message;
|
|
24
|
+
yield page.on("console", msg => message = msg.text());
|
|
25
|
+
yield customElement.locator("button").nth(2).click();
|
|
26
|
+
expect(message).toEqual("bar");
|
|
27
|
+
}));
|
|
28
|
+
test("should properly bind events with `this`", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
+
yield page.goto("/event");
|
|
30
|
+
const customElement = yield page.locator("test-element");
|
|
31
|
+
yield expect(customElement).toHaveJSProperty("foo", "bar");
|
|
32
|
+
yield customElement.locator("button").nth(3).click();
|
|
33
|
+
yield expect(customElement).toHaveJSProperty("foo", "modified-by-click");
|
|
11
34
|
}));
|
|
12
35
|
}));
|
|
@@ -1,15 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { __decorate, __metadata } from "tslib";
|
|
2
|
+
import { RenderableFASTElement, TemplateElement } from "@microsoft/fast-html";
|
|
3
|
+
import { attr, FASTElement } from "@microsoft/fast-element";
|
|
3
4
|
class TestElement extends FASTElement {
|
|
4
5
|
constructor() {
|
|
5
6
|
super(...arguments);
|
|
6
|
-
this.
|
|
7
|
-
|
|
7
|
+
this.foo = "";
|
|
8
|
+
this.handleNoArgsClick = () => {
|
|
9
|
+
console.log("no args");
|
|
10
|
+
};
|
|
11
|
+
this.handleEventArgClick = (e) => {
|
|
12
|
+
console.log(e.type);
|
|
13
|
+
};
|
|
14
|
+
this.handleAttributeArgClick = (foo) => {
|
|
15
|
+
console.log(foo);
|
|
16
|
+
};
|
|
17
|
+
this.handleModifyAttributeClick = () => {
|
|
18
|
+
this.foo = "modified-by-click";
|
|
8
19
|
};
|
|
9
20
|
}
|
|
10
21
|
}
|
|
11
|
-
|
|
22
|
+
__decorate([
|
|
23
|
+
attr,
|
|
24
|
+
__metadata("design:type", String)
|
|
25
|
+
], TestElement.prototype, "foo", void 0);
|
|
26
|
+
RenderableFASTElement(TestElement).defineAsync({
|
|
12
27
|
name: "test-element",
|
|
28
|
+
templateOptions: "defer-and-hydrate",
|
|
13
29
|
});
|
|
14
30
|
TemplateElement.define({
|
|
15
31
|
name: "f-template",
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { expect, test } from "@playwright/test";
|
|
3
|
+
test.describe("Lifecycle Callbacks", () => __awaiter(void 0, void 0, void 0, function* () {
|
|
4
|
+
test("should invoke all lifecycle callbacks in correct order for simple element", ({ page, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
5
|
+
yield page.goto("/lifecycle-callbacks");
|
|
6
|
+
// Wait for hydration to complete
|
|
7
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
8
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
9
|
+
// Verify callbacks for simple-element were called
|
|
10
|
+
const simpleElementEvents = events.filter((e) => e.name === "simple-element");
|
|
11
|
+
expect(simpleElementEvents.length).toBeGreaterThan(0);
|
|
12
|
+
// Check that callbacks were called in the correct order
|
|
13
|
+
const callbackOrder = simpleElementEvents.map((e) => e.callback);
|
|
14
|
+
expect(callbackOrder).toContain("elementDidRegister");
|
|
15
|
+
expect(callbackOrder).toContain("templateWillUpdate");
|
|
16
|
+
expect(callbackOrder).toContain("templateDidUpdate");
|
|
17
|
+
expect(callbackOrder).toContain("elementDidDefine");
|
|
18
|
+
expect(callbackOrder).toContain("elementWillHydrate");
|
|
19
|
+
expect(callbackOrder).toContain("elementDidHydrate");
|
|
20
|
+
// Verify the order is correct
|
|
21
|
+
const registerIndex = callbackOrder.indexOf("elementDidRegister");
|
|
22
|
+
const willUpdateIndex = callbackOrder.indexOf("templateWillUpdate");
|
|
23
|
+
const didUpdateIndex = callbackOrder.indexOf("templateDidUpdate");
|
|
24
|
+
const defineIndex = callbackOrder.indexOf("elementDidDefine");
|
|
25
|
+
const willHydrateIndex = callbackOrder.indexOf("elementWillHydrate");
|
|
26
|
+
const didHydrateIndex = callbackOrder.indexOf("elementDidHydrate");
|
|
27
|
+
expect(registerIndex).toBeLessThan(willUpdateIndex);
|
|
28
|
+
expect(willUpdateIndex).toBeLessThan(didUpdateIndex);
|
|
29
|
+
expect(didUpdateIndex).toBeLessThan(defineIndex);
|
|
30
|
+
expect(willHydrateIndex).toBeGreaterThan(-1);
|
|
31
|
+
expect(didHydrateIndex).toBeGreaterThan(willHydrateIndex);
|
|
32
|
+
}));
|
|
33
|
+
test("should invoke callbacks for multiple elements", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
+
yield page.goto("/lifecycle-callbacks");
|
|
35
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
36
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
37
|
+
// Check that callbacks were invoked for all elements
|
|
38
|
+
const elementNames = new Set(events.map((e) => e.name));
|
|
39
|
+
expect(elementNames.has("simple-element")).toBe(true);
|
|
40
|
+
expect(elementNames.has("complex-element")).toBe(true);
|
|
41
|
+
expect(elementNames.has("nested-element")).toBe(true);
|
|
42
|
+
}));
|
|
43
|
+
test("should invoke elementWillHydrate before hydration", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
yield page.goto("/lifecycle-callbacks");
|
|
45
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
46
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
47
|
+
const willHydrateEvents = events.filter((e) => e.callback === "elementWillHydrate");
|
|
48
|
+
const didHydrateEvents = events.filter((e) => e.callback === "elementDidHydrate");
|
|
49
|
+
// Every elementWillHydrate should be followed by elementDidHydrate for the same element
|
|
50
|
+
willHydrateEvents.forEach((willEvent) => {
|
|
51
|
+
const correspondingDidEvent = didHydrateEvents.find((e) => e.name === willEvent.name);
|
|
52
|
+
expect(correspondingDidEvent).toBeDefined();
|
|
53
|
+
});
|
|
54
|
+
}));
|
|
55
|
+
test("should invoke hydrationComplete callback after all elements hydrate", ({ page, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
|
+
yield page.goto("/lifecycle-callbacks");
|
|
57
|
+
const hydrationComplete = yield page.waitForFunction(() => window.getHydrationCompleteStatus(), { timeout: 5000 });
|
|
58
|
+
expect(hydrationComplete).toBeTruthy();
|
|
59
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
60
|
+
// Verify hydrationComplete callback was invoked
|
|
61
|
+
const hydrationCompleteEvents = events.filter((e) => e.callback === "hydrationComplete");
|
|
62
|
+
expect(hydrationCompleteEvents.length).toBe(1);
|
|
63
|
+
// Verify all elements are hydrated
|
|
64
|
+
const simpleElement = yield page.locator("simple-element");
|
|
65
|
+
const complexElement = yield page.locator("complex-element");
|
|
66
|
+
const nestedElement = yield page.locator("nested-element");
|
|
67
|
+
yield expect(simpleElement).not.toHaveAttribute("needs-hydration");
|
|
68
|
+
yield expect(complexElement).not.toHaveAttribute("needs-hydration");
|
|
69
|
+
yield expect(nestedElement).not.toHaveAttribute("needs-hydration");
|
|
70
|
+
// Verify hydrationComplete was called AFTER all individual element hydrations
|
|
71
|
+
const lastElementDidHydrateIndex = events.reduce((maxIndex, e, index) => {
|
|
72
|
+
return e.callback === "elementDidHydrate" ? index : maxIndex;
|
|
73
|
+
}, -1);
|
|
74
|
+
const hydrationCompleteIndex = events.findIndex((e) => e.callback === "hydrationComplete");
|
|
75
|
+
expect(hydrationCompleteIndex).toBeGreaterThan(lastElementDidHydrateIndex);
|
|
76
|
+
}));
|
|
77
|
+
test("should handle complex element with observer map", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
78
|
+
yield page.goto("/lifecycle-callbacks");
|
|
79
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
80
|
+
const complexElement = yield page.locator("complex-element");
|
|
81
|
+
// Verify the element has hydrated correctly
|
|
82
|
+
yield expect(complexElement).toHaveText(/Complex/);
|
|
83
|
+
yield expect(complexElement).not.toHaveAttribute("needs-hydration");
|
|
84
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
85
|
+
const complexEvents = events.filter((e) => e.name === "complex-element");
|
|
86
|
+
// Complex element should have all lifecycle callbacks
|
|
87
|
+
expect(complexEvents.length).toBeGreaterThan(0);
|
|
88
|
+
expect(complexEvents.some((e) => e.callback === "elementDidHydrate")).toBe(true);
|
|
89
|
+
}));
|
|
90
|
+
test("should handle nested elements correctly", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
91
|
+
yield page.goto("/lifecycle-callbacks");
|
|
92
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
93
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
94
|
+
// Both parent complex-element and nested nested-element should have callbacks
|
|
95
|
+
const complexEvents = events.filter((e) => e.name === "complex-element");
|
|
96
|
+
const nestedEvents = events.filter((e) => e.name === "nested-element");
|
|
97
|
+
expect(complexEvents.length).toBeGreaterThan(0);
|
|
98
|
+
expect(nestedEvents.length).toBeGreaterThan(0);
|
|
99
|
+
// Both should have hydrated
|
|
100
|
+
expect(complexEvents.some((e) => e.callback === "elementDidHydrate")).toBe(true);
|
|
101
|
+
expect(nestedEvents.some((e) => e.callback === "elementDidHydrate")).toBe(true);
|
|
102
|
+
}));
|
|
103
|
+
test("should handle deferred hydration element", ({ page }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
104
|
+
yield page.goto("/lifecycle-callbacks");
|
|
105
|
+
// The deferred element has a prepare() method that delays hydration
|
|
106
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus(), {
|
|
107
|
+
timeout: 5000,
|
|
108
|
+
});
|
|
109
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
110
|
+
const deferredEvents = events.filter((e) => e.name === "deferred-element");
|
|
111
|
+
// Should have hydration callbacks
|
|
112
|
+
expect(deferredEvents.some((e) => e.callback === "elementWillHydrate")).toBe(true);
|
|
113
|
+
expect(deferredEvents.some((e) => e.callback === "elementDidHydrate")).toBe(true);
|
|
114
|
+
const deferredElement = yield page.locator("deferred-element");
|
|
115
|
+
yield expect(deferredElement).not.toHaveAttribute("needs-hydration");
|
|
116
|
+
yield expect(deferredElement).not.toHaveAttribute("defer-hydration");
|
|
117
|
+
}));
|
|
118
|
+
test("should verify template and hydration callbacks are invoked", ({ page, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
119
|
+
yield page.goto("/lifecycle-callbacks");
|
|
120
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
121
|
+
const events = yield page.evaluate(() => window.lifecycleEvents);
|
|
122
|
+
// For each element, verify both template and hydration callbacks are invoked
|
|
123
|
+
// Note: These callbacks can be interleaved as template processing is async
|
|
124
|
+
const elementNames = ["simple-element", "complex-element", "nested-element"];
|
|
125
|
+
elementNames.forEach(name => {
|
|
126
|
+
const elementEvents = events.filter((e) => e.name === name);
|
|
127
|
+
const callbacks = elementEvents.map((e) => e.callback);
|
|
128
|
+
// Verify all expected callbacks were invoked
|
|
129
|
+
expect(callbacks).toContain("elementDidRegister");
|
|
130
|
+
expect(callbacks).toContain("templateWillUpdate");
|
|
131
|
+
expect(callbacks).toContain("templateDidUpdate");
|
|
132
|
+
expect(callbacks).toContain("elementDidDefine");
|
|
133
|
+
expect(callbacks).toContain("elementWillHydrate");
|
|
134
|
+
expect(callbacks).toContain("elementDidHydrate");
|
|
135
|
+
// Verify hydration callbacks are in order
|
|
136
|
+
const willHydrateIndex = callbacks.indexOf("elementWillHydrate");
|
|
137
|
+
const didHydrateIndex = callbacks.indexOf("elementDidHydrate");
|
|
138
|
+
expect(willHydrateIndex).toBeLessThan(didHydrateIndex);
|
|
139
|
+
// Verify template callbacks are in order
|
|
140
|
+
const registerIndex = callbacks.indexOf("elementDidRegister");
|
|
141
|
+
const willUpdateIndex = callbacks.indexOf("templateWillUpdate");
|
|
142
|
+
const didUpdateIndex = callbacks.indexOf("templateDidUpdate");
|
|
143
|
+
const defineIndex = callbacks.indexOf("elementDidDefine");
|
|
144
|
+
expect(registerIndex).toBeLessThan(willUpdateIndex);
|
|
145
|
+
expect(willUpdateIndex).toBeLessThan(didUpdateIndex);
|
|
146
|
+
expect(didUpdateIndex).toBeLessThan(defineIndex);
|
|
147
|
+
});
|
|
148
|
+
}));
|
|
149
|
+
test("should properly hydrate elements and maintain functionality", ({ page, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
150
|
+
yield page.goto("/lifecycle-callbacks");
|
|
151
|
+
yield page.waitForFunction(() => window.getHydrationCompleteStatus());
|
|
152
|
+
const simpleElement = yield page.locator("simple-element");
|
|
153
|
+
const complexElement = yield page.locator("complex-element");
|
|
154
|
+
// Verify simple element displays correctly
|
|
155
|
+
yield expect(simpleElement).toHaveText("Hello World");
|
|
156
|
+
// Verify complex element displays correctly
|
|
157
|
+
yield expect(complexElement).toHaveText(/Complex/);
|
|
158
|
+
// Verify elements are interactive after hydration
|
|
159
|
+
const currentCount = yield complexElement.evaluate((el) => el.count);
|
|
160
|
+
expect(currentCount).toBe(0);
|
|
161
|
+
// Interact with the element
|
|
162
|
+
yield complexElement.evaluate((el) => el.increment());
|
|
163
|
+
const newCount = yield complexElement.evaluate((el) => el.count);
|
|
164
|
+
expect(newCount).toBe(1);
|
|
165
|
+
}));
|
|
166
|
+
}));
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { __awaiter, __decorate, __metadata } from "tslib";
|
|
2
|
+
import { RenderableFASTElement, TemplateElement } from "@microsoft/fast-html";
|
|
3
|
+
import { attr, FASTElement, observable } from "@microsoft/fast-element";
|
|
4
|
+
// Track lifecycle callbacks for testing
|
|
5
|
+
export const lifecycleEvents = [];
|
|
6
|
+
// Track hydration complete
|
|
7
|
+
export let hydrationCompleteEmitted = false;
|
|
8
|
+
// Configure lifecycle callbacks
|
|
9
|
+
TemplateElement.config({
|
|
10
|
+
elementDidRegister(name) {
|
|
11
|
+
lifecycleEvents.push({ callback: "elementDidRegister", name });
|
|
12
|
+
},
|
|
13
|
+
templateWillUpdate(name) {
|
|
14
|
+
lifecycleEvents.push({ callback: "templateWillUpdate", name });
|
|
15
|
+
},
|
|
16
|
+
templateDidUpdate(name) {
|
|
17
|
+
lifecycleEvents.push({ callback: "templateDidUpdate", name });
|
|
18
|
+
},
|
|
19
|
+
elementDidDefine(name) {
|
|
20
|
+
lifecycleEvents.push({ callback: "elementDidDefine", name });
|
|
21
|
+
},
|
|
22
|
+
elementWillHydrate(name) {
|
|
23
|
+
lifecycleEvents.push({ callback: "elementWillHydrate", name });
|
|
24
|
+
},
|
|
25
|
+
elementDidHydrate(name) {
|
|
26
|
+
lifecycleEvents.push({ callback: "elementDidHydrate", name });
|
|
27
|
+
},
|
|
28
|
+
hydrationComplete() {
|
|
29
|
+
lifecycleEvents.push({ callback: "hydrationComplete" });
|
|
30
|
+
hydrationCompleteEmitted = true;
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
// Simple element with basic property
|
|
34
|
+
class SimpleElement extends FASTElement {
|
|
35
|
+
constructor() {
|
|
36
|
+
super(...arguments);
|
|
37
|
+
this.message = "Hello";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
__decorate([
|
|
41
|
+
attr,
|
|
42
|
+
__metadata("design:type", String)
|
|
43
|
+
], SimpleElement.prototype, "message", void 0);
|
|
44
|
+
RenderableFASTElement(SimpleElement).defineAsync({
|
|
45
|
+
name: "simple-element",
|
|
46
|
+
templateOptions: "defer-and-hydrate",
|
|
47
|
+
});
|
|
48
|
+
// Complex element with multiple properties and methods
|
|
49
|
+
class ComplexElement extends FASTElement {
|
|
50
|
+
constructor() {
|
|
51
|
+
super(...arguments);
|
|
52
|
+
this.title = "Complex";
|
|
53
|
+
this.count = 0;
|
|
54
|
+
this.items = [];
|
|
55
|
+
}
|
|
56
|
+
increment() {
|
|
57
|
+
this.count++;
|
|
58
|
+
}
|
|
59
|
+
addItem(item) {
|
|
60
|
+
this.items = [...this.items, item];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
__decorate([
|
|
64
|
+
attr,
|
|
65
|
+
__metadata("design:type", String)
|
|
66
|
+
], ComplexElement.prototype, "title", void 0);
|
|
67
|
+
__decorate([
|
|
68
|
+
observable,
|
|
69
|
+
__metadata("design:type", Number)
|
|
70
|
+
], ComplexElement.prototype, "count", void 0);
|
|
71
|
+
__decorate([
|
|
72
|
+
observable,
|
|
73
|
+
__metadata("design:type", Array)
|
|
74
|
+
], ComplexElement.prototype, "items", void 0);
|
|
75
|
+
RenderableFASTElement(ComplexElement).defineAsync({
|
|
76
|
+
name: "complex-element",
|
|
77
|
+
templateOptions: "defer-and-hydrate",
|
|
78
|
+
});
|
|
79
|
+
// Nested element
|
|
80
|
+
class NestedElement extends FASTElement {
|
|
81
|
+
constructor() {
|
|
82
|
+
super(...arguments);
|
|
83
|
+
this.label = "Nested";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
__decorate([
|
|
87
|
+
attr,
|
|
88
|
+
__metadata("design:type", String)
|
|
89
|
+
], NestedElement.prototype, "label", void 0);
|
|
90
|
+
RenderableFASTElement(NestedElement).defineAsync({
|
|
91
|
+
name: "nested-element",
|
|
92
|
+
templateOptions: "defer-and-hydrate",
|
|
93
|
+
});
|
|
94
|
+
// Element with deferred hydration
|
|
95
|
+
class DeferredElement extends FASTElement {
|
|
96
|
+
constructor() {
|
|
97
|
+
super(...arguments);
|
|
98
|
+
this.status = "pending";
|
|
99
|
+
}
|
|
100
|
+
prepare() {
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
// Simulate async work
|
|
103
|
+
yield new Promise(resolve => setTimeout(resolve, 100));
|
|
104
|
+
this.status = "ready";
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
__decorate([
|
|
109
|
+
attr,
|
|
110
|
+
__metadata("design:type", String)
|
|
111
|
+
], DeferredElement.prototype, "status", void 0);
|
|
112
|
+
RenderableFASTElement(DeferredElement).defineAsync({
|
|
113
|
+
name: "deferred-element",
|
|
114
|
+
templateOptions: "defer-and-hydrate",
|
|
115
|
+
});
|
|
116
|
+
// Define templates
|
|
117
|
+
TemplateElement.options({
|
|
118
|
+
"complex-element": {
|
|
119
|
+
observerMap: "all",
|
|
120
|
+
},
|
|
121
|
+
}).define({
|
|
122
|
+
name: "f-template",
|
|
123
|
+
});
|
|
124
|
+
// Make lifecycleEvents available globally for testing
|
|
125
|
+
window.lifecycleEvents = lifecycleEvents;
|
|
126
|
+
window.getHydrationCompleteStatus = () => hydrationCompleteEmitted;
|