@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.
Files changed (104) hide show
  1. package/.eslintrc.json +1 -12
  2. package/CHANGELOG.json +387 -1
  3. package/CHANGELOG.md +74 -2
  4. package/README.md +2 -2
  5. package/dist/dts/components/attributes.d.ts +4 -1
  6. package/dist/dts/components/controller.d.ts +12 -11
  7. package/dist/dts/components/fast-definitions.d.ts +10 -2
  8. package/dist/dts/components/fast-element.d.ts +12 -5
  9. package/dist/dts/context.d.ts +157 -0
  10. package/dist/dts/debug.d.ts +1 -0
  11. package/dist/dts/hooks.d.ts +20 -0
  12. package/dist/dts/index.d.ts +16 -15
  13. package/dist/dts/index.debug.d.ts +2 -0
  14. package/dist/dts/index.rollup.d.ts +2 -0
  15. package/dist/dts/index.rollup.debug.d.ts +3 -0
  16. package/dist/dts/interfaces.d.ts +145 -0
  17. package/dist/dts/metadata.d.ts +25 -0
  18. package/dist/dts/observation/arrays.d.ts +207 -0
  19. package/dist/dts/observation/behavior.d.ts +4 -4
  20. package/dist/dts/observation/notifier.d.ts +18 -18
  21. package/dist/dts/observation/observable.d.ts +56 -18
  22. package/dist/dts/observation/splice-strategies.d.ts +13 -0
  23. package/dist/dts/observation/update-queue.d.ts +40 -0
  24. package/dist/dts/platform.d.ts +18 -67
  25. package/dist/dts/polyfills.d.ts +8 -0
  26. package/dist/dts/styles/css-directive.d.ts +43 -5
  27. package/dist/dts/styles/css.d.ts +19 -3
  28. package/dist/dts/styles/element-styles.d.ts +42 -62
  29. package/dist/dts/templating/binding-signal.d.ts +38 -0
  30. package/dist/dts/templating/binding-two-way.d.ts +56 -0
  31. package/dist/dts/templating/binding.d.ts +233 -65
  32. package/dist/dts/templating/children.d.ts +18 -15
  33. package/dist/dts/templating/compiler.d.ts +46 -28
  34. package/dist/dts/templating/dom.d.ts +41 -0
  35. package/dist/dts/templating/html-directive.d.ts +181 -43
  36. package/dist/dts/templating/markup.d.ts +48 -0
  37. package/dist/dts/templating/node-observation.d.ts +45 -29
  38. package/dist/dts/templating/ref.d.ts +6 -12
  39. package/dist/dts/templating/repeat.d.ts +26 -14
  40. package/dist/dts/templating/slotted.d.ts +13 -14
  41. package/dist/dts/templating/template.d.ts +27 -21
  42. package/dist/dts/templating/view.d.ts +15 -22
  43. package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
  44. package/dist/dts/utilities.d.ts +40 -0
  45. package/dist/esm/components/attributes.js +25 -24
  46. package/dist/esm/components/controller.js +77 -57
  47. package/dist/esm/components/fast-definitions.js +16 -22
  48. package/dist/esm/components/fast-element.js +10 -2
  49. package/dist/esm/context.js +159 -0
  50. package/dist/esm/debug.js +30 -0
  51. package/dist/esm/hooks.js +32 -0
  52. package/dist/esm/index.debug.js +2 -0
  53. package/dist/esm/index.js +19 -14
  54. package/dist/esm/index.rollup.debug.js +3 -0
  55. package/dist/esm/index.rollup.js +2 -0
  56. package/dist/esm/interfaces.js +8 -1
  57. package/dist/esm/metadata.js +60 -0
  58. package/dist/esm/observation/arrays.js +269 -0
  59. package/dist/esm/observation/notifier.js +27 -35
  60. package/dist/esm/observation/observable.js +93 -68
  61. package/dist/esm/observation/{array-change-records.js → splice-strategies.js} +136 -62
  62. package/dist/esm/observation/update-queue.js +67 -0
  63. package/dist/esm/platform.js +36 -42
  64. package/dist/esm/polyfills.js +85 -0
  65. package/dist/esm/styles/css-directive.js +29 -13
  66. package/dist/esm/styles/css.js +27 -40
  67. package/dist/esm/styles/element-styles.js +65 -104
  68. package/dist/esm/templating/binding-signal.js +84 -0
  69. package/dist/esm/templating/binding-two-way.js +82 -0
  70. package/dist/esm/templating/binding.js +306 -153
  71. package/dist/esm/templating/children.js +33 -23
  72. package/dist/esm/templating/compiler.js +236 -152
  73. package/dist/esm/templating/dom.js +49 -0
  74. package/dist/esm/templating/html-directive.js +128 -40
  75. package/dist/esm/templating/markup.js +75 -0
  76. package/dist/esm/templating/node-observation.js +50 -45
  77. package/dist/esm/templating/ref.js +7 -16
  78. package/dist/esm/templating/repeat.js +39 -36
  79. package/dist/esm/templating/slotted.js +23 -20
  80. package/dist/esm/templating/template.js +51 -95
  81. package/dist/esm/templating/view.js +44 -43
  82. package/dist/esm/templating/when.js +2 -1
  83. package/dist/esm/utilities.js +139 -0
  84. package/dist/fast-element.api.json +11789 -5377
  85. package/dist/fast-element.d.ts +1178 -530
  86. package/dist/fast-element.debug.js +3722 -0
  87. package/dist/fast-element.debug.min.js +1 -0
  88. package/dist/fast-element.js +3484 -4033
  89. package/dist/fast-element.min.js +1 -1
  90. package/dist/fast-element.untrimmed.d.ts +2699 -0
  91. package/docs/api-report.md +472 -219
  92. package/docs/fast-element-2-changes.md +15 -0
  93. package/docs/guide/declaring-templates.md +4 -4
  94. package/docs/guide/defining-elements.md +2 -2
  95. package/docs/guide/next-steps.md +2 -2
  96. package/docs/guide/observables-and-state.md +1 -1
  97. package/docs/guide/using-directives.md +1 -1
  98. package/karma.conf.cjs +6 -17
  99. package/package.json +63 -15
  100. package/dist/dts/dom.d.ts +0 -112
  101. package/dist/dts/observation/array-change-records.d.ts +0 -48
  102. package/dist/dts/observation/array-observer.d.ts +0 -9
  103. package/dist/esm/dom.js +0 -207
  104. package/dist/esm/observation/array-observer.js +0 -177
