@microsoft/fast-element 2.0.0-beta.1 → 2.0.0-beta.11

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 (98) hide show
  1. package/CHANGELOG.json +348 -0
  2. package/CHANGELOG.md +114 -1
  3. package/dist/dts/components/attributes.d.ts +10 -0
  4. package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +49 -25
  5. package/dist/dts/components/fast-definitions.d.ts +43 -9
  6. package/dist/dts/components/fast-element.d.ts +15 -21
  7. package/dist/dts/context.d.ts +157 -0
  8. package/dist/dts/di/di.d.ts +899 -0
  9. package/dist/dts/index.d.ts +2 -2
  10. package/dist/dts/interfaces.d.ts +45 -14
  11. package/dist/dts/metadata.d.ts +25 -0
  12. package/dist/dts/observation/arrays.d.ts +1 -1
  13. package/dist/dts/observation/observable.d.ts +101 -75
  14. package/dist/dts/pending-task.d.ts +20 -0
  15. package/dist/dts/platform.d.ts +7 -0
  16. package/dist/dts/polyfills.d.ts +1 -8
  17. package/dist/dts/state/exports.d.ts +3 -0
  18. package/dist/dts/state/reactive.d.ts +8 -0
  19. package/dist/dts/state/state.d.ts +141 -0
  20. package/dist/dts/state/visitor.d.ts +6 -0
  21. package/dist/dts/state/watch.d.ts +10 -0
  22. package/dist/dts/styles/css-directive.d.ts +2 -2
  23. package/dist/dts/styles/element-styles.d.ts +10 -17
  24. package/dist/dts/styles/host.d.ts +68 -0
  25. package/dist/dts/templating/binding-signal.d.ts +21 -0
  26. package/dist/dts/templating/binding-two-way.d.ts +39 -0
  27. package/dist/dts/templating/binding.d.ts +69 -294
  28. package/dist/dts/templating/children.d.ts +1 -1
  29. package/dist/dts/templating/compiler.d.ts +1 -2
  30. package/dist/dts/templating/html-directive.d.ts +93 -35
  31. package/dist/dts/templating/node-observation.d.ts +4 -5
  32. package/dist/dts/templating/ref.d.ts +5 -13
  33. package/dist/dts/templating/render.d.ts +272 -0
  34. package/dist/dts/templating/repeat.d.ts +20 -75
  35. package/dist/dts/templating/slotted.d.ts +1 -1
  36. package/dist/dts/templating/template.d.ts +12 -61
  37. package/dist/dts/templating/view.d.ts +77 -12
  38. package/dist/dts/templating/when.d.ts +3 -3
  39. package/dist/dts/testing/exports.d.ts +3 -0
  40. package/dist/dts/testing/fakes.d.ts +4 -0
  41. package/dist/dts/testing/fixture.d.ts +84 -0
  42. package/dist/dts/testing/timeout.d.ts +7 -0
  43. package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +0 -0
  44. package/dist/dts/utilities.d.ts +0 -18
  45. package/dist/esm/components/attributes.js +13 -4
  46. package/dist/esm/components/{controller.js → element-controller.js} +188 -109
  47. package/dist/esm/components/fast-definitions.js +38 -28
  48. package/dist/esm/components/fast-element.js +31 -12
  49. package/dist/esm/context.js +163 -0
  50. package/dist/esm/debug.js +36 -4
  51. package/dist/esm/di/di.js +1435 -0
  52. package/dist/esm/index.js +2 -1
  53. package/dist/esm/interfaces.js +4 -0
  54. package/dist/esm/metadata.js +60 -0
  55. package/dist/esm/observation/arrays.js +304 -3
  56. package/dist/esm/observation/observable.js +81 -87
  57. package/dist/esm/pending-task.js +16 -0
  58. package/dist/esm/platform.js +26 -1
  59. package/dist/esm/polyfills.js +1 -55
  60. package/dist/esm/state/exports.js +3 -0
  61. package/dist/esm/state/reactive.js +34 -0
  62. package/dist/esm/state/state.js +148 -0
  63. package/dist/esm/state/visitor.js +28 -0
  64. package/dist/esm/state/watch.js +36 -0
  65. package/dist/esm/styles/css.js +4 -4
  66. package/dist/esm/styles/element-styles.js +14 -33
  67. package/dist/esm/{observation/behavior.js → styles/host.js} +0 -0
  68. package/dist/esm/templating/binding-signal.js +83 -0
  69. package/dist/esm/templating/binding-two-way.js +103 -0
  70. package/dist/esm/templating/binding.js +134 -414
  71. package/dist/esm/templating/compiler.js +30 -7
  72. package/dist/esm/templating/html-directive.js +100 -28
  73. package/dist/esm/templating/node-observation.js +9 -8
  74. package/dist/esm/templating/ref.js +4 -12
  75. package/dist/esm/templating/render.js +391 -0
  76. package/dist/esm/templating/repeat.js +96 -72
  77. package/dist/esm/templating/template.js +11 -29
  78. package/dist/esm/templating/view.js +107 -29
  79. package/dist/esm/templating/when.js +5 -4
  80. package/dist/esm/testing/exports.js +3 -0
  81. package/dist/esm/testing/fakes.js +76 -0
  82. package/dist/esm/testing/fixture.js +86 -0
  83. package/dist/esm/testing/timeout.js +24 -0
  84. package/dist/esm/utilities.js +0 -95
  85. package/dist/fast-element.api.json +9278 -10745
  86. package/dist/fast-element.d.ts +707 -813
  87. package/dist/fast-element.debug.js +1229 -944
  88. package/dist/fast-element.debug.min.js +1 -1
  89. package/dist/fast-element.js +1191 -938
  90. package/dist/fast-element.min.js +1 -1
  91. package/dist/fast-element.untrimmed.d.ts +716 -824
  92. package/docs/api-report.md +265 -319
  93. package/package.json +39 -14
  94. package/dist/dts/hooks.d.ts +0 -20
  95. package/dist/dts/observation/behavior.d.ts +0 -19
  96. package/dist/dts/observation/splice-strategies.d.ts +0 -13
  97. package/dist/esm/hooks.js +0 -32
  98. package/dist/esm/observation/splice-strategies.js +0 -400
