@microsoft/fast-element 2.0.0-beta.9 → 2.0.1

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 (142) hide show
  1. package/.eslintrc.json +1 -1
  2. package/CHANGELOG.json +518 -0
  3. package/CHANGELOG.md +181 -1
  4. package/README.md +1 -9
  5. package/api-extractor.context.json +14 -0
  6. package/api-extractor.di.json +14 -0
  7. package/dist/context/context.api.json +1068 -0
  8. package/dist/di/di.api.json +4929 -0
  9. package/dist/dts/binding/binding.d.ts +49 -0
  10. package/dist/dts/binding/normalize.d.ts +9 -0
  11. package/dist/dts/binding/one-time.d.ts +11 -0
  12. package/dist/dts/binding/one-way.d.ts +20 -0
  13. package/dist/dts/{templating/binding-signal.d.ts → binding/signal.d.ts} +19 -4
  14. package/dist/dts/{templating/binding-two-way.d.ts → binding/two-way.d.ts} +9 -5
  15. package/dist/dts/components/attributes.d.ts +7 -1
  16. package/dist/dts/components/element-controller.d.ts +104 -8
  17. package/dist/dts/components/element-hydration.d.ts +2 -0
  18. package/dist/dts/components/fast-definitions.d.ts +6 -0
  19. package/dist/dts/components/hydration.d.ts +56 -0
  20. package/dist/dts/components/install-hydration.d.ts +1 -0
  21. package/dist/dts/context.d.ts +29 -15
  22. package/dist/dts/di/di.d.ts +0 -5
  23. package/dist/dts/dom-policy.d.ts +83 -0
  24. package/dist/dts/dom.d.ts +100 -0
  25. package/dist/dts/hydration/target-builder.d.ts +63 -0
  26. package/dist/dts/index.d.ts +33 -26
  27. package/dist/dts/index.rollup.d.ts +0 -1
  28. package/dist/dts/index.rollup.debug.d.ts +0 -1
  29. package/dist/dts/interfaces.d.ts +32 -82
  30. package/dist/dts/metadata.d.ts +6 -5
  31. package/dist/dts/observation/arrays.d.ts +1 -1
  32. package/dist/dts/observation/observable.bench.d.ts +18 -0
  33. package/dist/dts/observation/observable.d.ts +5 -5
  34. package/dist/dts/pending-task.d.ts +19 -7
  35. package/dist/dts/platform.d.ts +11 -2
  36. package/dist/dts/polyfills.d.ts +0 -8
  37. package/dist/dts/styles/css-binding-directive.d.ts +60 -0
  38. package/dist/dts/styles/css.d.ts +9 -7
  39. package/dist/dts/styles/element-styles.d.ts +1 -14
  40. package/dist/dts/styles/host.d.ts +2 -5
  41. package/dist/dts/styles/style-strategy.d.ts +42 -0
  42. package/dist/dts/templating/compiler.d.ts +11 -13
  43. package/dist/dts/templating/{binding.d.ts → html-binding-directive.d.ts} +21 -41
  44. package/dist/dts/templating/html-directive.d.ts +44 -140
  45. package/dist/dts/templating/install-hydratable-view-templates.d.ts +1 -0
  46. package/dist/dts/templating/node-observation.d.ts +11 -1
  47. package/dist/dts/templating/ref.d.ts +4 -0
  48. package/dist/dts/templating/render.bench.d.ts +3 -0
  49. package/dist/dts/templating/render.d.ts +49 -9
  50. package/dist/dts/templating/repeat-basic-reverse.bench.d.ts +3 -0
  51. package/dist/dts/templating/repeat-basic-shift.bench.d.ts +3 -0
  52. package/dist/dts/templating/repeat.d.ts +31 -9
  53. package/dist/dts/templating/template.d.ts +97 -12
  54. package/dist/dts/templating/view.d.ts +146 -29
  55. package/dist/dts/templating/when-basic.bench.d.ts +3 -0
  56. package/dist/dts/templating/when-conditional.bench.d.ts +3 -0
  57. package/dist/dts/templating/when-switch.bench.d.ts +3 -0
  58. package/dist/dts/templating/when.d.ts +3 -1
  59. package/dist/dts/testing/fakes.d.ts +12 -1
  60. package/dist/dts/tsdoc-metadata.json +1 -1
  61. package/dist/dts/utilities.d.ts +55 -1
  62. package/dist/esm/binding/binding.js +18 -0
  63. package/dist/esm/binding/normalize.js +17 -0
  64. package/dist/esm/binding/one-time.js +21 -0
  65. package/dist/esm/binding/one-way.js +30 -0
  66. package/dist/esm/{templating/binding-signal.js → binding/signal.js} +22 -6
  67. package/dist/esm/{templating/binding-two-way.js → binding/two-way.js} +18 -12
  68. package/dist/esm/components/attributes.js +19 -6
  69. package/dist/esm/components/element-controller.js +319 -49
  70. package/dist/esm/components/element-hydration.js +2 -0
  71. package/dist/esm/components/fast-definitions.js +12 -4
  72. package/dist/esm/components/fast-element.js +3 -1
  73. package/dist/esm/components/hydration.js +104 -0
  74. package/dist/esm/components/install-hydration.js +3 -0
  75. package/dist/esm/context.js +26 -4
  76. package/dist/esm/debug.js +8 -2
  77. package/dist/esm/di/di.js +9 -12
  78. package/dist/esm/dom-policy.js +345 -0
  79. package/dist/esm/dom.js +101 -0
  80. package/dist/esm/hydration/target-builder.js +175 -0
  81. package/dist/esm/index.js +34 -25
  82. package/dist/esm/index.rollup.debug.js +3 -1
  83. package/dist/esm/index.rollup.js +3 -1
  84. package/dist/esm/interfaces.js +51 -3
  85. package/dist/esm/metadata.js +11 -8
  86. package/dist/esm/observation/arrays.js +1 -1
  87. package/dist/esm/observation/observable.bench.js +79 -0
  88. package/dist/esm/observation/observable.js +20 -15
  89. package/dist/esm/observation/update-queue.js +2 -2
  90. package/dist/esm/pending-task.js +13 -1
  91. package/dist/esm/platform.js +12 -2
  92. package/dist/esm/polyfills.js +3 -61
  93. package/dist/esm/styles/css-binding-directive.js +76 -0
  94. package/dist/esm/styles/css.js +14 -7
  95. package/dist/esm/styles/element-styles.js +0 -33
  96. package/dist/esm/styles/style-strategy.js +1 -0
  97. package/dist/esm/templating/children.js +8 -4
  98. package/dist/esm/templating/compiler.js +37 -44
  99. package/dist/esm/templating/html-binding-directive.js +218 -0
  100. package/dist/esm/templating/html-directive.js +25 -152
  101. package/dist/esm/templating/install-hydratable-view-templates.js +17 -0
  102. package/dist/esm/templating/node-observation.js +14 -8
  103. package/dist/esm/templating/ref.js +1 -1
  104. package/dist/esm/templating/render.bench.js +56 -0
  105. package/dist/esm/templating/render.js +74 -30
  106. package/dist/esm/templating/repeat-basic-reverse.bench.js +43 -0
  107. package/dist/esm/templating/repeat-basic-shift.bench.js +43 -0
  108. package/dist/esm/templating/repeat.js +116 -17
  109. package/dist/esm/templating/template.js +135 -60
  110. package/dist/esm/templating/view.js +254 -34
  111. package/dist/esm/templating/when-basic.bench.js +36 -0
  112. package/dist/esm/templating/when-conditional.bench.js +39 -0
  113. package/dist/esm/templating/when-switch.bench.js +68 -0
  114. package/dist/esm/templating/when.js +12 -5
  115. package/dist/esm/testing/fakes.js +32 -1
  116. package/dist/esm/testing/fixture.js +1 -1
  117. package/dist/esm/utilities.js +97 -1
  118. package/dist/fast-element.api.json +9789 -5667
  119. package/dist/fast-element.d.ts +813 -2392
  120. package/dist/fast-element.debug.js +2788 -974
  121. package/dist/fast-element.debug.min.js +3 -1
  122. package/dist/fast-element.js +2641 -833
  123. package/dist/fast-element.min.js +3 -1
  124. package/dist/fast-element.untrimmed.d.ts +662 -314
  125. package/docs/{api-report.md → api-report.api.md} +238 -151
  126. package/docs/context/api-report.api.md +69 -0
  127. package/docs/di/api-report.api.md +315 -0
  128. package/karma.conf.cjs +2 -1
  129. package/package.json +59 -47
  130. package/scripts/run-api-extractor.js +51 -0
  131. package/scripts/run-benchmarks.js +46 -0
  132. package/tensile.config.js +12 -0
  133. package/dist/dts/templating/dom.d.ts +0 -41
  134. package/dist/esm/templating/binding.js +0 -282
  135. package/dist/esm/templating/dom.js +0 -49
  136. package/docs/guide/declaring-templates.md +0 -230
  137. package/docs/guide/defining-elements.md +0 -214
  138. package/docs/guide/leveraging-css.md +0 -253
  139. package/docs/guide/next-steps.md +0 -13
  140. package/docs/guide/observables-and-state.md +0 -213
  141. package/docs/guide/using-directives.md +0 -576
  142. package/docs/guide/working-with-shadow-dom.md +0 -296
