@microsoft/fast-element 2.0.0-beta.2 → 2.0.0-beta.20

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 (113) hide show
  1. package/CHANGELOG.json +488 -0
  2. package/CHANGELOG.md +180 -1
  3. package/dist/dts/components/attributes.d.ts +15 -0
  4. package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +74 -28
  5. package/dist/dts/components/fast-definitions.d.ts +41 -9
  6. package/dist/dts/components/fast-element.d.ts +14 -26
  7. package/dist/dts/components/hydration.d.ts +14 -0
  8. package/dist/{esm/observation/behavior.js → dts/components/install-hydration.d.ts} +0 -0
  9. package/dist/dts/context.d.ts +1 -1
  10. package/dist/dts/di/di.d.ts +894 -0
  11. package/dist/dts/dom-policy.d.ts +68 -0
  12. package/dist/dts/dom.d.ts +100 -0
  13. package/dist/dts/index.d.ts +5 -4
  14. package/dist/dts/index.rollup.d.ts +0 -1
  15. package/dist/dts/index.rollup.debug.d.ts +0 -1
  16. package/dist/dts/interfaces.d.ts +60 -79
  17. package/dist/dts/observation/observable.d.ts +99 -54
  18. package/dist/dts/pending-task.d.ts +20 -0
  19. package/dist/dts/platform.d.ts +7 -0
  20. package/dist/dts/polyfills.d.ts +0 -8
  21. package/dist/dts/state/exports.d.ts +3 -0
  22. package/dist/dts/state/reactive.d.ts +8 -0
  23. package/dist/dts/state/state.d.ts +141 -0
  24. package/dist/dts/state/visitor.d.ts +6 -0
  25. package/dist/dts/state/watch.d.ts +10 -0
  26. package/dist/dts/styles/css-directive.d.ts +2 -2
  27. package/dist/dts/styles/css.d.ts +0 -5
  28. package/dist/dts/styles/element-styles.d.ts +10 -17
  29. package/dist/dts/styles/host.d.ts +68 -0
  30. package/dist/dts/styles/style-strategy.d.ts +42 -0
  31. package/dist/dts/templating/binding-signal.d.ts +12 -27
  32. package/dist/dts/templating/binding-two-way.d.ts +22 -37
  33. package/dist/dts/templating/binding.d.ts +76 -208
  34. package/dist/dts/templating/children.d.ts +1 -1
  35. package/dist/dts/templating/compiler.d.ts +11 -13
  36. package/dist/dts/templating/html-directive.d.ts +91 -97
  37. package/dist/dts/templating/node-observation.d.ts +15 -6
  38. package/dist/dts/templating/ref.d.ts +7 -11
  39. package/dist/dts/templating/render.d.ts +296 -0
  40. package/dist/dts/templating/repeat.d.ts +23 -34
  41. package/dist/dts/templating/slotted.d.ts +1 -1
  42. package/dist/dts/templating/template.d.ts +92 -14
  43. package/dist/dts/templating/view.d.ts +81 -11
  44. package/dist/dts/templating/when.d.ts +3 -3
  45. package/dist/dts/testing/exports.d.ts +3 -0
  46. package/dist/dts/testing/fakes.d.ts +14 -0
  47. package/dist/dts/testing/fixture.d.ts +84 -0
  48. package/dist/dts/testing/timeout.d.ts +7 -0
  49. package/dist/dts/utilities.d.ts +53 -18
  50. package/dist/esm/components/attributes.js +28 -5
  51. package/dist/esm/components/{controller.js → element-controller.js} +239 -137
  52. package/dist/esm/components/fast-definitions.js +38 -30
  53. package/dist/esm/components/fast-element.js +27 -16
  54. package/dist/esm/components/hydration.js +35 -0
  55. package/dist/esm/components/install-hydration.js +2 -0
  56. package/dist/esm/context.js +5 -1
  57. package/dist/esm/debug.js +40 -5
  58. package/dist/esm/di/di.js +1430 -0
  59. package/dist/esm/dom-policy.js +337 -0
  60. package/dist/esm/dom.js +101 -0
  61. package/dist/esm/index.js +4 -2
  62. package/dist/esm/index.rollup.debug.js +3 -1
  63. package/dist/esm/index.rollup.js +3 -1
  64. package/dist/esm/interfaces.js +52 -0
  65. package/dist/esm/observation/arrays.js +303 -2
  66. package/dist/esm/observation/observable.js +88 -142
  67. package/dist/esm/observation/update-queue.js +2 -2
  68. package/dist/esm/pending-task.js +16 -0
  69. package/dist/esm/platform.js +27 -2
  70. package/dist/esm/polyfills.js +3 -61
  71. package/dist/esm/state/exports.js +3 -0
  72. package/dist/esm/state/reactive.js +34 -0
  73. package/dist/esm/state/state.js +148 -0
  74. package/dist/esm/state/visitor.js +28 -0
  75. package/dist/esm/state/watch.js +36 -0
  76. package/dist/esm/styles/css.js +4 -9
  77. package/dist/esm/styles/element-styles.js +14 -33
  78. package/dist/esm/styles/host.js +1 -0
  79. package/dist/esm/styles/style-strategy.js +1 -0
  80. package/dist/esm/templating/binding-signal.js +67 -62
  81. package/dist/esm/templating/binding-two-way.js +72 -39
  82. package/dist/esm/templating/binding.js +142 -286
  83. package/dist/esm/templating/children.js +8 -4
  84. package/dist/esm/templating/compiler.js +59 -43
  85. package/dist/esm/templating/html-directive.js +56 -75
  86. package/dist/esm/templating/node-observation.js +20 -13
  87. package/dist/esm/templating/ref.js +4 -12
  88. package/dist/esm/templating/render.js +402 -0
  89. package/dist/esm/templating/repeat.js +88 -75
  90. package/dist/esm/templating/template.js +132 -60
  91. package/dist/esm/templating/view.js +113 -29
  92. package/dist/esm/templating/when.js +5 -4
  93. package/dist/esm/testing/exports.js +3 -0
  94. package/dist/esm/testing/fakes.js +107 -0
  95. package/dist/esm/testing/fixture.js +86 -0
  96. package/dist/esm/testing/timeout.js +24 -0
  97. package/dist/esm/utilities.js +95 -95
  98. package/dist/fast-element.api.json +9487 -8326
  99. package/dist/fast-element.d.ts +847 -644
  100. package/dist/fast-element.debug.js +1993 -1166
  101. package/dist/fast-element.debug.min.js +1 -1
  102. package/dist/fast-element.js +1903 -1111
  103. package/dist/fast-element.min.js +1 -1
  104. package/dist/fast-element.untrimmed.d.ts +911 -701
  105. package/docs/api-report.md +329 -252
  106. package/package.json +38 -16
  107. package/dist/dts/hooks.d.ts +0 -20
  108. package/dist/dts/observation/behavior.d.ts +0 -19
  109. package/dist/dts/observation/splice-strategies.d.ts +0 -13
  110. package/dist/dts/templating/dom.d.ts +0 -41
  111. package/dist/esm/hooks.js +0 -32
  112. package/dist/esm/observation/splice-strategies.js +0 -400
  113. package/dist/esm/templating/dom.js +0 -49