@@ -1,7 +1,7 @@
1
- import { isString } from "../interfaces.js";
1
+ import { isFunction, isString } from "../interfaces.js";
2
2
  import { FAST } from "../platform.js";
3
3
  import { Parser } from "./markup.js";
4
- import { bind, oneTime } from "./binding.js";
4
+ import { HTMLBindingDirective, oneTime } from "./binding.js";
5
5
  import { Aspect } from "./html-directive.js";
6
6
  import { HTMLView } from "./view.js";
7
7
  const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
@@ -11,6 +11,22 @@ const next = {
11
11
  index: 0,
12
12
  node: null,
13
13
  };
14
+ function tryWarn(name) {
15
+ if (!name.startsWith("fast-")) {
16
+ FAST.warn(1204 /* Message.hostBindingWithoutHost */, { name });
17
+ }
18
+ }
19
+ const warningHost = new Proxy(document.createElement("div"), {
20
+ get(target, property) {
21
+ tryWarn(property);
22
+ const value = Reflect.get(target, property);
23
+ return isFunction(value) ? value.bind(target) : value;
24
+ },
25
+ set(target, property, value) {
26
+ tryWarn(property);
27
+ return Reflect.set(target, property, value);
28
+ },
29
+ });
14
30
  class CompilationContext {
15
31
  constructor(fragment, directives) {
16
32
  this.fragment = fragment;
@@ -61,7 +77,7 @@ class CompilationContext {
61
77
  const fragment = this.fragment.cloneNode(true);
62
78
  const targets = Object.create(this.proto);
63
79
  targets.r = fragment;
64
- targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : fragment;
80
+ targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : warningHost;
65
81
  for (const id of this.nodeIds) {
66
82
  targets[id]; // trigger locator
67
83
  }
@@ -78,7 +94,7 @@ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBa
78
94
  let result = null;
79
95
  if (parseResult === null) {
80
96
  if (includeBasicValues) {
81
- result = bind(() => attrValue, oneTime);
97
+ result = new HTMLBindingDirective(oneTime(() => attrValue));
82
98
  Aspect.assign(result, attr.name);
83
99
  }
84
100
  }
@@ -115,6 +131,7 @@ function compileContent(context, node, parentId, nodeId, nodeIndex) {
115
131
  }
116
132
  else {
117
133
  currentNode.textContent = " ";
134
+ Aspect.assign(currentPart);
118
135
  context.addFactory(currentPart, parentId, nodeId, nodeIndex);
119
136
  }
120
137
  lastNode = currentNode;
@@ -247,22 +264,28 @@ export const Compiler = {
247
264
  return parts[0];
248
265
  }
249
266
  let sourceAspect;
267
+ let binding;
268
+ let isVolatile = false;
250
269
  const partCount = parts.length;
251
270
  const finalParts = parts.map((x) => {
252
271
  if (isString(x)) {
253
272
  return () => x;
254
273
  }
255
274
  sourceAspect = x.sourceAspect || sourceAspect;
256
- return x.binding;
275
+ binding = x.dataBinding || binding;
276
+ isVolatile = isVolatile || x.dataBinding.isVolatile;
277
+ return x.dataBinding.evaluate;
257
278
  });
258
- const binding = (scope, context) => {
279
+ const expression = (scope, context) => {
259
280
  let output = "";
260
281
  for (let i = 0; i < partCount; ++i) {
261
282
  output += finalParts[i](scope, context);
262
283
  }
263
284
  return output;
264
285
  };
265
- const directive = bind(binding);
286
+ binding.evaluate = expression;
287
+ binding.isVolatile = isVolatile;
288
+ const directive = new HTMLBindingDirective(binding);
266
289
  Aspect.assign(directive, sourceAspect);
267
290
  return directive;
268
291
  },
@@ -1,5 +1,67 @@
1
+ import { ExecutionContext, } from "../observation/observable.js";
1
2
  import { createTypeRegistry } from "../platform.js";
2
- import { Markup } from "./markup.js";
3
+ import { Markup, nextId } from "./markup.js";
4
+ /**
5
+ * Bridges between ViewBehaviors and HostBehaviors, enabling a host to
6
+ * control ViewBehaviors.
7
+ * @public
8
+ */
9
+ export const ViewBehaviorOrchestrator = Object.freeze({
10
+ /**
11
+ * Creates a ViewBehaviorOrchestrator.
12
+ * @param source - The source to to associate behaviors with.
13
+ * @returns A ViewBehaviorOrchestrator.
14
+ */
15
+ create(source) {
16
+ const behaviors = [];
17
+ const targets = {};
18
+ let unbindables = null;
19
+ let isConnected = false;
20
+ return {
21
+ source,
22
+ context: ExecutionContext.default,
23
+ targets,
24
+ get isBound() {
25
+ return isConnected;
26
+ },
27
+ addBehaviorFactory(factory, target) {
28
+ const nodeId = factory.nodeId || (factory.nodeId = nextId());
29
+ factory.id || (factory.id = nextId());
30
+ this.addTarget(nodeId, target);
31
+ this.addBehavior(factory.createBehavior());
32
+ },
33
+ addTarget(nodeId, target) {
34
+ targets[nodeId] = target;
35
+ },
36
+ addBehavior(behavior) {
37
+ behaviors.push(behavior);
38
+ if (isConnected) {
39
+ behavior.bind(this);
40
+ }
41
+ },
42
+ onUnbind(unbindable) {
43
+ if (unbindables === null) {
44
+ unbindables = [];
45
+ }
46
+ unbindables.push(unbindable);
47
+ },
48
+ connectedCallback(controller) {
49
+ if (!isConnected) {
50
+ isConnected = true;
51
+ behaviors.forEach(x => x.bind(this));
52
+ }
53
+ },
54
+ disconnectedCallback(controller) {
55
+ if (isConnected) {
56
+ isConnected = false;
57
+ if (unbindables !== null) {
58
+ unbindables.forEach(x => x.unbind(this));
59
+ }
60
+ }
61
+ },
62
+ };
63
+ },
64
+ });
3
65
  const registry = createTypeRegistry();
4
66
  /**
5
67
  * Instructs the template engine to apply behavior to a node.
@@ -39,6 +101,22 @@ export function htmlDirective(options) {
39
101
  HTMLDirective.define(type, options);
40
102
  };
41
103
  }
104
+ /**
105
+ * Captures a binding expression along with related information and capabilities.
106
+ *
107
+ * @public
108
+ */
109
+ export class Binding {
110
+ /**
111
+ * Creates a binding.
112
+ * @param evaluate - Evaluates the binding.
113
+ * @param isVolatile - Indicates whether the binding is volatile.
114
+ */
115
+ constructor(evaluate, isVolatile = false) {
116
+ this.evaluate = evaluate;
117
+ this.isVolatile = isVolatile;
118
+ }
119
+ }
42
120
  /**
43
121
  * The type of HTML aspect to target.
44
122
  * @public
@@ -76,26 +154,22 @@ export const Aspect = Object.freeze({
76
154
  *
77
155
  * @param directive - The directive to assign the aspect to.
78
156
  * @param value - The value to base the aspect determination on.
157
+ * @remarks
158
+ * If a falsy value is provided, then the content aspect will be assigned.
79
159
  */
80
160
  assign(directive, value) {
81
- directive.sourceAspect = value;
82
161
  if (!value) {
162
+ directive.aspectType = Aspect.content;
83
163
  return;
84
164
  }
165
+ directive.sourceAspect = value;
85
166
  switch (value[0]) {
86
167
  case ":":
87
168
  directive.targetAspect = value.substring(1);
88
- switch (directive.targetAspect) {
89
- case "innerHTML":
90
- directive.aspectType = Aspect.property;
91
- break;
92
- case "classList":
93
- directive.aspectType = Aspect.tokenList;
94
- break;
95
- default:
96
- directive.aspectType = Aspect.property;
97
- break;
98
- }
169
+ directive.aspectType =
170
+ directive.targetAspect === "classList"
171
+ ? Aspect.tokenList
172
+ : Aspect.property;
99
173
  break;
100
174
  case "?":
101
175
  directive.targetAspect = value.substring(1);
@@ -106,14 +180,8 @@ export const Aspect = Object.freeze({
106
180
  directive.aspectType = Aspect.event;
107
181
  break;
108
182
  default:
109
- if (value === "class") {
110
- directive.targetAspect = "className";
111
- directive.aspectType = Aspect.property;
112
- }
113
- else {
114
- directive.targetAspect = value;
115
- directive.aspectType = Aspect.attribute;
116
- }
183
+ directive.targetAspect = value;
184
+ directive.aspectType = Aspect.attribute;
117
185
  break;
118
186
  }
119
187
  },
@@ -129,13 +197,10 @@ export class StatelessAttachedAttributeDirective {
129
197
  */
130
198
  constructor(options) {
131
199
  this.options = options;
132
- }
133
- /**
134
- * Creates a behavior.
135
- * @param targets - The targets available for behaviors to be attached to.
136
- */
137
- createBehavior(targets) {
138
- return this;
200
+ /**
201
+ * The unique id of the factory.
202
+ */
203
+ this.id = nextId();
139
204
  }
140
205
  /**
141
206
  * Creates a placeholder string based on the directive's index within the template.
@@ -146,4 +211,11 @@ export class StatelessAttachedAttributeDirective {
146
211
  createHTML(add) {
147
212
  return Markup.attribute(add(this));
148
213
  }
214
+ /**
215
+ * Creates a behavior.
216
+ * @param targets - The targets available for behaviors to be attached to.
217
+ */
218
+ createBehavior() {
219
+ return this;
220
+ }
149
221
  }
@@ -1,5 +1,5 @@
1
1
  import { emptyArray } from "../platform.js";
2
- import { StatelessAttachedAttributeDirective, } from "./html-directive.js";
2
+ import { StatelessAttachedAttributeDirective } from "./html-directive.js";
3
3
  const selectElements = (value) => value.nodeType === 1;
4
4
  /**
5
5
  * Creates a function that can be used to filter a Node array, selecting only elements.
@@ -26,11 +26,12 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
26
26
  * @param context - The execution context that the binding is operating within.
27
27
  * @param targets - The targets that behaviors in a view can attach to.
28
28
  */
29
- bind(source, context, targets) {
30
- const target = targets[this.nodeId];
31
- target[this.sourceProperty] = source;
32
- this.updateTarget(source, this.computeNodes(target));
29
+ bind(controller) {
30
+ const target = controller.targets[this.nodeId];
31
+ target[this.sourceProperty] = controller.source;
32
+ this.updateTarget(controller.source, this.computeNodes(target));
33
33
  this.observe(target);
34
+ controller.onUnbind(this);
34
35
  }
35
36
  /**
36
37
  * Unbinds this behavior from the source.
@@ -38,9 +39,9 @@ export class NodeObservationDirective extends StatelessAttachedAttributeDirectiv
38
39
  * @param context - The execution context that the binding is operating within.
39
40
  * @param targets - The targets that behaviors in a view can attach to.
40
41
  */
41
- unbind(source, context, targets) {
42
- const target = targets[this.nodeId];
43
- this.updateTarget(source, emptyArray);
42
+ unbind(controller) {
43
+ const target = controller.targets[this.nodeId];
44
+ this.updateTarget(controller.source, emptyArray);
44
45
  this.disconnect(target);
45
46
  target[this.sourceProperty] = null;
46
47
  }
@@ -5,20 +5,12 @@ import { HTMLDirective, StatelessAttachedAttributeDirective, } from "./html-dire
5
5
  */
6
6
  export class RefDirective extends StatelessAttachedAttributeDirective {
7
7
  /**
8
- * Bind this behavior to the source.
9
- * @param source - The source to bind to.
10
- * @param context - The execution context that the binding is operating within.
11
- * @param targets - The targets that behaviors in a view can attach to.
8
+ * Bind this behavior.
9
+ * @param controller - The view controller that manages the lifecycle of this behavior.
12
10
  */
13
- bind(source, context, targets) {
14
- source[this.options] = targets[this.nodeId];
11
+ bind(controller) {
12
+ controller.source[this.options] = controller.targets[this.nodeId];
15
13
  }
16
- /**
17
- * Unbinds this behavior from the source.
18
- * @param source - The source to unbind from.
19
- */
20
- /* eslint-disable-next-line @typescript-eslint/no-empty-function */
21
- unbind() { }
22
14
  }
23
15
  HTMLDirective.define(RefDirective);
24
16
  /**