@@ -1,8 +1,56 @@
1
1
  import { isFunction, isString } from "../interfaces.js";
2
- import { bind, HTMLBindingDirective, oneTime } from "./binding.js";
2
+ import { Binding } from "../binding/binding.js";
3
+ import { FAST, makeSerializationNoop } from "../platform.js";
4
+ import { oneWay } from "../binding/one-way.js";
5
+ import { oneTime } from "../binding/one-time.js";
6
+ import { HTMLBindingDirective } from "./html-binding-directive.js";
3
7
  import { Compiler } from "./compiler.js";
4
- import { Aspect, Binding, HTMLDirective, } from "./html-directive.js";
8
+ import { HTMLDirective, } from "./html-directive.js";
5
9
  import { nextId } from "./markup.js";
10
+ // Much thanks to LitHTML for working this out!
11
+ const lastAttributeNameRegex =
12
+ /* eslint-disable-next-line no-control-regex, max-len */
13
+ /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;
14
+ const noFactories = Object.create(null);
15
+ /**
16
+ * Inlines a template into another template.
17
+ * @public
18
+ */
19
+ export class InlineTemplateDirective {
20
+ /**
21
+ * Creates an instance of InlineTemplateDirective.
22
+ * @param template - The template to inline.
23
+ */
24
+ constructor(html, factories = noFactories) {
25
+ this.html = html;
26
+ this.factories = factories;
27
+ }
28
+ /**
29
+ * Creates HTML to be used within a template.
30
+ * @param add - Can be used to add behavior factories to a template.
31
+ */
32
+ createHTML(add) {
33
+ const factories = this.factories;
34
+ for (const key in factories) {
35
+ add(factories[key]);
36
+ }
37
+ return this.html;
38
+ }
39
+ }
40
+ /**
41
+ * An empty template partial.
42
+ */
43
+ InlineTemplateDirective.empty = new InlineTemplateDirective("");
44
+ HTMLDirective.define(InlineTemplateDirective);
45
+ function createHTML(value, prevString, add, definition = HTMLDirective.getForInstance(value)) {
46
+ if (definition.aspected) {
47
+ const match = lastAttributeNameRegex.exec(prevString);
48
+ if (match !== null) {
49
+ HTMLDirective.assignAspect(value, match[2]);
50
+ }
51
+ }
52
+ return value.createHTML(add);
53
+ }
6
54
  /**
7
55
  * A template capable of creating HTMLView instances or rendering directly to DOM.
8
56
  * @public
@@ -12,21 +60,53 @@ export class ViewTemplate {
12
60
  * Creates an instance of ViewTemplate.
13
61
  * @param html - The html representing what this template will instantiate, including placeholders for directives.
14
62
  * @param factories - The directives that will be connected to placeholders in the html.
63
+ * @param policy - The security policy to use when compiling this template.
15
64
  */