@@ -1,6 +1,7 @@
1
- import { DOM } from "../dom.js";
1
+ import "../interfaces.js";
2
2
  import { PropertyChangeNotifier } from "../observation/notifier.js";
3
- import { defaultExecutionContext, Observable } from "../observation/observable.js";
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
- return element.shadowRoot || shadowRoots.get(element) || null;
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
- const shadowRoot = element.attachShadow(shadowOptions);
54
- if (shadowOptions.mode === "closed") {
55
- shadowRoots.set(element, shadowRoot);
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, "isConnected");
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, "isConnected");
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 && value !== null) {
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 HTMLStyleElement) {
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 HTMLStyleElement) {
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
- const targetBehaviors = this.behaviors || (this.behaviors = new Map());
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, defaultExecutionContext);
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, defaultExecutionContext);
271
+ this.view.bind(element, context);
226
272
  }
227
273
  const behaviors = this.behaviors;
228
274
  if (behaviors !== null) {
229
- for (const [behavior] of behaviors) {
230
- behavior.bind(element, defaultExecutionContext);
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
- for (const [behavior] of behaviors) {
251
- behavior.unbind(element);
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
- const definition = this.definition;
294
- // 1. Template overrides take top precedence.
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) || 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
- DOM.removeChildNodes(host);
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.forType(element.constructor);
381
+ const definition = FASTElementDefinition.getForInstance(element);
362
382
  if (definition === void 0) {
363
- throw new Error("Missing FASTElement definition.");
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 { FAST } from "../platform.js";
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 fastRegistry = FAST.getById(4 /* elementRegistry */, () => {
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 (typeof nameOrConfig === "string") {
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.create(nameOrConfig.styles)
55
+ ? new ElementStyles(nameOrConfig.styles)
69
56
  : nameOrConfig.styles instanceof ElementStyles
70
57
  ? nameOrConfig.styles
71
- : ElementStyles.create([nameOrConfig.styles]);
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 !!fastRegistry.getByType(this.type);
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 (fastRegistry.register(this)) {
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.forType = fastRegistry.getByType;
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 new FASTElementDefinition(type, nameOrDef).define().type;
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
- new FASTElementDefinition(type, nameOrDef).define();
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
+ }
@@ -0,0 +1,2 @@
1
+ import "./debug.js";
2
+ export * from "./index.js";
package/dist/esm/index.js CHANGED
@@ -1,19 +1,18 @@
1
1
  export * from "./platform.js";
2
- export * from "./templating/template.js";
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 {} from "./observation/array-change-records.js";
15
- export { enableArrayObservation } from "./observation/array-observer.js";
16
- export { DOM } from "./dom.js";
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 { elements, } from "./templating/node-observation.js";
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";
@@ -0,0 +1,3 @@
1
+ import "./polyfills.js";
2
+ import "./debug.js";
3
+ export * from "./index.js";
@@ -0,0 +1,2 @@
1
+ import "./polyfills.js";
2
+ export * from "./index.js";
@@ -1 +1,8 @@
1
- export {};
1
+ /**
2
+ * @internal
3
+ */
4
+ export const isFunction = (object) => typeof object === "function";
5
+ /**
6
+ * @internal
7
+ */
8
+ export const isString = (object) => typeof object === "string";