@microsoft/fast-element 2.0.0-beta.8 → 2.0.0
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/.eslintrc.json +1 -1
- package/CHANGELOG.json +512 -0
- package/CHANGELOG.md +180 -1
- package/README.md +1 -9
- package/api-extractor.context.json +14 -0
- package/api-extractor.di.json +14 -0
- package/dist/context/context.api.json +1068 -0
- package/dist/di/di.api.json +4929 -0
- package/dist/dts/binding/binding.d.ts +49 -0
- package/dist/dts/binding/normalize.d.ts +9 -0
- package/dist/dts/binding/one-time.d.ts +11 -0
- package/dist/dts/binding/one-way.d.ts +20 -0
- package/dist/dts/{templating/binding-signal.d.ts → binding/signal.d.ts} +19 -4
- package/dist/dts/{templating/binding-two-way.d.ts → binding/two-way.d.ts} +9 -5
- package/dist/dts/components/attributes.d.ts +6 -0
- package/dist/dts/components/element-controller.d.ts +104 -8
- package/dist/dts/components/element-hydration.d.ts +2 -0
- package/dist/dts/components/fast-definitions.d.ts +6 -0
- package/dist/dts/components/hydration.d.ts +56 -0
- package/dist/dts/components/install-hydration.d.ts +1 -0
- package/dist/dts/context.d.ts +29 -15
- package/dist/dts/di/di.d.ts +0 -5
- package/dist/dts/dom-policy.d.ts +83 -0
- package/dist/dts/dom.d.ts +100 -0
- package/dist/dts/hydration/target-builder.d.ts +63 -0
- package/dist/dts/index.d.ts +33 -26
- package/dist/dts/index.rollup.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +32 -82
- package/dist/dts/metadata.d.ts +6 -5
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/observable.bench.d.ts +18 -0
- package/dist/dts/observation/observable.d.ts +5 -5
- package/dist/dts/pending-task.d.ts +19 -7
- package/dist/dts/platform.d.ts +11 -2
- package/dist/dts/polyfills.d.ts +0 -8
- package/dist/dts/styles/css-binding-directive.d.ts +60 -0
- package/dist/dts/styles/css.d.ts +9 -7
- package/dist/dts/styles/element-styles.d.ts +1 -14
- package/dist/dts/styles/host.d.ts +2 -5
- package/dist/dts/styles/style-strategy.d.ts +42 -0
- package/dist/dts/templating/compiler.d.ts +11 -13
- package/dist/dts/templating/{binding.d.ts → html-binding-directive.d.ts} +22 -42
- package/dist/dts/templating/html-directive.d.ts +44 -140
- package/dist/dts/templating/install-hydratable-view-templates.d.ts +1 -0
- package/dist/dts/templating/node-observation.d.ts +11 -1
- package/dist/dts/templating/ref.d.ts +4 -0
- package/dist/dts/templating/render.bench.d.ts +3 -0
- package/dist/dts/templating/render.d.ts +49 -9
- package/dist/dts/templating/repeat-basic-reverse.bench.d.ts +3 -0
- package/dist/dts/templating/repeat-basic-shift.bench.d.ts +3 -0
- package/dist/dts/templating/repeat.d.ts +31 -9
- package/dist/dts/templating/template.d.ts +97 -12
- package/dist/dts/templating/view.d.ts +149 -26
- package/dist/dts/templating/when-basic.bench.d.ts +3 -0
- package/dist/dts/templating/when-conditional.bench.d.ts +3 -0
- package/dist/dts/templating/when-switch.bench.d.ts +3 -0
- package/dist/dts/templating/when.d.ts +3 -1
- package/dist/dts/testing/fakes.d.ts +12 -1
- package/dist/dts/tsdoc-metadata.json +1 -1
- package/dist/dts/utilities.d.ts +55 -1
- package/dist/esm/binding/binding.js +18 -0
- package/dist/esm/binding/normalize.js +17 -0
- package/dist/esm/binding/one-time.js +21 -0
- package/dist/esm/binding/one-way.js +30 -0
- package/dist/esm/{templating/binding-signal.js → binding/signal.js} +22 -6
- package/dist/esm/{templating/binding-two-way.js → binding/two-way.js} +18 -12
- package/dist/esm/components/attributes.js +16 -1
- package/dist/esm/components/element-controller.js +319 -49
- package/dist/esm/components/element-hydration.js +2 -0
- package/dist/esm/components/fast-definitions.js +12 -4
- package/dist/esm/components/fast-element.js +3 -1
- package/dist/esm/components/hydration.js +104 -0
- package/dist/esm/components/install-hydration.js +3 -0
- package/dist/esm/context.js +26 -4
- package/dist/esm/debug.js +8 -2
- package/dist/esm/di/di.js +9 -12
- package/dist/esm/dom-policy.js +345 -0
- package/dist/esm/dom.js +101 -0
- package/dist/esm/hydration/target-builder.js +175 -0
- package/dist/esm/index.js +34 -25
- package/dist/esm/index.rollup.debug.js +3 -1
- package/dist/esm/index.rollup.js +3 -1
- package/dist/esm/interfaces.js +51 -3
- package/dist/esm/metadata.js +11 -8
- package/dist/esm/observation/arrays.js +1 -1
- package/dist/esm/observation/observable.bench.js +79 -0
- package/dist/esm/observation/observable.js +20 -15
- package/dist/esm/observation/update-queue.js +2 -2
- package/dist/esm/pending-task.js +13 -1
- package/dist/esm/platform.js +12 -2
- package/dist/esm/polyfills.js +3 -61
- package/dist/esm/styles/css-binding-directive.js +76 -0
- package/dist/esm/styles/css.js +14 -7
- package/dist/esm/styles/element-styles.js +0 -33
- package/dist/esm/styles/style-strategy.js +1 -0
- package/dist/esm/templating/children.js +8 -4
- package/dist/esm/templating/compiler.js +37 -44
- package/dist/esm/templating/html-binding-directive.js +218 -0
- package/dist/esm/templating/html-directive.js +25 -152
- package/dist/esm/templating/install-hydratable-view-templates.js +17 -0
- package/dist/esm/templating/node-observation.js +14 -8
- package/dist/esm/templating/ref.js +1 -1
- package/dist/esm/templating/render.bench.js +56 -0
- package/dist/esm/templating/render.js +74 -30
- package/dist/esm/templating/repeat-basic-reverse.bench.js +43 -0
- package/dist/esm/templating/repeat-basic-shift.bench.js +43 -0
- package/dist/esm/templating/repeat.js +116 -17
- package/dist/esm/templating/template.js +135 -60
- package/dist/esm/templating/view.js +259 -32
- package/dist/esm/templating/when-basic.bench.js +36 -0
- package/dist/esm/templating/when-conditional.bench.js +39 -0
- package/dist/esm/templating/when-switch.bench.js +68 -0
- package/dist/esm/templating/when.js +12 -5
- package/dist/esm/testing/fakes.js +32 -1
- package/dist/esm/testing/fixture.js +1 -1
- package/dist/esm/utilities.js +97 -1
- package/dist/fast-element.api.json +9804 -5622
- package/dist/fast-element.d.ts +813 -2386
- package/dist/fast-element.debug.js +2797 -974
- package/dist/fast-element.debug.min.js +3 -1
- package/dist/fast-element.js +2642 -825
- package/dist/fast-element.min.js +3 -1
- package/dist/fast-element.untrimmed.d.ts +669 -315
- package/docs/{api-report.md → api-report.api.md} +243 -158
- package/docs/context/api-report.api.md +69 -0
- package/docs/di/api-report.api.md +315 -0
- package/karma.conf.cjs +2 -1
- package/package.json +59 -47
- package/scripts/run-api-extractor.js +51 -0
- package/scripts/run-benchmarks.js +46 -0
- package/tensile.config.js +12 -0
- package/dist/dts/templating/dom.d.ts +0 -41
- package/dist/esm/templating/binding.js +0 -282
- package/dist/esm/templating/dom.js +0 -49
- package/docs/guide/declaring-templates.md +0 -230
- package/docs/guide/defining-elements.md +0 -214
- package/docs/guide/leveraging-css.md +0 -253
- package/docs/guide/next-steps.md +0 -13
- package/docs/guide/observables-and-state.md +0 -213
- package/docs/guide/using-directives.md +0 -576
- package/docs/guide/working-with-shadow-dom.md +0 -296
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { HydrationMarkup } from "../components/hydration.js";
|
|
2
|
+
export class HydrationTargetElementError extends Error {
|
|
3
|
+
constructor(
|
|
4
|
+
/**
|
|
5
|
+
* The error message
|
|
6
|
+
*/
|
|
7
|
+
message,
|
|
8
|
+
/**
|
|
9
|
+
* The Compiled View Behavior Factories that belong to the view.
|
|
10
|
+
*/
|
|
11
|
+
factories,
|
|
12
|
+
/**
|
|
13
|
+
* The node to target factory.
|
|
14
|
+
*/
|
|
15
|
+
node) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.factories = factories;
|
|
18
|
+
this.node = node;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isComment(node) {
|
|
22
|
+
return node.nodeType === Node.COMMENT_NODE;
|
|
23
|
+
}
|
|
24
|
+
function isText(node) {
|
|
25
|
+
return node.nodeType === Node.TEXT_NODE;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Returns a range object inclusive of all nodes including and between the
|
|
29
|
+
* provided first and last node.
|
|
30
|
+
* @param first - The first node
|
|
31
|
+
* @param last - This last node
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
export function createRangeForNodes(first, last) {
|
|
35
|
+
const range = document.createRange();
|
|
36
|
+
range.setStart(first, 0);
|
|
37
|
+
// The lastIndex should be inclusive of the end of the lastChild. Obtain offset based
|
|
38
|
+
// on usageNotes: https://developer.mozilla.org/en-US/docs/Web/API/Range/setEnd#usage_notes
|
|
39
|
+
range.setEnd(last, isComment(last) || isText(last) ? last.data.length : last.childNodes.length);
|
|
40
|
+
return range;
|
|
41
|
+
}
|
|
42
|
+
function isShadowRoot(node) {
|
|
43
|
+
return node instanceof DocumentFragment && "mode" in node;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Maps {@link CompiledViewBehaviorFactory} ids to the corresponding node targets for the view.
|
|
47
|
+
* @param firstNode - The first node of the view.
|
|
48
|
+
* @param lastNode - The last node of the view.
|
|
49
|
+
* @param factories - The Compiled View Behavior Factories that belong to the view.
|
|
50
|
+
* @returns - A {@link ViewBehaviorTargets } object for the factories in the view.
|
|
51
|
+
*/
|
|
52
|
+
export function buildViewBindingTargets(firstNode, lastNode, factories) {
|
|
53
|
+
const range = createRangeForNodes(firstNode, lastNode);
|
|
54
|
+
const treeRoot = range.commonAncestorContainer;
|
|
55
|
+
const walker = document.createTreeWalker(treeRoot, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_COMMENT + NodeFilter.SHOW_TEXT, {
|
|
56
|
+
acceptNode(node) {
|
|
57
|
+
return range.comparePoint(node, 0) === 0
|
|
58
|
+
? NodeFilter.FILTER_ACCEPT
|
|
59
|
+
: NodeFilter.FILTER_REJECT;
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const targets = {};
|
|
63
|
+
const boundaries = {};
|
|
64
|
+
let node = (walker.currentNode = firstNode);
|
|
65
|
+
while (node !== null) {
|
|
66
|
+
switch (node.nodeType) {
|
|
67
|
+
case Node.ELEMENT_NODE: {
|
|
68
|
+
targetElement(node, factories, targets);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case Node.COMMENT_NODE: {
|
|
72
|
+
targetComment(node, walker, factories, targets, boundaries);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
node = walker.nextNode();
|
|
77
|
+
}
|
|
78
|
+
range.detach();
|
|
79
|
+
return { targets, boundaries };
|
|
80
|
+
}
|
|
81
|
+
function targetElement(node, factories, targets) {
|
|
82
|
+
// Check for attributes and map any factories.
|
|
83
|
+
const attrFactoryIds = HydrationMarkup.parseAttributeBinding(node);
|
|
84
|
+
if (attrFactoryIds !== null) {
|
|
85
|
+
for (const id of attrFactoryIds) {
|
|
86
|
+
if (!factories[id]) {
|
|
87
|
+
throw new HydrationTargetElementError(`HydrationView was unable to successfully target factory on ${node.nodeName} inside ${node.getRootNode().host.nodeName}. This likely indicates a template mismatch between SSR rendering and hydration.`, factories, node);
|
|
88
|
+
}
|
|
89
|
+
targetFactory(factories[id], node, targets);
|
|
90
|
+
}
|
|
91
|
+
node.removeAttribute(HydrationMarkup.attributeMarkerName);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function targetComment(node, walker, factories, targets, boundaries) {
|
|
95
|
+
if (HydrationMarkup.isElementBoundaryStartMarker(node)) {
|
|
96
|
+
skipToElementBoundaryEndMarker(node, walker);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (HydrationMarkup.isContentBindingStartMarker(node.data)) {
|
|
100
|
+
const parsed = HydrationMarkup.parseContentBindingStartMarker(node.data);
|
|
101
|
+
if (parsed === null) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const [index, id] = parsed;
|
|
105
|
+
const factory = factories[index];
|
|
106
|
+
const nodes = [];
|
|
107
|
+
let current = walker.nextSibling();
|
|
108
|
+
node.data = "";
|
|
109
|
+
const first = current;
|
|
110
|
+
// Search for the binding end marker that closes the binding.
|
|
111
|
+
while (current !== null) {
|
|
112
|
+
if (isComment(current)) {
|
|
113
|
+
const parsed = HydrationMarkup.parseContentBindingEndMarker(current.data);
|
|
114
|
+
if (parsed && parsed[1] === id) {
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
nodes.push(current);
|
|
119
|
+
current = walker.nextSibling();
|
|
120
|
+
}
|
|
121
|
+
if (current === null) {
|
|
122
|
+
const root = node.getRootNode();
|
|
123
|
+
throw new Error(`Error hydrating Comment node inside "${isShadowRoot(root) ? root.host.nodeName : root.nodeName}".`);
|
|
124
|
+
}
|
|
125
|
+
current.data = "";
|
|
126
|
+
if (nodes.length === 1 && isText(nodes[0])) {
|
|
127
|
+
targetFactory(factory, nodes[0], targets);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// If current === first, it means there is no content in
|
|
131
|
+
// the view. This happens when a `when` directive evaluates false,
|
|
132
|
+
// or whenever a content binding returns null or undefined.
|
|
133
|
+
// In that case, there will never be any content
|
|
134
|
+
// to hydrate and Binding can simply create a HTMLView
|
|
135
|
+
// whenever it needs to.
|
|
136
|
+
if (current !== first && current.previousSibling !== null) {
|
|
137
|
+
boundaries[factory.targetNodeId] = {
|
|
138
|
+
first,
|
|
139
|
+
last: current.previousSibling,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
// Binding evaluates to null / undefined or a template.
|
|
143
|
+
// If binding revaluates to string, it will replace content in target
|
|
144
|
+
// So we always insert a text node to ensure that
|
|
145
|
+
// text content binding will be written to this text node instead of comment
|
|
146
|
+
const dummyTextNode = current.parentNode.insertBefore(document.createTextNode(""), current);
|
|
147
|
+
targetFactory(factory, dummyTextNode, targets);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Moves TreeWalker to element boundary end marker
|
|
153
|
+
* @param node - element boundary start marker node
|
|
154
|
+
* @param walker - tree walker
|
|
155
|
+
*/
|
|
156
|
+
function skipToElementBoundaryEndMarker(node, walker) {
|
|
157
|
+
const id = HydrationMarkup.parseElementBoundaryStartMarker(node.data);
|
|
158
|
+
let current = walker.nextSibling();
|
|
159
|
+
while (current !== null) {
|
|
160
|
+
if (isComment(current)) {
|
|
161
|
+
const parsed = HydrationMarkup.parseElementBoundaryEndMarker(current.data);
|
|
162
|
+
if (parsed && parsed === id) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
current = walker.nextSibling();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
export function targetFactory(factory, node, targets) {
|
|
170
|
+
if (factory.targetNodeId === undefined) {
|
|
171
|
+
// Dev error, this shouldn't ever be thrown
|
|
172
|
+
throw new Error("Factory could not be target to the node");
|
|
173
|
+
}
|
|
174
|
+
targets[factory.targetNodeId] = node;
|
|
175
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { FAST, emptyArray } from "./platform.js";
|
|
2
|
+
// DOM
|
|
3
|
+
export { DOMAspect, DOM } from "./dom.js";
|
|
2
4
|
// Observation
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
5
|
+
export { ExecutionContext, Observable, observable, SourceLifetime, volatile, } from "./observation/observable.js";
|
|
6
|
+
export { PropertyChangeNotifier, SubscriberSet, } from "./observation/notifier.js";
|
|
7
|
+
export { ArrayObserver, lengthOf, Splice, SpliceStrategy, SpliceStrategySupport, } from "./observation/arrays.js";
|
|
8
|
+
export { Updates } from "./observation/update-queue.js";
|
|
9
|
+
// Binding
|
|
10
|
+
export { Binding } from "./binding/binding.js";
|
|
11
|
+
export { listener, oneWay } from "./binding/one-way.js";
|
|
12
|
+
export { oneTime } from "./binding/one-time.js";
|
|
13
|
+
export { normalizeBinding } from "./binding/normalize.js";
|
|
7
14
|
// Styles
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export
|
|
11
|
-
export
|
|
15
|
+
export { ElementStyles, } from "./styles/element-styles.js";
|
|
16
|
+
export { css } from "./styles/css.js";
|
|
17
|
+
export { cssDirective, CSSDirective, } from "./styles/css-directive.js";
|
|
18
|
+
export {} from "./styles/host.js";
|
|
19
|
+
export {} from "./styles/style-strategy.js";
|
|
20
|
+
export { CSSBindingDirective } from "./styles/css-binding-directive.js";
|
|
12
21
|
// Templating
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export * from "./templating/compiler.js";
|
|
22
|
+
export { html, InlineTemplateDirective, ViewTemplate, } from "./templating/template.js";
|
|
23
|
+
export { Compiler } from "./templating/compiler.js";
|
|
16
24
|
export { Markup, Parser } from "./templating/markup.js";
|
|
17
|
-
export
|
|
18
|
-
export
|
|
19
|
-
export
|
|
20
|
-
export
|
|
21
|
-
export
|
|
22
|
-
export
|
|
23
|
-
export
|
|
24
|
-
export
|
|
25
|
-
export
|
|
25
|
+
export { HTMLBindingDirective, } from "./templating/html-binding-directive.js";
|
|
26
|
+
export { htmlDirective, HTMLDirective, StatelessAttachedAttributeDirective, } from "./templating/html-directive.js";
|
|
27
|
+
export { ref, RefDirective } from "./templating/ref.js";
|
|
28
|
+
export { when } from "./templating/when.js";
|
|
29
|
+
export { repeat, RepeatBehavior, RepeatDirective, } from "./templating/repeat.js";
|
|
30
|
+
export { slotted, SlottedDirective, } from "./templating/slotted.js";
|
|
31
|
+
export { children, ChildrenDirective, } from "./templating/children.js";
|
|
32
|
+
export { HTMLView, HydrationBindingError, } from "./templating/view.js";
|
|
33
|
+
export { elements, NodeObservationDirective, } from "./templating/node-observation.js";
|
|
34
|
+
export { render, RenderBehavior, RenderDirective } from "./templating/render.js";
|
|
26
35
|
// Components
|
|
27
|
-
export
|
|
28
|
-
export
|
|
29
|
-
export
|
|
30
|
-
export
|
|
36
|
+
export { customElement, FASTElement } from "./components/fast-element.js";
|
|
37
|
+
export { FASTElementDefinition, } from "./components/fast-definitions.js";
|
|
38
|
+
export { attr, AttributeConfiguration, AttributeDefinition, booleanConverter, nullableBooleanConverter, nullableNumberConverter, } from "./components/attributes.js";
|
|
39
|
+
export { ElementController, HydratableElementController, } from "./components/element-controller.js";
|
package/dist/esm/index.rollup.js
CHANGED
package/dist/esm/interfaces.js
CHANGED
|
@@ -1,12 +1,60 @@
|
|
|
1
|
+
let kernelMode;
|
|
2
|
+
const kernelAttr = "fast-kernel";
|
|
3
|
+
try {
|
|
4
|
+
if (document.currentScript) {
|
|
5
|
+
kernelMode = document.currentScript.getAttribute(kernelAttr);
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
const scripts = document.getElementsByTagName("script");
|
|
9
|
+
const currentScript = scripts[scripts.length - 1];
|
|
10
|
+
kernelMode = currentScript.getAttribute(kernelAttr);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
kernelMode = "isolate";
|
|
15
|
+
}
|
|
16
|
+
let KernelServiceId;
|
|
17
|
+
switch (kernelMode) {
|
|
18
|
+
case "share": // share the kernel across major versions
|
|
19
|
+
KernelServiceId = Object.freeze({
|
|
20
|
+
updateQueue: 1,
|
|
21
|
+
observable: 2,
|
|
22
|
+
contextEvent: 3,
|
|
23
|
+
elementRegistry: 4,
|
|
24
|
+
});
|
|
25
|
+
break;
|
|
26
|
+
case "share-v2": // only share the kernel with other v2 instances
|
|
27
|
+
KernelServiceId = Object.freeze({
|
|
28
|
+
updateQueue: 1.2,
|
|
29
|
+
observable: 2.2,
|
|
30
|
+
contextEvent: 3.2,
|
|
31
|
+
elementRegistry: 4.2,
|
|
32
|
+
});
|
|
33
|
+
break;
|
|
34
|
+
default:
|
|
35
|
+
// fully isolate the kernel from all other FAST instances
|
|
36
|
+
const postfix = `-${Math.random().toString(36).substring(2, 8)}`;
|
|
37
|
+
KernelServiceId = Object.freeze({
|
|
38
|
+
updateQueue: `1.2${postfix}`,
|
|
39
|
+
observable: `2.2${postfix}`,
|
|
40
|
+
contextEvent: `3.2${postfix}`,
|
|
41
|
+
elementRegistry: `4.2${postfix}`,
|
|
42
|
+
});
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
export { KernelServiceId };
|
|
1
46
|
/**
|
|
2
|
-
*
|
|
47
|
+
* Determines whether or not an object is a function.
|
|
48
|
+
* @public
|
|
3
49
|
*/
|
|
4
50
|
export const isFunction = (object) => typeof object === "function";
|
|
5
51
|
/**
|
|
6
|
-
*
|
|
52
|
+
* Determines whether or not an object is a string.
|
|
53
|
+
* @public
|
|
7
54
|
*/
|
|
8
55
|
export const isString = (object) => typeof object === "string";
|
|
9
56
|
/**
|
|
10
|
-
*
|
|
57
|
+
* A function which does nothing.
|
|
58
|
+
* @public
|
|
11
59
|
*/
|
|
12
60
|
export const noop = () => void 0;
|
package/dist/esm/metadata.js
CHANGED
|
@@ -22,8 +22,11 @@ if (!("metadata" in Reflect)) {
|
|
|
22
22
|
return void 0;
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
|
+
const annotationParamTypesKey = "annotation:paramtypes";
|
|
26
|
+
const designParamTypesKey = "design:paramtypes";
|
|
25
27
|
/**
|
|
26
28
|
* Provides basic metadata capabilities used by Context and Dependency Injection.
|
|
29
|
+
* @public
|
|
27
30
|
*/
|
|
28
31
|
export const Metadata = Object.freeze({
|
|
29
32
|
/**
|
|
@@ -31,29 +34,29 @@ export const Metadata = Object.freeze({
|
|
|
31
34
|
* @param Type - The type to get the metadata for.
|
|
32
35
|
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
33
36
|
*/
|
|
34
|
-
getDesignParamTypes: Type => {
|
|
37
|
+
getDesignParamTypes: (Type) => {
|
|
35
38
|
var _a;
|
|
36
|
-
return (_a = Reflect.getOwnMetadata(
|
|
39
|
+
return ((_a = Reflect.getOwnMetadata(designParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
|
|
37
40
|
},
|
|
38
41
|
/**
|
|
39
42
|
* Gets the "annotation:paramtypes" metadata for the specified type.
|
|
40
43
|
* @param Type - The type to get the metadata for.
|
|
41
44
|
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
42
45
|
*/
|
|
43
|
-
getAnnotationParamTypes: Type => {
|
|
46
|
+
getAnnotationParamTypes: (Type) => {
|
|
44
47
|
var _a;
|
|
45
|
-
return (_a = Reflect.getOwnMetadata(
|
|
48
|
+
return ((_a = Reflect.getOwnMetadata(annotationParamTypesKey, Type)) !== null && _a !== void 0 ? _a : emptyArray);
|
|
46
49
|
},
|
|
47
50
|
/**
|
|
48
|
-
*
|
|
49
|
-
* @param Type - Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
|
|
51
|
+
* Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
|
|
50
52
|
* an empty, mutable metadata array is created and added.
|
|
51
|
-
* @
|
|
53
|
+
* @param Type - The type to get or create the metadata for.
|
|
54
|
+
* @returns A mutable metadata array.
|
|
52
55
|
*/
|
|
53
56
|
getOrCreateAnnotationParamTypes(Type) {
|
|
54
57
|
let types = this.getAnnotationParamTypes(Type);
|
|
55
58
|
if (types === emptyArray) {
|
|
56
|
-
Reflect.defineMetadata(
|
|
59
|
+
Reflect.defineMetadata(annotationParamTypesKey, (types = []), Type);
|
|
57
60
|
}
|
|
58
61
|
return types;
|
|
59
62
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { attr, FASTElement, Observable } from "../index.js";
|
|
11
|
+
import { _random, adjectives, nouns } from "../__test__/utilities.js";
|
|
12
|
+
export class TestObservable extends FASTElement {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this._greetMessage = "";
|
|
16
|
+
this._name = "";
|
|
17
|
+
this._exit = false;
|
|
18
|
+
}
|
|
19
|
+
connectedCallback() {
|
|
20
|
+
super.connectedCallback();
|
|
21
|
+
const first = this.firstName[0].toUpperCase() + this.firstName.slice(1);
|
|
22
|
+
const last = this.lastName[0].toUpperCase() + this.lastName.slice(1);
|
|
23
|
+
this.name = `${first} ${last}`;
|
|
24
|
+
this.greetMessage = `Welcome to FAST, ${this.name} !!`;
|
|
25
|
+
}
|
|
26
|
+
get greetMessage() {
|
|
27
|
+
Observable.track(this, "greetMessage");
|
|
28
|
+
return this._greetMessage;
|
|
29
|
+
}
|
|
30
|
+
set greetMessage(value) {
|
|
31
|
+
this._greetMessage = value;
|
|
32
|
+
Observable.notify(this, "greetMessage");
|
|
33
|
+
}
|
|
34
|
+
get name() {
|
|
35
|
+
Observable.track(this, "name");
|
|
36
|
+
return this._name;
|
|
37
|
+
}
|
|
38
|
+
set name(value) {
|
|
39
|
+
this._name = value;
|
|
40
|
+
Observable.notify(this, "name");
|
|
41
|
+
}
|
|
42
|
+
get exit() {
|
|
43
|
+
Observable.track(this, "exit");
|
|
44
|
+
return this._exit;
|
|
45
|
+
}
|
|
46
|
+
set exit(value) {
|
|
47
|
+
this._exit = value;
|
|
48
|
+
Observable.notify(this, "exit");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
__decorate([
|
|
52
|
+
attr,
|
|
53
|
+
__metadata("design:type", String)
|
|
54
|
+
], TestObservable.prototype, "firstName", void 0);
|
|
55
|
+
__decorate([
|
|
56
|
+
attr,
|
|
57
|
+
__metadata("design:type", String)
|
|
58
|
+
], TestObservable.prototype, "lastName", void 0);
|
|
59
|
+
TestObservable.define({
|
|
60
|
+
name: "test-observable",
|
|
61
|
+
});
|
|
62
|
+
const itemRenderer = () => {
|
|
63
|
+
const testObservable = document.createElement("test-observable");
|
|
64
|
+
testObservable.setAttribute("firstname", adjectives[_random(adjectives.length)]);
|
|
65
|
+
testObservable.setAttribute("lastname", nouns[_random(nouns.length)]);
|
|
66
|
+
const notifier = Observable.getNotifier(testObservable);
|
|
67
|
+
const handler = {
|
|
68
|
+
handleChange(source, propertyName) {
|
|
69
|
+
if (propertyName === "greetMessage")
|
|
70
|
+
source._exit = true;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
notifier.subscribe(handler, "greetMessage");
|
|
74
|
+
testObservable.greetMessage = `Goodbye ${testObservable.name}, see you next time!`;
|
|
75
|
+
notifier.unsubscribe(handler, "greetMessage");
|
|
76
|
+
return testObservable;
|
|
77
|
+
};
|
|
78
|
+
export default itemRenderer;
|
|
79
|
+
export { tests } from "@tensile-perf/web-components";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isFunction, isString, } from "../interfaces.js";
|
|
2
|
-
import { createMetadataLocator, FAST } from "../platform.js";
|
|
1
|
+
import { isFunction, isString, KernelServiceId, } from "../interfaces.js";
|
|
2
|
+
import { createMetadataLocator, FAST, makeSerializationNoop } from "../platform.js";
|
|
3
3
|
import { Updates } from "./update-queue.js";
|
|
4
4
|
import { PropertyChangeNotifier, SubscriberSet } from "./notifier.js";
|
|
5
5
|
/**
|
|
@@ -21,9 +21,9 @@ export const SourceLifetime = Object.freeze({
|
|
|
21
21
|
* Common Observable APIs.
|
|
22
22
|
* @public
|
|
23
23
|
*/
|
|
24
|
-
export const Observable = FAST.getById(
|
|
24
|
+
export const Observable = FAST.getById(KernelServiceId.observable, () => {
|
|
25
25
|
const queueUpdate = Updates.enqueue;
|
|
26
|
-
const volatileRegex = /(:|&&|\|\||if)/;
|
|
26
|
+
const volatileRegex = /(:|&&|\|\||if|\?\.)/;
|
|
27
27
|
const notifierLookup = new WeakMap();
|
|
28
28
|
let watcher = void 0;
|
|
29
29
|
let createArrayObserver = (array) => {
|
|
@@ -66,9 +66,9 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
class ExpressionNotifierImplementation extends SubscriberSet {
|
|
69
|
-
constructor(
|
|
70
|
-
super(
|
|
71
|
-
this.
|
|
69
|
+
constructor(expression, initialSubscriber, isVolatileBinding = false) {
|
|
70
|
+
super(expression, initialSubscriber);
|
|
71
|
+
this.expression = expression;
|
|
72
72
|
this.isVolatileBinding = isVolatileBinding;
|
|
73
73
|
this.needsRefresh = true;
|
|
74
74
|
this.needsQueue = true;
|
|
@@ -108,13 +108,17 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
|
|
|
108
108
|
this.needsRefresh = this.isVolatileBinding;
|
|
109
109
|
let result;
|
|
110
110
|
try {
|
|
111
|
-
result = this.
|
|
111
|
+
result = this.expression(source, context);
|
|
112
112
|
}
|
|
113
113
|
finally {
|
|
114
114
|
watcher = previousWatcher;
|
|
115
115
|
}
|
|
116
116
|
return result;
|
|
117
117
|
}
|
|
118
|
+
// backwards compat with v1 kernel
|
|
119
|
+
disconnect() {
|
|
120
|
+
this.dispose();
|
|
121
|
+
}
|
|
118
122
|
dispose() {
|
|
119
123
|
if (this.last !== null) {
|
|
120
124
|
let current = this.first;
|
|
@@ -176,6 +180,7 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
|
|
|
176
180
|
}
|
|
177
181
|
}
|
|
178
182
|
}
|
|
183
|
+
makeSerializationNoop(ExpressionNotifierImplementation);
|
|
179
184
|
return Object.freeze({
|
|
180
185
|
/**
|
|
181
186
|
* @internal
|
|
@@ -243,20 +248,20 @@ export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () =>
|
|
|
243
248
|
/**
|
|
244
249
|
* Creates a {@link ExpressionNotifier} that can watch the
|
|
245
250
|
* provided {@link Expression} for changes.
|
|
246
|
-
* @param
|
|
251
|
+
* @param expression - The binding to observe.
|
|
247
252
|
* @param initialSubscriber - An initial subscriber to changes in the binding value.
|
|
248
253
|
* @param isVolatileBinding - Indicates whether the binding's dependency list must be re-evaluated on every value evaluation.
|
|
249
254
|
*/
|
|
250
|
-
binding(
|
|
251
|
-
return new ExpressionNotifierImplementation(
|
|
255
|
+
binding(expression, initialSubscriber, isVolatileBinding = this.isVolatileBinding(expression)) {
|
|
256
|
+
return new ExpressionNotifierImplementation(expression, initialSubscriber, isVolatileBinding);
|
|
252
257
|
},
|
|
253
258
|
/**
|
|
254
259
|
* Determines whether a binding expression is volatile and needs to have its dependency list re-evaluated
|
|
255
260
|
* on every evaluation of the value.
|
|
256
|
-
* @param
|
|
261
|
+
* @param expression - The binding to inspect.
|
|
257
262
|
*/
|
|
258
|
-
isVolatileBinding(
|
|
259
|
-
return volatileRegex.test(
|
|
263
|
+
isVolatileBinding(expression) {
|
|
264
|
+
return volatileRegex.test(expression.toString());
|
|
260
265
|
},
|
|
261
266
|
});
|
|
262
267
|
});
|
|
@@ -284,7 +289,7 @@ export function volatile(target, name, descriptor) {
|
|
|
284
289
|
},
|
|
285
290
|
});
|
|
286
291
|
}
|
|
287
|
-
const contextEvent = FAST.getById(
|
|
292
|
+
const contextEvent = FAST.getById(KernelServiceId.contextEvent, () => {
|
|
288
293
|
let current = null;
|
|
289
294
|
return {
|
|
290
295
|
get() {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import "../interfaces.js";
|
|
1
|
+
import { KernelServiceId } from "../interfaces.js";
|
|
2
2
|
import { FAST } from "../platform.js";
|
|
3
3
|
/**
|
|
4
4
|
* The default UpdateQueue.
|
|
5
5
|
* @public
|
|
6
6
|
*/
|
|
7
|
-
export const Updates = FAST.getById(
|
|
7
|
+
export const Updates = FAST.getById(KernelServiceId.updateQueue, () => {
|
|
8
8
|
const tasks = [];
|
|
9
9
|
const pendingErrors = [];
|
|
10
10
|
const rAF = globalThis.requestAnimationFrame;
|
package/dist/esm/pending-task.js
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A concrete implementation of {@link PendingTask}
|
|
3
|
-
* @
|
|
3
|
+
* @public
|
|
4
4
|
*/
|
|
5
5
|
export class PendingTaskEvent extends Event {
|
|
6
|
+
/**
|
|
7
|
+
* Creates an instance of PendingTaskEvent.
|
|
8
|
+
* @param complete - A promise that resolves when the pending task is complete.
|
|
9
|
+
*/
|
|
6
10
|
constructor(complete) {
|
|
7
11
|
super(PendingTaskEvent.type, { bubbles: true, composed: true });
|
|
8
12
|
this.complete = complete;
|
|
9
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Determines whether a value is a PendingTaskEvent.
|
|
16
|
+
* @param value - The value to check.
|
|
17
|
+
* @returns True if the value is a PendingTaskEvent; false otherwise.
|
|
18
|
+
*/
|
|
10
19
|
static isPendingTask(value) {
|
|
11
20
|
var _a;
|
|
12
21
|
return (value.type === PendingTaskEvent.type &&
|
|
13
22
|
typeof ((_a = value.complete) === null || _a === void 0 ? void 0 : _a.then) === "function");
|
|
14
23
|
}
|
|
15
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* The type of the pending task event.
|
|
27
|
+
*/
|
|
16
28
|
PendingTaskEvent.type = "pending-task";
|
package/dist/esm/platform.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { noop } from "./interfaces.js";
|
|
2
|
+
import "./polyfills.js";
|
|
3
|
+
// ensure FAST global - duplicated debug.ts
|
|
2
4
|
const propConfig = {
|
|
3
5
|
configurable: false,
|
|
4
6
|
enumerable: false,
|
|
@@ -9,7 +11,7 @@ if (globalThis.FAST === void 0) {
|
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* The FAST global.
|
|
12
|
-
* @
|
|
14
|
+
* @public
|
|
13
15
|
*/
|
|
14
16
|
export const FAST = globalThis.FAST;
|
|
15
17
|
if (FAST.getById === void 0) {
|
|
@@ -85,3 +87,11 @@ export function createMetadataLocator() {
|
|
|
85
87
|
return metadata;
|
|
86
88
|
};
|
|
87
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Makes a type noop for JSON serialization.
|
|
92
|
+
* @param type - The type to make noop for JSON serialization.
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
export function makeSerializationNoop(type) {
|
|
96
|
+
type.prototype.toJSON = noop;
|
|
97
|
+
}
|