16
- constructor(html, factories) {
65
+ constructor(html, factories = {}, policy) {
66
+ this.policy = policy;
17
67
  this.result = null;
18
68
  this.html = html;
19
69
  this.factories = factories;
20
70
  }
71
+ /**
72
+ * @internal
73
+ */
74
+ compile() {
75
+ if (this.result === null) {
76
+ this.result = Compiler.compile(this.html, this.factories, this.policy);
77
+ }
78
+ return this.result;
79
+ }
21
80
  /**
22
81
  * Creates an HTMLView instance based on this template definition.
23
82
  * @param hostBindingTarget - The element that host behaviors will be bound to.
24
83
  */
25
84
  create(hostBindingTarget) {
26
- if (this.result === null) {
27
- this.result = Compiler.compile(this.html, this.factories);
85
+ return this.compile().createView(hostBindingTarget);
86
+ }
87
+ /**
88
+ * Returns a directive that can inline the template.
89
+ */
90
+ inline() {
91
+ return new InlineTemplateDirective(isString(this.html) ? this.html : this.html.innerHTML, this.factories);
92
+ }
93
+ /**
94
+ * Sets the DOMPolicy for this template.
95
+ * @param policy - The policy to associated with this template.
96
+ * @returns The modified template instance.
97
+ * @remarks
98
+ * The DOMPolicy can only be set once for a template and cannot be
99
+ * set after the template is compiled.
100
+ */
101
+ withPolicy(policy) {
102
+ if (this.result) {
103
+ throw FAST.error(1208 /* Message.cannotSetTemplatePolicyAfterCompilation */);
104
+ }
105
+ if (this.policy) {
106
+ throw FAST.error(1207 /* Message.onlySetTemplatePolicyOnce */);
28
107
  }
29
- return this.result.createView(hostBindingTarget);
108
+ this.policy = policy;
109
+ return this;
30
110
  }
31
111
  /**
32
112
  * Creates an HTMLView from this template, binds it to the source, and then appends it to the host.
@@ -41,18 +121,49 @@ export class ViewTemplate {
41
121
  view.appendTo(host);
42
122
  return view;
43
123
  }
44
- }
45
- // Much thanks to LitHTML for working this out!
46
- const lastAttributeNameRegex =
47
- /* eslint-disable-next-line no-control-regex */
48
- /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;
49
- function createAspectedHTML(value, prevString, add) {
50
- const match = lastAttributeNameRegex.exec(prevString);
51
- if (match !== null) {
52
- Aspect.assign(value, match[2]);
124
+ /**
125
+ * Creates a template based on a set of static strings and dynamic values.
126
+ * @param strings - The static strings to create the template with.
127
+ * @param values - The dynamic values to create the template with.
128
+ * @param policy - The DOMPolicy to associated with the template.
129
+ * @returns A ViewTemplate.
130
+ * @remarks
131
+ * This API should not be used directly under normal circumstances because constructing
132
+ * a template in this way, if not done properly, can open up the application to XSS
133
+ * attacks. When using this API, provide a strong DOMPolicy that can properly sanitize
134
+ * and also be sure to manually sanitize all static strings particularly if they can
135
+ * come from user input.
136
+ */
137
+ static create(strings, values, policy) {
138
+ let html = "";
139
+ const factories = Object.create(null);
140
+ const add = (factory) => {
141
+ var _a;
142
+ const id = (_a = factory.id) !== null && _a !== void 0 ? _a : (factory.id = nextId());
143
+ factories[id] = factory;
144
+ return id;
145
+ };
146
+ for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
147
+ const currentString = strings[i];
148
+ let currentValue = values[i];
149
+ let definition;
150
+ html += currentString;
151
+ if (isFunction(currentValue)) {
152
+ currentValue = new HTMLBindingDirective(oneWay(currentValue));
153
+ }
154
+ else if (currentValue instanceof Binding) {
155
+ currentValue = new HTMLBindingDirective(currentValue);
156
+ }
157
+ else if (!(definition = HTMLDirective.getForInstance(currentValue))) {
158
+ const staticValue = currentValue;
159
+ currentValue = new HTMLBindingDirective(oneTime(() => staticValue));
160
+ }
161
+ html += createHTML(currentValue, currentString, add, definition);
162
+ }
163
+ return new ViewTemplate(html + strings[strings.length - 1], factories, policy);
53
164
  }
54
- return value.createHTML(add);
55
165
  }
166
+ makeSerializationNoop(ViewTemplate);
56
167
  /**
57
168
  * Transforms a template literal string into a ViewTemplate.
58
169
  * @param strings - The string fragments that are interpolated with the values.
@@ -62,48 +173,12 @@ function createAspectedHTML(value, prevString, add) {
62
173
  * other template instances, and Directive instances.
63
174
  * @public
64
175
  */
65
- export function html(strings, ...values) {
66
- let html = "";
67
- const factories = Object.create(null);
68
- const add = (factory) => {
69
- var _a;
70
- const id = (_a = factory.id) !== null && _a !== void 0 ? _a : (factory.id = nextId());
71
- factories[id] = factory;
72
- return id;
73
- };
74
- for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
75
- const currentString = strings[i];
76
- const currentValue = values[i];
77
- let definition;
78
- html += currentString;
79
- if (isFunction(currentValue)) {
80
- html += createAspectedHTML(new HTMLBindingDirective(bind(currentValue)), currentString, add);
81
- }
82
- else if (isString(currentValue)) {
83
- const match = lastAttributeNameRegex.exec(currentString);
84
- if (match !== null) {
85
- const directive = new HTMLBindingDirective(oneTime(() => currentValue));
86
- Aspect.assign(directive, match[2]);
87
- html += directive.createHTML(add);
88
- }
89
- else {
90
- html += currentValue;
91
- }
92
- }
93
- else if (currentValue instanceof Binding) {
94
- html += createAspectedHTML(new HTMLBindingDirective(currentValue), currentString, add);
95
- }
96
- else if ((definition = HTMLDirective.getForInstance(currentValue)) === void 0) {
97
- html += createAspectedHTML(new HTMLBindingDirective(oneTime(() => currentValue)), currentString, add);
98
- }
99
- else {
100
- if (definition.aspected) {
101
- html += createAspectedHTML(currentValue, currentString, add);
102
- }
103
- else {
104
- html += currentValue.createHTML(add);
105
- }
106
- }
176
+ export const html = ((strings, ...values) => {
177
+ if (Array.isArray(strings) && Array.isArray(strings.raw)) {
178
+ return ViewTemplate.create(strings, values);
107
179
  }
108
- return new ViewTemplate(html + strings[strings.length - 1], factories);
109
- }
180
+ throw FAST.error(1206 /* Message.directCallToHTMLTagNotAllowed */);
181
+ });
182
+ html.partial = (html) => {
183
+ return new InlineTemplateDirective(html);
184
+ };
@@ -1,47 +1,24 @@
1
+ var _a;
2
+ import { Hydratable } from "../components/hydration.js";
3
+ import { buildViewBindingTargets, createRangeForNodes, HydrationTargetElementError, targetFactory, } from "../hydration/target-builder.js";
1
4
  import { ExecutionContext, Observable, SourceLifetime, } from "../observation/observable.js";
5
+ import { makeSerializationNoop } from "../platform.js";
2
6
  function removeNodeSequence(firstNode, lastNode) {
3
7
  const parent = firstNode.parentNode;
4
8
  let current = firstNode;
5
9
  let next;
6
10
  while (current !== lastNode) {
7
11
  next = current.nextSibling;
12
+ if (!next) {
13
+ throw new Error(`Unmatched first/last child inside "${lastNode.getRootNode().host.nodeName}".`);
14
+ }
8
15
  parent.removeChild(current);
9
16
  current = next;
10
17
  }
11
18
  parent.removeChild(lastNode);
12
19
  }
13
- /**
14
- * The standard View implementation, which also implements ElementView and SyntheticView.
15
- * @public
16
- */
17
- export class HTMLView {
18
- /**
19
- * Constructs an instance of HTMLView.
20
- * @param fragment - The html fragment that contains the nodes for this view.
21
- * @param behaviors - The behaviors to be applied to this view.
22
- */
23
- constructor(fragment, factories, targets) {
24
- this.fragment = fragment;
25
- this.factories = factories;
26
- this.targets = targets;
27
- this.behaviors = null;
28
- this.unbindables = [];
29
- /**
30
- * The data that the view is bound to.
31
- */
32
- this.source = null;
33
- /**
34
- * Indicates whether the controller is bound.
35
- */
36
- this.isBound = false;
37
- /**
38
- * Indicates how the source's lifetime relates to the controller's lifetime.
39
- */
40
- this.sourceLifetime = SourceLifetime.unknown;
41
- /**
42
- * The execution context the view is running within.
43
- */
44
- this.context = this;
20
+ class DefaultExecutionContext {
21
+ constructor() {
45
22
  /**
46
23
  * The index of the current item within a repeat context.
47
24
  */
@@ -50,8 +27,6 @@ export class HTMLView {
50
27
  * The length of the current collection within a repeat context.
51
28
  */
52
29
  this.length = 0;
53
- this.firstChild = fragment.firstChild;
54
- this.lastChild = fragment.lastChild;
55
30
  }
56
31
  /**
57
32
  * The current event within an event handler.
@@ -106,6 +81,43 @@ export class HTMLView {
106
81
  eventTarget() {
107
82
  return this.event.target;
108
83
  }
84
+ }
85
+ /**
86
+ * The standard View implementation, which also implements ElementView and SyntheticView.
87
+ * @public
88
+ */
89
+ export class HTMLView extends DefaultExecutionContext {
90
+ /**
91
+ * Constructs an instance of HTMLView.
92
+ * @param fragment - The html fragment that contains the nodes for this view.
93
+ * @param behaviors - The behaviors to be applied to this view.
94
+ */
95
+ constructor(fragment, factories, targets) {
96
+ super();
97
+ this.fragment = fragment;
98
+ this.factories = factories;
99
+ this.targets = targets;
100
+ this.behaviors = null;
101
+ this.unbindables = [];
102
+ /**
103
+ * The data that the view is bound to.
104
+ */
105
+ this.source = null;
106
+ /**
107
+ * Indicates whether the controller is bound.
108
+ */
109
+ this.isBound = false;
110
+ /**
111
+ * Indicates how the source's lifetime relates to the controller's lifetime.
112
+ */
113
+ this.sourceLifetime = SourceLifetime.unknown;
114
+ /**
115
+ * The execution context the view is running within.
116
+ */
117
+ this.context = this;
118
+ this.firstChild = fragment.firstChild;
119
+ this.lastChild = fragment.lastChild;
120
+ }
109
121
  /**
110
122
  * Appends the view's DOM nodes to the referenced node.
111
123
  * @param node - The parent node to append the view's DOM nodes to.
@@ -230,5 +242,213 @@ export class HTMLView {
230
242
  }
231
243
  }
232
244
  }
245
+ makeSerializationNoop(HTMLView);
233
246
  Observable.defineProperty(HTMLView.prototype, "index");
234
247
  Observable.defineProperty(HTMLView.prototype, "length");
248
+ export const HydrationStage = {
249
+ unhydrated: "unhydrated",
250
+ hydrating: "hydrating",
251
+ hydrated: "hydrated",
252
+ };
253
+ /** @public */
254
+ export class HydrationBindingError extends Error {
255
+ constructor(
256
+ /**
257
+ * The error message
258
+ */
259
+ message,
260
+ /**
261
+ * The factory that was unable to be bound
262
+ */
263
+ factory,
264
+ /**
265
+ * A DocumentFragment containing a clone of the
266
+ * view's Nodes.
267
+ */
268
+ fragment,
269
+ /**
270
+ * String representation of the HTML in the template that
271
+ * threw the binding error.
272
+ */
273
+ templateString) {
274
+ super(message);
275
+ this.factory = factory;
276
+ this.fragment = fragment;
277
+ this.templateString = templateString;
278
+ }
279
+ }
280
+ export class HydrationView extends DefaultExecutionContext {
281
+ constructor(firstChild, lastChild, sourceTemplate, hostBindingTarget) {
282
+ super();
283
+ this.firstChild = firstChild;
284
+ this.lastChild = lastChild;
285
+ this.sourceTemplate = sourceTemplate;
286
+ this.hostBindingTarget = hostBindingTarget;
287
+ this[_a] = Hydratable;
288
+ this.context = this;
289
+ this.source = null;
290
+ this.isBound = false;
291
+ this.sourceLifetime = SourceLifetime.unknown;
292
+ this.unbindables = [];
293
+ this.fragment = null;
294
+ this.behaviors = null;
295
+ this._hydrationStage = HydrationStage.unhydrated;
296
+ this._bindingViewBoundaries = {};
297
+ this._targets = {};
298
+ this.factories = sourceTemplate.compile().factories;
299
+ }
300
+ get hydrationStage() {
301
+ return this._hydrationStage;
302
+ }
303
+ get targets() {
304
+ return this._targets;
305
+ }
306
+ get bindingViewBoundaries() {
307
+ return this._bindingViewBoundaries;
308
+ }
309
+ /**
310
+ * no-op. Hydrated views are don't need to be moved from a documentFragment
311
+ * to the target node.
312
+ */
313
+ insertBefore(node) {
314
+ // No-op in cases where this is called before the view is removed,
315
+ // because the nodes will already be in the document and just need hydrating.
316
+ if (this.fragment === null) {
317
+ return;
318
+ }
319
+ if (this.fragment.hasChildNodes()) {
320
+ node.parentNode.insertBefore(this.fragment, node);
321
+ }
322
+ else {
323
+ const end = this.lastChild;
324
+ if (node.previousSibling === end)
325
+ return;
326
+ const parentNode = node.parentNode;
327
+ let current = this.firstChild;
328
+ let next;
329
+ while (current !== end) {
330
+ next = current.nextSibling;
331
+ parentNode.insertBefore(current, node);
332
+ current = next;
333
+ }
334
+ parentNode.insertBefore(end, node);
335
+ }
336
+ }
337
+ /**
338
+ * Appends the view to a node. In cases where this is called before the
339
+ * view has been removed, the method will no-op.
340
+ * @param node - the node to append the view to.
341
+ */
342
+ appendTo(node) {
343
+ if (this.fragment !== null) {
344
+ node.appendChild(this.fragment);
345
+ }
346
+ }
347
+ remove() {
348
+ const fragment = this.fragment || (this.fragment = document.createDocumentFragment());
349
+ const end = this.lastChild;
350
+ let current = this.firstChild;
351
+ let next;
352
+ while (current !== end) {
353
+ next = current.nextSibling;
354
+ if (!next) {
355
+ throw new Error(`Unmatched first/last child inside "${end.getRootNode().host.nodeName}".`);
356
+ }
357
+ fragment.appendChild(current);
358
+ current = next;
359
+ }
360
+ fragment.appendChild(end);
361
+ }
362
+ bind(source, context = this) {
363
+ var _b, _c;
364
+ if (this.hydrationStage !== HydrationStage.hydrated) {
365
+ this._hydrationStage = HydrationStage.hydrating;
366
+ }
367
+ if (this.source === source) {
368
+ return;
369
+ }
370
+ let behaviors = this.behaviors;
371
+ if (behaviors === null) {
372
+ this.source = source;
373
+ this.context = context;
374
+ try {
375
+ const { targets, boundaries } = buildViewBindingTargets(this.firstChild, this.lastChild, this.factories);
376
+ this._targets = targets;
377
+ this._bindingViewBoundaries = boundaries;
378
+ }
379
+ catch (error) {
380
+ if (error instanceof HydrationTargetElementError) {
381
+ let templateString = this.sourceTemplate.html;
382
+ if (typeof templateString !== "string") {
383
+ templateString = templateString.innerHTML;
384
+ }
385
+ error.templateString = templateString;
386
+ }
387
+ throw error;
388
+ }
389
+ this.behaviors = behaviors = new Array(this.factories.length);
390
+ const factories = this.factories;
391
+ for (let i = 0, ii = factories.length; i < ii; ++i) {
392
+ const factory = factories[i];
393
+ if (factory.targetNodeId === "h" && this.hostBindingTarget) {
394
+ targetFactory(factory, this.hostBindingTarget, this._targets);
395
+ }
396
+ // If the binding has been targeted or it is a host binding and the view has a hostBindingTarget
397
+ if (factory.targetNodeId in this.targets) {
398
+ const behavior = factory.createBehavior();
399
+ behavior.bind(this);
400
+ behaviors[i] = behavior;
401
+ }
402
+ else {
403
+ let templateString = this.sourceTemplate.html;
404
+ if (typeof templateString !== "string") {
405
+ templateString = templateString.innerHTML;
406
+ }
407
+ throw new HydrationBindingError(`HydrationView was unable to successfully target bindings inside "${(_c = ((_b = this.firstChild) === null || _b === void 0 ? void 0 : _b.getRootNode()).host) === null || _c === void 0 ? void 0 : _c.nodeName}".`, factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
408
+ }
409
+ }
410
+ }
411
+ else {
412
+ if (this.source !== null) {
413
+ this.evaluateUnbindables();
414
+ }
415
+ this.isBound = false;
416
+ this.source = source;
417
+ this.context = context;
418
+ for (let i = 0, ii = behaviors.length; i < ii; ++i) {
419
+ behaviors[i].bind(this);
420
+ }
421
+ }
422
+ this.isBound = true;
423
+ this._hydrationStage = HydrationStage.hydrated;
424
+ }
425
+ unbind() {
426
+ if (!this.isBound || this.source === null) {
427
+ return;
428
+ }
429
+ this.evaluateUnbindables();
430
+ this.source = null;
431
+ this.context = this;
432
+ this.isBound = false;
433
+ }
434
+ /**
435
+ * Removes the view and unbinds its behaviors, disposing of DOM nodes afterward.
436
+ * Once a view has been disposed, it cannot be inserted or bound again.
437
+ */
438
+ dispose() {
439
+ removeNodeSequence(this.firstChild, this.lastChild);
440
+ this.unbind();
441
+ }
442
+ onUnbind(behavior) {
443
+ this.unbindables.push(behavior);
444
+ }
445
+ evaluateUnbindables() {
446
+ const unbindables = this.unbindables;
447
+ for (let i = 0, ii = unbindables.length; i < ii; ++i) {
448
+ unbindables[i].unbind(this);
449
+ }
450
+ unbindables.length = 0;
451
+ }
452
+ }
453
+ _a = Hydratable;
454
+ makeSerializationNoop(HydrationView);
@@ -0,0 +1,36 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { attr, FASTElement, html, when } from "../index.js";
11
+ class TestWhen extends FASTElement {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.try = false;
15
+ }
16
+ }
17
+ __decorate([
18
+ attr({
19
+ mode: "boolean",
20
+ }),
21
+ __metadata("design:type", Boolean)
22
+ ], TestWhen.prototype, "try", void 0);
23
+ TestWhen.define({
24
+ name: "test-when",
25
+ template: html `
26
+ ${when(x => x.try, html `
27
+ <span>Yes</span>
28
+ `)}
29
+ `,
30
+ });
31
+ const itemRenderer = () => {
32
+ const testWhen = document.createElement("test-when");
33
+ return testWhen;
34
+ };
35
+ export default itemRenderer;
36
+ export { tests } from "@tensile-perf/web-components";
@@ -0,0 +1,39 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { attr, FASTElement, html, when } from "../index.js";
11
+ class TestWhen extends FASTElement {
12
+ constructor() {
13
+ super(...arguments);
14
+ this.try = false;
15
+ }
16
+ }
17
+ __decorate([
18
+ attr({
19
+ mode: "boolean",
20
+ }),
21
+ __metadata("design:type", Boolean)
22
+ ], TestWhen.prototype, "try", void 0);
23
+ TestWhen.define({
24
+ name: "test-when",
25
+ template: html `
26
+ ${when(x => x.try, html `
27
+ <span>Yes</span>
28
+ `)}
29
+ ${when(x => !x.try, html `
30
+ <span>No</span>
31
+ `)}
32
+ `,
33
+ });
34
+ const itemRenderer = () => {
35
+ const testWhen = document.createElement("test-when");
36
+ return testWhen;
37
+ };
38
+ export default itemRenderer;
39
+ export { tests } from "@tensile-perf/web-components";