@microsoft/fast-element 1.10.2 → 2.0.0-beta.3
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 -12
- package/CHANGELOG.json +387 -1
- package/CHANGELOG.md +74 -2
- package/README.md +2 -2
- package/dist/dts/components/attributes.d.ts +4 -1
- package/dist/dts/components/controller.d.ts +12 -11
- package/dist/dts/components/fast-definitions.d.ts +10 -2
- package/dist/dts/components/fast-element.d.ts +12 -5
- package/dist/dts/context.d.ts +157 -0
- package/dist/dts/debug.d.ts +1 -0
- package/dist/dts/hooks.d.ts +20 -0
- package/dist/dts/index.d.ts +16 -15
- package/dist/dts/index.debug.d.ts +2 -0
- package/dist/dts/index.rollup.d.ts +2 -0
- package/dist/dts/index.rollup.debug.d.ts +3 -0
- package/dist/dts/interfaces.d.ts +145 -0
- package/dist/dts/metadata.d.ts +25 -0
- package/dist/dts/observation/arrays.d.ts +207 -0
- package/dist/dts/observation/behavior.d.ts +4 -4
- package/dist/dts/observation/notifier.d.ts +18 -18
- package/dist/dts/observation/observable.d.ts +56 -18
- package/dist/dts/observation/splice-strategies.d.ts +13 -0
- package/dist/dts/observation/update-queue.d.ts +40 -0
- package/dist/dts/platform.d.ts +18 -67
- package/dist/dts/polyfills.d.ts +8 -0
- package/dist/dts/styles/css-directive.d.ts +43 -5
- package/dist/dts/styles/css.d.ts +19 -3
- package/dist/dts/styles/element-styles.d.ts +42 -62
- package/dist/dts/templating/binding-signal.d.ts +38 -0
- package/dist/dts/templating/binding-two-way.d.ts +56 -0
- package/dist/dts/templating/binding.d.ts +233 -65
- package/dist/dts/templating/children.d.ts +18 -15
- package/dist/dts/templating/compiler.d.ts +46 -28
- package/dist/dts/templating/dom.d.ts +41 -0
- package/dist/dts/templating/html-directive.d.ts +181 -43
- package/dist/dts/templating/markup.d.ts +48 -0
- package/dist/dts/templating/node-observation.d.ts +45 -29
- package/dist/dts/templating/ref.d.ts +6 -12
- package/dist/dts/templating/repeat.d.ts +26 -14
- package/dist/dts/templating/slotted.d.ts +13 -14
- package/dist/dts/templating/template.d.ts +27 -21
- package/dist/dts/templating/view.d.ts +15 -22
- package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
- package/dist/dts/utilities.d.ts +40 -0
- package/dist/esm/components/attributes.js +25 -24
- package/dist/esm/components/controller.js +77 -57
- package/dist/esm/components/fast-definitions.js +16 -22
- package/dist/esm/components/fast-element.js +10 -2
- package/dist/esm/context.js +159 -0
- package/dist/esm/debug.js +30 -0
- package/dist/esm/hooks.js +32 -0
- package/dist/esm/index.debug.js +2 -0
- package/dist/esm/index.js +19 -14
- package/dist/esm/index.rollup.debug.js +3 -0
- package/dist/esm/index.rollup.js +2 -0
- package/dist/esm/interfaces.js +8 -1
- package/dist/esm/metadata.js +60 -0
- package/dist/esm/observation/arrays.js +269 -0
- package/dist/esm/observation/notifier.js +27 -35
- package/dist/esm/observation/observable.js +93 -68
- package/dist/esm/observation/{array-change-records.js → splice-strategies.js} +136 -62
- package/dist/esm/observation/update-queue.js +67 -0
- package/dist/esm/platform.js +36 -42
- package/dist/esm/polyfills.js +85 -0
- package/dist/esm/styles/css-directive.js +29 -13
- package/dist/esm/styles/css.js +27 -40
- package/dist/esm/styles/element-styles.js +65 -104
- package/dist/esm/templating/binding-signal.js +84 -0
- package/dist/esm/templating/binding-two-way.js +82 -0
- package/dist/esm/templating/binding.js +306 -153
- package/dist/esm/templating/children.js +33 -23
- package/dist/esm/templating/compiler.js +236 -152
- package/dist/esm/templating/dom.js +49 -0
- package/dist/esm/templating/html-directive.js +128 -40
- package/dist/esm/templating/markup.js +75 -0
- package/dist/esm/templating/node-observation.js +50 -45
- package/dist/esm/templating/ref.js +7 -16
- package/dist/esm/templating/repeat.js +39 -36
- package/dist/esm/templating/slotted.js +23 -20
- package/dist/esm/templating/template.js +51 -95
- package/dist/esm/templating/view.js +44 -43
- package/dist/esm/templating/when.js +2 -1
- package/dist/esm/utilities.js +139 -0
- package/dist/fast-element.api.json +11789 -5377
- package/dist/fast-element.d.ts +1178 -530
- package/dist/fast-element.debug.js +3722 -0
- package/dist/fast-element.debug.min.js +1 -0
- package/dist/fast-element.js +3484 -4033
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +2699 -0
- package/docs/api-report.md +472 -219
- package/docs/fast-element-2-changes.md +15 -0
- package/docs/guide/declaring-templates.md +4 -4
- package/docs/guide/defining-elements.md +2 -2
- package/docs/guide/next-steps.md +2 -2
- package/docs/guide/observables-and-state.md +1 -1
- package/docs/guide/using-directives.md +1 -1
- package/karma.conf.cjs +6 -17
- package/package.json +63 -15
- package/dist/dts/dom.d.ts +0 -112
- package/dist/dts/observation/array-change-records.d.ts +0 -48
- package/dist/dts/observation/array-observer.d.ts +0 -9
- package/dist/esm/dom.js +0 -207
- package/dist/esm/observation/array-observer.js +0 -177
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "../interfaces.js";
|
|
2
2
|
import { PropertyChangeNotifier } from "../observation/notifier.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ExecutionContext, Observable } from "../observation/observable.js";
|
|
4
|
+
import { FAST } from "../platform.js";
|
|
4
5
|
import { FASTElementDefinition } from "./fast-definitions.js";
|
|
5
6
|
const shadowRoots = new WeakMap();
|
|
6
7
|
const defaultEventOptions = {
|
|
@@ -9,8 +10,10 @@ const defaultEventOptions = {
|
|
|
9
10
|
cancelable: true,
|
|
10
11
|
};
|
|
11
12
|
function getShadowRoot(element) {
|
|
12
|
-
|
|
13
|
+
var _a, _b;
|
|
14
|
+
return (_b = (_a = element.shadowRoot) !== null && _a !== void 0 ? _a : shadowRoots.get(element)) !== null && _b !== void 0 ? _b : null;
|
|
13
15
|
}
|
|
16
|
+
const isConnectedPropertyName = "isConnected";
|
|
14
17
|
/**
|
|
15
18
|
* Controls the lifecycle and rendering of a `FASTElement`.
|
|
16
19
|
* @public
|
|
@@ -28,6 +31,7 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
28
31
|
this.boundObservables = null;
|
|
29
32
|
this.behaviors = null;
|
|
30
33
|
this.needsInitialization = true;
|
|
34
|
+
this.hasExistingShadowRoot = false;
|
|
31
35
|
this._template = null;
|
|
32
36
|
this._styles = null;
|
|
33
37
|
this._isConnected = false;
|
|
@@ -50,9 +54,15 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
50
54
|
this.definition = definition;
|
|
51
55
|
const shadowOptions = definition.shadowOptions;
|
|
52
56
|
if (shadowOptions !== void 0) {
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
57
|
+
let shadowRoot = element.shadowRoot;
|
|
58
|
+
if (shadowRoot) {
|
|
59
|
+
this.hasExistingShadowRoot = true;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
shadowRoot = element.attachShadow(shadowOptions);
|
|
63
|
+
if (shadowOptions.mode === "closed") {
|
|
64
|
+
shadowRoots.set(element, shadowRoot);
|
|
65
|
+
}
|
|
56
66
|
}
|
|
57
67
|
}
|
|
58
68
|
// Capture any observable values that were set by the binding engine before
|
|
@@ -77,12 +87,12 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
77
87
|
* connected to the document.
|
|
78
88
|
*/
|
|
79
89
|
get isConnected() {
|
|
80
|
-
Observable.track(this,
|
|
90
|
+
Observable.track(this, isConnectedPropertyName);
|
|
81
91
|
return this._isConnected;
|
|
82
92
|
}
|
|
83
93
|
setIsConnected(value) {
|
|
84
94
|
this._isConnected = value;
|
|
85
|
-
Observable.notify(this,
|
|
95
|
+
Observable.notify(this, isConnectedPropertyName);
|
|
86
96
|
}
|
|
87
97
|
/**
|
|
88
98
|
* Gets/sets the template used to render the component.
|
|
@@ -90,6 +100,19 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
90
100
|
* This value can only be accurately read after connect but can be set at any time.
|
|
91
101
|
*/
|
|
92
102
|
get template() {
|
|
103
|
+
var _a;
|
|
104
|
+
// 1. Template overrides take top precedence.
|
|
105
|
+
if (this._template === null) {
|
|
106
|
+
const definition = this.definition;
|
|
107
|
+
if (this.element.resolveTemplate) {
|
|
108
|
+
// 2. Allow for element instance overrides next.
|
|
109
|
+
this._template = this.element.resolveTemplate();
|
|
110
|
+
}
|
|
111
|
+
else if (definition.template) {
|
|
112
|
+
// 3. Default to the static definition.
|
|
113
|
+
this._template = (_a = definition.template) !== null && _a !== void 0 ? _a : null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
93
116
|
return this._template;
|
|
94
117
|
}
|
|
95
118
|
set template(value) {
|
|
@@ -107,6 +130,19 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
107
130
|
* This value can only be accurately read after connect but can be set at any time.
|
|
108
131
|
*/
|
|
109
132
|
get styles() {
|
|
133
|
+
var _a;
|
|
134
|
+
// 1. Styles overrides take top precedence.
|
|
135
|
+
if (this._styles === null) {
|
|
136
|
+
const definition = this.definition;
|
|
137
|
+
if (this.element.resolveStyles) {
|
|
138
|
+
// 2. Allow for element instance overrides next.
|
|
139
|
+
this._styles = this.element.resolveStyles();
|
|
140
|
+
}
|
|
141
|
+
else if (definition.styles) {
|
|
142
|
+
// 3. Default to the static definition.
|
|
143
|
+
this._styles = (_a = definition.styles) !== null && _a !== void 0 ? _a : null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
110
146
|
return this._styles;
|
|
111
147
|
}
|
|
112
148
|
set styles(value) {
|
|
@@ -117,7 +153,7 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
117
153
|
this.removeStyles(this._styles);
|
|
118
154
|
}
|
|
119
155
|
this._styles = value;
|
|
120
|
-
if (!this.needsInitialization
|
|
156
|
+
if (!this.needsInitialization) {
|
|
121
157
|
this.addStyles(value);
|
|
122
158
|
}
|
|
123
159
|
}
|
|
@@ -126,9 +162,12 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
126
162
|
* @param styles - The styles to add.
|
|
127
163
|
*/
|
|
128
164
|
addStyles(styles) {
|
|
165
|
+
if (!styles) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
129
168
|
const target = getShadowRoot(this.element) ||
|
|
130
169
|
this.element.getRootNode();
|
|
131
|
-
if (styles instanceof
|
|
170
|
+
if (styles instanceof HTMLElement) {
|
|
132
171
|
target.append(styles);
|
|
133
172
|
}
|
|
134
173
|
else if (!styles.isAttachedTo(target)) {
|
|
@@ -144,9 +183,12 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
144
183
|
* @param styles - the styles to remove.
|
|
145
184
|
*/
|
|
146
185
|
removeStyles(styles) {
|
|
186
|
+
if (!styles) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
147
189
|
const target = getShadowRoot(this.element) ||
|
|
148
190
|
this.element.getRootNode();
|
|
149
|
-
if (styles instanceof
|
|
191
|
+
if (styles instanceof HTMLElement) {
|
|
150
192
|
target.removeChild(styles);
|
|
151
193
|
}
|
|
152
194
|
else if (styles.isAttachedTo(target)) {
|
|
@@ -162,7 +204,8 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
162
204
|
* @param behaviors - The behaviors to add.
|
|
163
205
|
*/
|
|
164
206
|
addBehaviors(behaviors) {
|
|
165
|
-
|
|
207
|
+
var _a;
|
|
208
|
+
const targetBehaviors = (_a = this.behaviors) !== null && _a !== void 0 ? _a : (this.behaviors = new Map());
|
|
166
209
|
const length = behaviors.length;
|
|
167
210
|
const behaviorsToBind = [];
|
|
168
211
|
for (let i = 0; i < length; ++i) {
|
|
@@ -177,8 +220,9 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
177
220
|
}
|
|
178
221
|
if (this._isConnected) {
|
|
179
222
|
const element = this.element;
|
|
223
|
+
const context = ExecutionContext.default;
|
|
180
224
|
for (let i = 0; i < behaviorsToBind.length; ++i) {
|
|
181
|
-
behaviorsToBind[i].bind(element,
|
|
225
|
+
behaviorsToBind[i].bind(element, context);
|
|
182
226
|
}
|
|
183
227
|
}
|
|
184
228
|
}
|
|
@@ -205,8 +249,9 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
205
249
|
}
|
|
206
250
|
if (this._isConnected) {
|
|
207
251
|
const element = this.element;
|
|
252
|
+
const context = ExecutionContext.default;
|
|
208
253
|
for (let i = 0; i < behaviorsToUnbind.length; ++i) {
|
|
209
|
-
behaviorsToUnbind[i].unbind(element);
|
|
254
|
+
behaviorsToUnbind[i].unbind(element, context);
|
|
210
255
|
}
|
|
211
256
|
}
|
|
212
257
|
}
|
|
@@ -218,16 +263,17 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
218
263
|
return;
|
|
219
264
|
}
|
|
220
265
|
const element = this.element;
|
|
266
|
+
const context = ExecutionContext.default;
|
|
221
267
|
if (this.needsInitialization) {
|
|
222
268
|
this.finishInitialization();
|
|
223
269
|
}
|
|
224
270
|
else if (this.view !== null) {
|
|
225
|
-
this.view.bind(element,
|
|
271
|
+
this.view.bind(element, context);
|
|
226
272
|
}
|
|
227
273
|
const behaviors = this.behaviors;
|
|
228
274
|
if (behaviors !== null) {
|
|
229
|
-
for (const
|
|
230
|
-
behavior.bind(element,
|
|
275
|
+
for (const behavior of behaviors.keys()) {
|
|
276
|
+
behavior.bind(element, context);
|
|
231
277
|
}
|
|
232
278
|
}
|
|
233
279
|
this.setIsConnected(true);
|
|
@@ -247,8 +293,9 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
247
293
|
const behaviors = this.behaviors;
|
|
248
294
|
if (behaviors !== null) {
|
|
249
295
|
const element = this.element;
|
|
250
|
-
|
|
251
|
-
|
|
296
|
+
const context = ExecutionContext.default;
|
|
297
|
+
for (const behavior of behaviors.keys()) {
|
|
298
|
+
behavior.unbind(element, context);
|
|
252
299
|
}
|
|
253
300
|
}
|
|
254
301
|
}
|
|
@@ -290,55 +337,28 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
290
337
|
}
|
|
291
338
|
this.boundObservables = null;
|
|
292
339
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (this._template === null) {
|
|
296
|
-
if (this.element.resolveTemplate) {
|
|
297
|
-
// 2. Allow for element instance overrides next.
|
|
298
|
-
this._template = this.element.resolveTemplate();
|
|
299
|
-
}
|
|
300
|
-
else if (definition.template) {
|
|
301
|
-
// 3. Default to the static definition.
|
|
302
|
-
this._template = definition.template || null;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
// If we have a template after the above process, render it.
|
|
306
|
-
// If there's no template, then the element author has opted into
|
|
307
|
-
// custom rendering and they will managed the shadow root's content themselves.
|
|
308
|
-
if (this._template !== null) {
|
|
309
|
-
this.renderTemplate(this._template);
|
|
310
|
-
}
|
|
311
|
-
// 1. Styles overrides take top precedence.
|
|
312
|
-
if (this._styles === null) {
|
|
313
|
-
if (this.element.resolveStyles) {
|
|
314
|
-
// 2. Allow for element instance overrides next.
|
|
315
|
-
this._styles = this.element.resolveStyles();
|
|
316
|
-
}
|
|
317
|
-
else if (definition.styles) {
|
|
318
|
-
// 3. Default to the static definition.
|
|
319
|
-
this._styles = definition.styles || null;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// If we have styles after the above process, add them.
|
|
323
|
-
if (this._styles !== null) {
|
|
324
|
-
this.addStyles(this._styles);
|
|
325
|
-
}
|
|
340
|
+
this.renderTemplate(this.template);
|
|
341
|
+
this.addStyles(this.styles);
|
|
326
342
|
this.needsInitialization = false;
|
|
327
343
|
}
|
|
328
344
|
renderTemplate(template) {
|
|
345
|
+
var _a;
|
|
329
346
|
const element = this.element;
|
|
330
347
|
// When getting the host to render to, we start by looking
|
|
331
348
|
// up the shadow root. If there isn't one, then that means
|
|
332
349
|
// we're doing a Light DOM render to the element's direct children.
|
|
333
|
-
const host = getShadowRoot(element)
|
|
350
|
+
const host = (_a = getShadowRoot(element)) !== null && _a !== void 0 ? _a : element;
|
|
334
351
|
if (this.view !== null) {
|
|
335
352
|
// If there's already a view, we need to unbind and remove through dispose.
|
|
336
353
|
this.view.dispose();
|
|
337
354
|
this.view = null;
|
|
338
355
|
}
|
|
339
|
-
else if (!this.needsInitialization) {
|
|
356
|
+
else if (!this.needsInitialization || this.hasExistingShadowRoot) {
|
|
357
|
+
this.hasExistingShadowRoot = false;
|
|
340
358
|
// If there was previous custom rendering, we need to clear out the host.
|
|
341
|
-
|
|
359
|
+
for (let child = host.firstChild; child !== null; child = host.firstChild) {
|
|
360
|
+
host.removeChild(child);
|
|
361
|
+
}
|
|
342
362
|
}
|
|
343
363
|
if (template) {
|
|
344
364
|
// If a new template was provided, render it.
|
|
@@ -358,9 +378,9 @@ export class Controller extends PropertyChangeNotifier {
|
|
|
358
378
|
if (controller !== void 0) {
|
|
359
379
|
return controller;
|
|
360
380
|
}
|
|
361
|
-
const definition = FASTElementDefinition.
|
|
381
|
+
const definition = FASTElementDefinition.getForInstance(element);
|
|
362
382
|
if (definition === void 0) {
|
|
363
|
-
throw
|
|
383
|
+
throw FAST.error(1401 /* Message.missingElementDefinition */);
|
|
364
384
|
}
|
|
365
385
|
return (element.$fastController = new Controller(element, definition));
|
|
366
386
|
}
|
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isString } from "../interfaces.js";
|
|
2
2
|
import { Observable } from "../observation/observable.js";
|
|
3
|
+
import { createTypeRegistry, FAST } from "../platform.js";
|
|
3
4
|
import { ElementStyles } from "../styles/element-styles.js";
|
|
4
5
|
import { AttributeDefinition } from "./attributes.js";
|
|
5
6
|
const defaultShadowOptions = { mode: "open" };
|
|
6
7
|
const defaultElementOptions = {};
|
|
7
|
-
const
|
|
8
|
-
const typeToDefinition = new Map();
|
|
9
|
-
return Object.freeze({
|
|
10
|
-
register(definition) {
|
|
11
|
-
if (typeToDefinition.has(definition.type)) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
typeToDefinition.set(definition.type, definition);
|
|
15
|
-
return true;
|
|
16
|
-
},
|
|
17
|
-
getByType(key) {
|
|
18
|
-
return typeToDefinition.get(key);
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
});
|
|
8
|
+
const fastElementRegistry = FAST.getById(4 /* KernelServiceId.elementRegistry */, () => createTypeRegistry());
|
|
22
9
|
/**
|
|
23
10
|
* Defines metadata for a FASTElement.
|
|
24
11
|
* @public
|
|
@@ -31,7 +18,7 @@ export class FASTElementDefinition {
|
|
|
31
18
|
* that describes the element to define.
|
|
32
19
|
*/
|
|
33
20
|
constructor(type, nameOrConfig = type.definition) {
|
|
34
|
-
if (
|
|
21
|
+
if (isString(nameOrConfig)) {
|
|
35
22
|
nameOrConfig = { name: nameOrConfig };
|
|
36
23
|
}
|
|
37
24
|
this.type = type;
|
|
@@ -65,24 +52,26 @@ export class FASTElementDefinition {
|
|
|
65
52
|
nameOrConfig.styles === void 0
|
|
66
53
|
? void 0
|
|
67
54
|
: Array.isArray(nameOrConfig.styles)
|
|
68
|
-
? ElementStyles
|
|
55
|
+
? new ElementStyles(nameOrConfig.styles)
|
|
69
56
|
: nameOrConfig.styles instanceof ElementStyles
|
|
70
57
|
? nameOrConfig.styles
|
|
71
|
-
: ElementStyles
|
|
58
|
+
: new ElementStyles([nameOrConfig.styles]);
|
|
72
59
|
}
|
|
73
60
|
/**
|
|
74
61
|
* Indicates if this element has been defined in at least one registry.
|
|
75
62
|
*/
|
|
76
63
|
get isDefined() {
|
|
77
|
-
return !!
|
|
64
|
+
return !!fastElementRegistry.getByType(this.type);
|
|
78
65
|
}
|
|
79
66
|
/**
|
|
80
67
|
* Defines a custom element based on this definition.
|
|
81
68
|
* @param registry - The element registry to define the element in.
|
|
69
|
+
* @remarks
|
|
70
|
+
* This operation is idempotent per registry.
|
|
82
71
|
*/
|
|
83
72
|
define(registry = customElements) {
|
|
84
73
|
const type = this.type;
|
|
85
|
-
if (
|
|
74
|
+
if (fastElementRegistry.register(this)) {
|
|
86
75
|
const attributes = this.attributes;
|
|
87
76
|
const proto = type.prototype;
|
|
88
77
|
for (let i = 0, ii = attributes.length; i < ii; ++i) {
|
|
@@ -103,4 +92,9 @@ export class FASTElementDefinition {
|
|
|
103
92
|
* Gets the element definition associated with the specified type.
|
|
104
93
|
* @param type - The custom element type to retrieve the definition for.
|
|
105
94
|
*/
|
|
106
|
-
FASTElementDefinition.
|
|
95
|
+
FASTElementDefinition.getByType = fastElementRegistry.getByType;
|
|
96
|
+
/**
|
|
97
|
+
* Gets the element definition associated with the instance.
|
|
98
|
+
* @param instance - The custom element instance to retrieve the definition for.
|
|
99
|
+
*/
|
|
100
|
+
FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
|
|
@@ -43,7 +43,15 @@ export const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
43
43
|
* that describes the element to define.
|
|
44
44
|
*/
|
|
45
45
|
define(type, nameOrDef) {
|
|
46
|
-
return
|
|
46
|
+
return this.metadata(type, nameOrDef).define().type;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* Defines metadata for a FASTElement which can be used to later define the element.
|
|
50
|
+
* IMPORTANT: This API will be renamed to "compose" in a future beta.
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
metadata(type, nameOrDef) {
|
|
54
|
+
return new FASTElementDefinition(type, nameOrDef);
|
|
47
55
|
},
|
|
48
56
|
});
|
|
49
57
|
/**
|
|
@@ -55,6 +63,6 @@ export const FASTElement = Object.assign(createFASTElement(HTMLElement), {
|
|
|
55
63
|
export function customElement(nameOrDef) {
|
|
56
64
|
/* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
|
|
57
65
|
return function (type) {
|
|
58
|
-
|
|
66
|
+
FASTElement.define(type, nameOrDef);
|
|
59
67
|
};
|
|
60
68
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Metadata } from "./metadata.js";
|
|
2
|
+
const contextEventType = "context-request";
|
|
3
|
+
let requestStrategy;
|
|
4
|
+
/**
|
|
5
|
+
* Enables using the {@link https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md | W3C Community Context protocol.}
|
|
6
|
+
* @beta
|
|
7
|
+
*/
|
|
8
|
+
export const Context = Object.freeze({
|
|
9
|
+
/**
|
|
10
|
+
* The event type used for W3C Context Protocol requests.
|
|
11
|
+
*/
|
|
12
|
+
eventType: contextEventType,
|
|
13
|
+
/**
|
|
14
|
+
* Creates a W3C Community Protocol-based Context object to use in requesting/providing
|
|
15
|
+
* context through the DOM.
|
|
16
|
+
* @param name - The name to use for the connext. Useful in debugging.
|
|
17
|
+
* @param initialValue - An optional initial value to use if a context handler isn't found.
|
|
18
|
+
*/
|
|
19
|
+
create(name, initialValue) {
|
|
20
|
+
const Interface = function (target, property, index) {
|
|
21
|
+
if (target == null || new.target !== undefined) {
|
|
22
|
+
throw new Error(`No registration for context: '${Interface.name}'`);
|
|
23
|
+
}
|
|
24
|
+
if (property) {
|
|
25
|
+
Context.defineProperty(target, property, Interface);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const types = Metadata.getOrCreateAnnotationParamTypes(target);
|
|
29
|
+
types[index] = Interface;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
Interface.$isInterface = true;
|
|
33
|
+
Interface.initialValue = initialValue;
|
|
34
|
+
Reflect.defineProperty(Interface, "name", { value: name });
|
|
35
|
+
Interface.handle = (target, callback) => Context.handle(target, callback, Interface);
|
|
36
|
+
Interface.provide = (target, value) => Context.provide(target, Interface, value);
|
|
37
|
+
Interface.get = (target) => Context.get(target, Interface);
|
|
38
|
+
Interface.request = (target, callback, multiple) => Context.request(target, Interface, callback, multiple);
|
|
39
|
+
Interface.toString = () => `Context<${Interface.name}>`;
|
|
40
|
+
return Interface;
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Sets the strategy used by all FAST-specific context requests made through the
|
|
44
|
+
* Context.request, Context.get, Context.defineProperty, and ContextDecorator APIs.
|
|
45
|
+
* @param strategy - The strategy to use. By default, the strategy is Context.dispatch.
|
|
46
|
+
*/
|
|
47
|
+
setDefaultRequestStrategy(strategy) {
|
|
48
|
+
requestStrategy = strategy;
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* Gets the context value for the target node or returns the initial value if
|
|
52
|
+
* a context handler is not found.
|
|
53
|
+
* @param target - The target to get the context for.
|
|
54
|
+
* @param context - The context to locate.
|
|
55
|
+
* @returns The context value.
|
|
56
|
+
* @remarks
|
|
57
|
+
* Uses the default request strategy to locate the context. If no context is found
|
|
58
|
+
* then the initial value of the context is returned.
|
|
59
|
+
*/
|
|
60
|
+
get(target, context) {
|
|
61
|
+
var _a;
|
|
62
|
+
let value;
|
|
63
|
+
requestStrategy(target, context, found => (value = found), false);
|
|
64
|
+
return (_a = value) !== null && _a !== void 0 ? _a : context.initialValue;
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Requests the context value for the target node.
|
|
68
|
+
* @param target - The target to request the context for.
|
|
69
|
+
* @param context - The context to locate.
|
|
70
|
+
* @param callback - A callback to invoke with the context value.
|
|
71
|
+
* @param multiple - Whether the context requestor expects to handle updates
|
|
72
|
+
* to the context value after the initial request.
|
|
73
|
+
* @remarks
|
|
74
|
+
* Uses the default request strategy to locate the context.
|
|
75
|
+
*/
|
|
76
|
+
request(target, context, callback, multiple = false) {
|
|
77
|
+
requestStrategy(target, context, callback, multiple);
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @param target - The target to dispatch the context event on.
|
|
82
|
+
* @param context - The context to locate.
|
|
83
|
+
* @param callback - The callback to invoke with the context value.
|
|
84
|
+
* @param multiple - Whether the context requestor expects to handle updates
|
|
85
|
+
* to the context value after the initial request.
|
|
86
|
+
* @remarks
|
|
87
|
+
* This API does NOT use the default request strategy. It always dispatches
|
|
88
|
+
* an event through the DOM.
|
|
89
|
+
*/
|
|
90
|
+
dispatch(target, context, callback, multiple = false) {
|
|
91
|
+
target.dispatchEvent(new ContextEvent(context, callback, multiple));
|
|
92
|
+
},
|
|
93
|
+
provide(target, context, value) {
|
|
94
|
+
this.handle(target, (event) => {
|
|
95
|
+
event.stopImmediatePropagation();
|
|
96
|
+
event.callback(value);
|
|
97
|
+
}, context);
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
*
|
|
101
|
+
* @param target - The target on which to handle context requests.
|
|
102
|
+
* @param callback - The callback to invoke when a context request is received.
|
|
103
|
+
* @param context - The context to handle requests for.
|
|
104
|
+
* @remarks
|
|
105
|
+
* If a context is not provided then the callback will be invoked for all context
|
|
106
|
+
* requests that are received on the target.
|
|
107
|
+
*/
|
|
108
|
+
handle(target, callback, context) {
|
|
109
|
+
if (context) {
|
|
110
|
+
target.addEventListener(contextEventType, (event) => {
|
|
111
|
+
if (event.context === context) {
|
|
112
|
+
callback(event);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
target.addEventListener(contextEventType, callback);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
/**
|
|
121
|
+
* Defines a getter-only property on the target that will return the context
|
|
122
|
+
* value for the target.
|
|
123
|
+
* @param target The target to define the property on.
|
|
124
|
+
* @param propertyName The name of the property to define.
|
|
125
|
+
* @param context The context that will be used to retrieve the property value.
|
|
126
|
+
* @remarks
|
|
127
|
+
* Uses the default request strategy to locate the context and will return the
|
|
128
|
+
* initialValue if the context isn't handled.
|
|
129
|
+
*/
|
|
130
|
+
defineProperty(target, propertyName, context) {
|
|
131
|
+
const field = `$di_${propertyName}`;
|
|
132
|
+
Reflect.defineProperty(target, propertyName, {
|
|
133
|
+
get: function () {
|
|
134
|
+
var _a;
|
|
135
|
+
return (_a = this[field]) !== null && _a !== void 0 ? _a : (this[field] = Context.get(this, context));
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
Context.setDefaultRequestStrategy(Context.dispatch);
|
|
141
|
+
/**
|
|
142
|
+
* An event fired by a context requester to signal it desires a named context.
|
|
143
|
+
*
|
|
144
|
+
* A provider should inspect the `context` property of the event to determine if it has a value that can
|
|
145
|
+
* satisfy the request, calling the `callback` with the requested value if so.
|
|
146
|
+
*
|
|
147
|
+
* If the requested context event contains a truthy `multiple` value, then a provider can call the callback
|
|
148
|
+
* multiple times if the value is changed, if this is the case the provider should pass a `dispose`
|
|
149
|
+
* method to the callback which requesters can invoke to indicate they no longer wish to receive these updates.
|
|
150
|
+
* @public
|
|
151
|
+
*/
|
|
152
|
+
export class ContextEvent extends Event {
|
|
153
|
+
constructor(context, callback, multiple) {
|
|
154
|
+
super(contextEventType, { bubbles: true, composed: true });
|
|
155
|
+
this.context = context;
|
|
156
|
+
this.callback = callback;
|
|
157
|
+
this.multiple = multiple;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
if (globalThis.FAST === void 0) {
|
|
2
|
+
Reflect.defineProperty(globalThis, "FAST", {
|
|
3
|
+
value: Object.create(null),
|
|
4
|
+
configurable: false,
|
|
5
|
+
enumerable: false,
|
|
6
|
+
writable: false,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
const FAST = globalThis.FAST;
|
|
10
|
+
const debugMessages = {
|
|
11
|
+
[1101 /* needsArrayObservation */]: "Must call enableArrayObservation before observing arrays.",
|
|
12
|
+
[1201 /* onlySetHTMLPolicyOnce */]: "The HTML policy can only be set once.",
|
|
13
|
+
[1202 /* bindingInnerHTMLRequiresTrustedTypes */]: "To bind innerHTML, you must use a TrustedTypesPolicy.",
|
|
14
|
+
[1203 /* twoWayBindingRequiresObservables */]: "View=>Model update skipped. To use twoWay binding, the target property must be observable.",
|
|
15
|
+
[1401 /* missingElementDefinition */]: "Missing FASTElement definition.",
|
|
16
|
+
};
|
|
17
|
+
Object.assign(FAST, {
|
|
18
|
+
addMessages(messages) {
|
|
19
|
+
Object.assign(debugMessages, messages);
|
|
20
|
+
},
|
|
21
|
+
warn(code, ...args) {
|
|
22
|
+
var _a;
|
|
23
|
+
console.warn((_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Warning");
|
|
24
|
+
},
|
|
25
|
+
error(code, ...args) {
|
|
26
|
+
var _a;
|
|
27
|
+
return new Error((_a = debugMessages[code]) !== null && _a !== void 0 ? _a : "Unknown Error");
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Observable } from "./observation/observable.js";
|
|
2
|
+
import { makeObservable } from "./utilities.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates an observable state value.
|
|
5
|
+
* @param value The initial state value.
|
|
6
|
+
* @param deep Whether or not to convert the state value to an observable.
|
|
7
|
+
* @returns The state accessor functions.
|
|
8
|
+
* @beta
|
|
9
|
+
*/
|
|
10
|
+
export function useState(value, deep = false) {
|
|
11
|
+
const host = makeObservable({ value }, deep);
|
|
12
|
+
return [() => host.value, newValue => (host.value = newValue)];
|
|
13
|
+
}
|
|
14
|
+
const effectModel = Object.freeze({});
|
|
15
|
+
/**
|
|
16
|
+
* Executes an action once, and then whenever any of its dependent state changes.
|
|
17
|
+
* @param action An action that is affected by state changes.
|
|
18
|
+
* @returns A BindingObserver which can be used to dispose of the effect.
|
|
19
|
+
*/
|
|
20
|
+
export function useEffect(action) {
|
|
21
|
+
/* eslint prefer-const: 0 */
|
|
22
|
+
let observer;
|
|
23
|
+
const subscriber = {
|
|
24
|
+
handleChange() {
|
|
25
|
+
observer.observe(effectModel);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
observer = Observable.binding(action, subscriber);
|
|
29
|
+
observer.setMode(false);
|
|
30
|
+
subscriber.handleChange();
|
|
31
|
+
return observer;
|
|
32
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
export * from "./platform.js";
|
|
2
|
-
|
|
3
|
-
export * from "./components/fast-element.js";
|
|
4
|
-
export { FASTElementDefinition, } from "./components/fast-definitions.js";
|
|
5
|
-
export * from "./components/attributes.js";
|
|
6
|
-
export * from "./components/controller.js";
|
|
7
|
-
export * from "./templating/compiler.js";
|
|
8
|
-
export { ElementStyles, } from "./styles/element-styles.js";
|
|
9
|
-
export { css, cssPartial } from "./styles/css.js";
|
|
10
|
-
export { CSSDirective } from "./styles/css-directive.js";
|
|
11
|
-
export * from "./templating/view.js";
|
|
2
|
+
// Observation
|
|
12
3
|
export * from "./observation/observable.js";
|
|
13
4
|
export * from "./observation/notifier.js";
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
|
|
5
|
+
export * from "./observation/arrays.js";
|
|
6
|
+
export * from "./observation/update-queue.js";
|
|
7
|
+
// Styles
|
|
8
|
+
export * from "./styles/element-styles.js";
|
|
9
|
+
export * from "./styles/css.js";
|
|
10
|
+
export * from "./styles/css-directive.js";
|
|
11
|
+
// Templating
|
|
12
|
+
export * from "./templating/dom.js";
|
|
13
|
+
export * from "./templating/template.js";
|
|
14
|
+
export * from "./templating/compiler.js";
|
|
15
|
+
export { Markup, Parser } from "./templating/markup.js";
|
|
17
16
|
export * from "./templating/binding.js";
|
|
18
17
|
export * from "./templating/html-directive.js";
|
|
19
18
|
export * from "./templating/ref.js";
|
|
@@ -21,4 +20,10 @@ export * from "./templating/when.js";
|
|
|
21
20
|
export * from "./templating/repeat.js";
|
|
22
21
|
export * from "./templating/slotted.js";
|
|
23
22
|
export * from "./templating/children.js";
|
|
24
|
-
export
|
|
23
|
+
export * from "./templating/view.js";
|
|
24
|
+
export * from "./templating/node-observation.js";
|
|
25
|
+
// Components
|
|
26
|
+
export * from "./components/fast-element.js";
|
|
27
|
+
export * from "./components/fast-definitions.js";
|
|
28
|
+
export * from "./components/attributes.js";
|
|
29
|
+
export * from "./components/controller.js";
|