@@ -0,0 +1,402 @@
1
+ import { FASTElementDefinition } from "../components/fast-definitions.js";
2
+ import { isFunction, isString } from "../interfaces.js";
3
+ import { bind, normalizeBinding, oneTime, } from "./binding.js";
4
+ import { Binding, HTMLDirective, } from "./html-directive.js";
5
+ import { Markup } from "./markup.js";
6
+ import { html, ViewTemplate, } from "./template.js";
7
+ /**
8
+ * A Behavior that enables advanced rendering.
9
+ * @public
10
+ */
11
+ export class RenderBehavior {
12
+ /**
13
+ * Creates an instance of RenderBehavior.
14
+ * @param directive - The render directive that created this behavior.
15
+ */
16
+ constructor(directive) {
17
+ this.directive = directive;
18
+ this.location = null;
19
+ this.controller = null;
20
+ this.view = null;
21
+ this.data = null;
22
+ this.dataBindingObserver = directive.dataBinding.createObserver(directive, this);
23
+ this.templateBindingObserver = directive.templateBinding.createObserver(directive, this);
24
+ }
25
+ /**
26
+ * Bind this behavior.
27
+ * @param controller - The view controller that manages the lifecycle of this behavior.
28
+ */
29
+ bind(controller) {
30
+ this.location = controller.targets[this.directive.targetNodeId];
31
+ this.controller = controller;
32
+ this.data = this.dataBindingObserver.bind(controller);
33
+ this.template = this.templateBindingObserver.bind(controller);
34
+ controller.onUnbind(this);
35
+ this.refreshView();
36
+ }
37
+ /**
38
+ * Unbinds this behavior.
39
+ * @param controller - The view controller that manages the lifecycle of this behavior.
40
+ */
41
+ unbind(controller) {
42
+ const view = this.view;
43
+ if (view !== null && view.isComposed) {
44
+ view.unbind();
45
+ view.needsBindOnly = true;
46
+ }
47
+ }
48
+ /** @internal */
49
+ handleChange(source, observer) {
50
+ if (observer === this.dataBindingObserver) {
51
+ this.data = this.dataBindingObserver.bind(this.controller);
52
+ }
53
+ if (this.directive.templateBindingDependsOnData ||
54
+ observer === this.templateBindingObserver) {
55
+ this.template = this.templateBindingObserver.bind(this.controller);
56
+ }
57
+ this.refreshView();
58
+ }
59
+ refreshView() {
60
+ let view = this.view;
61
+ const template = this.template;
62
+ if (view === null) {
63
+ this.view = view = template.create();
64
+ this.view.context.parent = this.controller.source;
65
+ this.view.context.parentContext = this.controller.context;
66
+ }
67
+ else {
68
+ // If there is a previous view, but it wasn't created
69
+ // from the same template as the new value, then we
70
+ // need to remove the old view if it's still in the DOM
71
+ // and create a new view from the template.
72
+ if (view.$fastTemplate !== template) {
73
+ if (view.isComposed) {
74
+ view.remove();
75
+ view.unbind();
76
+ }
77
+ this.view = view = template.create();
78
+ this.view.context.parent = this.controller.source;
79
+ this.view.context.parentContext = this.controller.context;
80
+ }
81
+ }
82
+ // It's possible that the value is the same as the previous template
83
+ // and that there's actually no need to compose it.
84
+ if (!view.isComposed) {
85
+ view.isComposed = true;
86
+ view.bind(this.data);
87
+ view.insertBefore(this.location);
88
+ view.$fastTemplate = template;
89
+ }
90
+ else if (view.needsBindOnly) {
91
+ view.needsBindOnly = false;
92
+ view.bind(this.data);
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * A Directive that enables use of the RenderBehavior.
98
+ * @public
99
+ */
100
+ export class RenderDirective {
101
+ /**
102
+ * Creates an instance of RenderDirective.
103
+ * @param dataBinding - A binding expression that returns the data to render.
104
+ * @param templateBinding - A binding expression that returns the template to use to render the data.
105
+ */
106
+ constructor(dataBinding, templateBinding, templateBindingDependsOnData) {
107
+ this.dataBinding = dataBinding;
108
+ this.templateBinding = templateBinding;
109
+ this.templateBindingDependsOnData = templateBindingDependsOnData;
110
+ }
111
+ /**
112
+ * Creates HTML to be used within a template.
113
+ * @param add - Can be used to add behavior factories to a template.
114
+ */
115
+ createHTML(add) {
116
+ return Markup.comment(add(this));
117
+ }
118
+ /**
119
+ * Creates a behavior.
120
+ * @param targets - The targets available for behaviors to be attached to.
121
+ */
122
+ createBehavior() {
123
+ return new RenderBehavior(this);
124
+ }
125
+ }
126
+ HTMLDirective.define(RenderDirective);
127
+ function isElementRenderOptions(object) {
128
+ return !!object.element || !!object.tagName;
129
+ }
130
+ const typeToInstructionLookup = new Map();
131
+ /* eslint @typescript-eslint/naming-convention: "off"*/
132
+ const defaultAttributes = { ":model": x => x };
133
+ const brand = Symbol("RenderInstruction");
134
+ const defaultViewName = "default-view";
135
+ const nullTemplate = html `
136
+  
137
+ `;
138
+ function instructionToTemplate(def) {
139
+ if (def === void 0) {
140
+ return nullTemplate;
141
+ }
142
+ return def.template;
143
+ }
144
+ function createElementTemplate(tagName, attributes, content, policy) {
145
+ const markup = [];
146
+ const values = [];
147
+ if (attributes) {
148
+ const attrNames = Object.getOwnPropertyNames(attributes);
149
+ markup.push(`<${tagName}`);
150
+ for (let i = 0, ii = attrNames.length; i < ii; ++i) {
151
+ const name = attrNames[i];
152
+ if (i === 0) {
153
+ markup[0] = `${markup[0]} ${name}="`;
154
+ }
155
+ else {
156
+ markup.push(`" ${name}="`);
157
+ }
158
+ values.push(attributes[name]);
159
+ }
160
+ markup.push(`">`);
161
+ }
162
+ else {
163
+ markup.push(`<${tagName}>`);
164
+ }
165
+ if (content && isFunction(content.create)) {
166
+ values.push(content);
167
+ markup.push(`</${tagName}>`);
168
+ }
169
+ else {
170
+ const lastIndex = markup.length - 1;
171
+ markup[lastIndex] = `${markup[lastIndex]}${content !== null && content !== void 0 ? content : ""}</${tagName}>`;
172
+ }
173
+ return ViewTemplate.create(markup, values, policy);
174
+ }
175
+ function create(options) {
176
+ var _a, _b;
177
+ const name = (_a = options.name) !== null && _a !== void 0 ? _a : defaultViewName;
178
+ let template;
179
+ if (isElementRenderOptions(options)) {
180
+ let tagName = options.tagName;
181
+ if (!tagName) {
182
+ const def = FASTElementDefinition.getByType(options.element);
183
+ if (def) {
184
+ tagName = def.name;
185
+ }
186
+ else {
187
+ throw new Error("Invalid element for model rendering.");
188
+ }
189
+ }
190
+ template = createElementTemplate(tagName, (_b = options.attributes) !== null && _b !== void 0 ? _b : defaultAttributes, options.content, options.policy);
191
+ }
192
+ else {
193
+ template = options.template;
194
+ }
195
+ return {
196
+ brand,
197
+ type: options.type,
198
+ name,
199
+ template,
200
+ };
201
+ }
202
+ function instanceOf(object) {
203
+ return object && object.brand === brand;
204
+ }
205
+ function register(optionsOrInstruction) {
206
+ let lookup = typeToInstructionLookup.get(optionsOrInstruction.type);
207
+ if (lookup === void 0) {
208
+ typeToInstructionLookup.set(optionsOrInstruction.type, (lookup = Object.create(null)));
209
+ }
210
+ const instruction = instanceOf(optionsOrInstruction)
211
+ ? optionsOrInstruction
212
+ : create(optionsOrInstruction);
213
+ return (lookup[instruction.name] = instruction);
214
+ }
215
+ function getByType(type, name) {
216
+ const entries = typeToInstructionLookup.get(type);
217
+ if (entries === void 0) {
218
+ return void 0;
219
+ }
220
+ return entries[name !== null && name !== void 0 ? name : defaultViewName];
221
+ }
222
+ function getForInstance(object, name) {
223
+ if (object) {
224
+ return getByType(object.constructor, name);
225
+ }
226
+ return void 0;
227
+ }
228
+ /**
229
+ * Provides APIs for creating and interacting with render instructions.
230
+ * @public
231
+ */
232
+ export const RenderInstruction = Object.freeze({
233
+ /**
234
+ * Checks whether the provided object is a RenderInstruction.
235
+ * @param object - The object to check.
236
+ * @returns true if the object is a RenderInstruction; false otherwise
237
+ */
238
+ instanceOf,
239
+ /**
240
+ * Creates a RenderInstruction for a set of options.
241
+ * @param options - The options to use when creating the RenderInstruction.
242
+ * @remarks
243
+ * This API should be used with caution. When providing attributes or content,
244
+ * if not done properly, you can open up the application to XSS attacks. When using this API,
245
+ * provide a strong DOMPolicy that can properly sanitize and also be sure to manually sanitize
246
+ * content and attribute values particularly if they can come from user input.
247
+ */
248
+ create,
249
+ /**
250
+ * Creates a template based on a tag name.
251
+ * @param tagName - The tag name to use when creating the template.
252
+ * @param attributes - The attributes to apply to the element.
253
+ * @param content - The content to insert into the element.
254
+ * @param policy - The DOMPolicy to create the template with.
255
+ * @returns A template based on the provided specifications.
256
+ * @remarks
257
+ * This API should be used with caution. When providing attributes or content,
258
+ * if not done properly, you can open up the application to XSS attacks. When using this API,
259
+ * provide a strong DOMPolicy that can properly sanitize and also be sure to manually sanitize
260
+ * content and attribute values particularly if they can come from user input.
261
+ */
262
+ createElementTemplate,
263
+ /**
264
+ * Creates and registers an instruction.
265
+ * @param options The options to use when creating the RenderInstruction.
266
+ * @remarks
267
+ * A previously created RenderInstruction can also be registered.
268
+ */
269
+ register,
270
+ /**
271
+ * Finds a previously registered RenderInstruction by type and optionally by name.
272
+ * @param type - The type to retrieve the RenderInstruction for.
273
+ * @param name - An optional name used in differentiating between multiple registered instructions.
274
+ * @returns The located RenderInstruction that matches the criteria or undefined if none is found.
275
+ */
276
+ getByType,
277
+ /**
278
+ * Finds a previously registered RenderInstruction for the instance's type and optionally by name.
279
+ * @param object - The instance to retrieve the RenderInstruction for.
280
+ * @param name - An optional name used in differentiating between multiple registered instructions.
281
+ * @returns The located RenderInstruction that matches the criteria or undefined if none is found.
282
+ */
283
+ getForInstance,
284
+ });
285
+ export function renderWith(value, name) {
286
+ return function (type) {
287
+ if (isFunction(value)) {
288
+ register({ type, element: value, name });
289
+ }
290
+ else if (isFunction(value.create)) {
291
+ register({ type, template: value, name });
292
+ }
293
+ else {
294
+ register(Object.assign({ type }, value));
295
+ }
296
+ };
297
+ }
298
+ /**
299
+ * @internal
300
+ */
301
+ export class NodeTemplate {
302
+ constructor(node) {
303
+ this.node = node;
304
+ node.$fastTemplate = this;
305
+ }
306
+ get context() {
307
+ // HACK
308
+ return this;
309
+ }
310
+ bind(source) { }
311
+ unbind() { }
312
+ insertBefore(refNode) {
313
+ refNode.parentNode.insertBefore(this.node, refNode);
314
+ }
315
+ remove() {
316
+ this.node.parentNode.removeChild(this.node);
317
+ }
318
+ create() {
319
+ return this;
320
+ }
321
+ }
322
+ /**
323
+ * Creates a RenderDirective for use in advanced rendering scenarios.
324
+ * @param value - The binding expression that returns the data to be rendered. The expression
325
+ * can also return a Node to render directly.
326
+ * @param template - A template to render the data with
327
+ * or a string to indicate which RenderInstruction to use when looking up a RenderInstruction.
328
+ * Expressions can also be provided to dynamically determine either the template or the name.
329
+ * @returns A RenderDirective suitable for use in a template.
330
+ * @remarks
331
+ * If no binding is provided, then a default binding that returns the source is created.
332
+ * If no template is provided, then a binding is created that will use registered
333
+ * RenderInstructions to determine the view.
334
+ * If the template binding returns a string, then it will be used to look up a
335
+ * RenderInstruction to determine the view.
336
+ * @public
337
+ */
338
+ export function render(value, template) {
339
+ let dataBinding;
340
+ if (value === void 0) {
341
+ dataBinding = oneTime((source) => source);
342
+ }
343
+ else {
344
+ dataBinding = normalizeBinding(value);
345
+ }
346
+ let templateBinding;
347
+ let templateBindingDependsOnData = false;
348
+ if (template === void 0) {
349
+ templateBindingDependsOnData = true;
350
+ templateBinding = oneTime((s, c) => {
351
+ var _a;
352
+ const data = dataBinding.evaluate(s, c);
353
+ if (data instanceof Node) {
354
+ return (_a = data.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(data);
355
+ }
356
+ return instructionToTemplate(getForInstance(data));
357
+ });
358
+ }
359
+ else if (isFunction(template)) {
360
+ templateBinding = bind((s, c) => {
361
+ var _a;
362
+ let result = template(s, c);
363
+ if (isString(result)) {
364
+ result = instructionToTemplate(getForInstance(dataBinding.evaluate(s, c), result));
365
+ }
366
+ else if (result instanceof Node) {
367
+ result = (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
368
+ }
369
+ return result;
370
+ }, void 0, true);
371
+ }
372
+ else if (isString(template)) {
373
+ templateBindingDependsOnData = true;
374
+ templateBinding = oneTime((s, c) => {
375
+ var _a;
376
+ const data = dataBinding.evaluate(s, c);
377
+ if (data instanceof Node) {
378
+ return (_a = data.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(data);
379
+ }
380
+ return instructionToTemplate(getForInstance(data, template));
381
+ });
382
+ }
383
+ else if (template instanceof Binding) {
384
+ const evaluateTemplate = template.evaluate;
385
+ template.evaluate = (s, c) => {
386
+ var _a;
387
+ let result = evaluateTemplate(s, c);
388
+ if (isString(result)) {
389
+ result = instructionToTemplate(getForInstance(dataBinding.evaluate(s, c), result));
390
+ }
391
+ else if (result instanceof Node) {
392
+ result = (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
393
+ }
394
+ return result;
395
+ };
396
+ templateBinding = template;
397
+ }
398
+ else {
399
+ templateBinding = oneTime((s, c) => template);
400
+ }
401
+ return new RenderDirective(dataBinding, templateBinding, templateBindingDependsOnData);
402
+ }