@lushly-dev/fast-element 3.0.1-preview.0 → 3.0.1-preview.2

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 (250) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/command/command.api.json +7857 -0
  3. package/dist/context/context.api.json +1084 -0
  4. package/dist/declarative/declarative.api.json +8130 -0
  5. package/dist/definition-schema/definition-schema.api.json +2689 -0
  6. package/dist/di/di.api.json +4945 -0
  7. package/dist/dts/arrays.d.ts +2 -0
  8. package/dist/dts/binding/binding.d.ts +59 -0
  9. package/dist/dts/binding/exports.d.ts +9 -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/binding/signal.d.ts +36 -0
  14. package/dist/dts/binding/two-way.d.ts +44 -0
  15. package/dist/dts/command/behavior.d.ts +94 -0
  16. package/dist/dts/command/behaviors/confirm-behavior.d.ts +139 -0
  17. package/dist/dts/command/behaviors/undo-behavior.d.ts +178 -0
  18. package/dist/dts/command/command.d.ts +79 -0
  19. package/dist/dts/command/component-registry.d.ts +50 -0
  20. package/dist/dts/command/components/confirm-dialog.d.ts +117 -0
  21. package/dist/dts/command/index.d.ts +21 -0
  22. package/dist/dts/command/registry.d.ts +201 -0
  23. package/dist/dts/command/schema-validation.d.ts +45 -0
  24. package/dist/dts/command/types.d.ts +332 -0
  25. package/dist/dts/command/validation.d.ts +116 -0
  26. package/dist/dts/command/weak-ref.d.ts +11 -0
  27. package/dist/dts/components/attributes.d.ts +153 -0
  28. package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
  29. package/dist/dts/components/element-controller.d.ts +349 -0
  30. package/dist/dts/components/element-hydration.d.ts +2 -0
  31. package/dist/dts/components/enable-hydration.d.ts +66 -0
  32. package/dist/dts/components/fast-definitions.d.ts +211 -0
  33. package/dist/dts/components/fast-element-registry.d.ts +23 -0
  34. package/dist/dts/components/fast-element.d.ts +91 -0
  35. package/dist/dts/components/hydration-tracker.d.ts +110 -0
  36. package/dist/dts/components/hydration.d.ts +52 -0
  37. package/dist/dts/components/schema.d.ts +205 -0
  38. package/dist/dts/context.d.ts +171 -0
  39. package/dist/dts/debug.d.ts +5 -0
  40. package/dist/dts/declarative/attribute-map.d.ts +58 -0
  41. package/dist/dts/declarative/debug.d.ts +4 -0
  42. package/dist/dts/declarative/index.d.ts +14 -0
  43. package/dist/dts/declarative/interfaces.d.ts +8 -0
  44. package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
  45. package/dist/dts/declarative/observer-map.d.ts +89 -0
  46. package/dist/dts/declarative/runtime.d.ts +5 -0
  47. package/dist/dts/declarative/syntax.d.ts +21 -0
  48. package/dist/dts/declarative/template-bridge.d.ts +33 -0
  49. package/dist/dts/declarative/template-parser.d.ts +98 -0
  50. package/dist/dts/declarative/template.d.ts +9 -0
  51. package/dist/dts/declarative/utilities.d.ts +358 -0
  52. package/dist/dts/definition-schema/api.d.ts +42 -0
  53. package/dist/dts/definition-schema/cem.d.ts +78 -0
  54. package/dist/dts/definition-schema/extension.d.ts +18 -0
  55. package/dist/dts/definition-schema/extract.d.ts +38 -0
  56. package/dist/dts/definition-schema/index.d.ts +9 -0
  57. package/dist/dts/definition-schema/storage.d.ts +35 -0
  58. package/dist/dts/definition-schema/types.d.ts +176 -0
  59. package/dist/dts/dev-mode.d.ts +13 -0
  60. package/dist/dts/di/di.d.ts +894 -0
  61. package/dist/dts/dom-policy.d.ts +101 -0
  62. package/dist/dts/dom.d.ts +88 -0
  63. package/dist/dts/hydration/diagnostics.d.ts +93 -0
  64. package/dist/dts/hydration/exports.d.ts +18 -0
  65. package/dist/dts/hydration/hydration-debugger.d.ts +35 -0
  66. package/dist/dts/hydration/messages.d.ts +62 -0
  67. package/dist/dts/hydration/runtime.d.ts +7 -0
  68. package/dist/dts/hydration/target-builder.d.ts +107 -0
  69. package/dist/dts/index.d.ts +51 -0
  70. package/dist/dts/index.debug.d.ts +1 -0
  71. package/dist/dts/index.rollup.d.ts +1 -0
  72. package/dist/dts/index.rollup.debug.d.ts +1 -0
  73. package/dist/dts/interfaces.d.ts +106 -0
  74. package/dist/dts/metadata.d.ts +26 -0
  75. package/dist/dts/observation/arrays.d.ts +248 -0
  76. package/dist/dts/observation/notifier.d.ts +127 -0
  77. package/dist/dts/observation/observable.d.ts +276 -0
  78. package/dist/dts/observation/update-queue.d.ts +40 -0
  79. package/dist/dts/observation/volatile.d.ts +9 -0
  80. package/dist/dts/platform.d.ts +87 -0
  81. package/dist/dts/registry.d.ts +2 -0
  82. package/dist/dts/render.d.ts +7 -0
  83. package/dist/dts/schema.d.ts +1 -0
  84. package/dist/dts/scoped/detection.d.ts +55 -0
  85. package/dist/dts/scoped/index.d.ts +68 -0
  86. package/dist/dts/scoped/mixin.d.ts +118 -0
  87. package/dist/dts/scoped/registry.d.ts +76 -0
  88. package/dist/dts/scoped/types.d.ts +48 -0
  89. package/dist/dts/state/exports.d.ts +3 -0
  90. package/dist/dts/state/reactive.d.ts +8 -0
  91. package/dist/dts/state/state.d.ts +141 -0
  92. package/dist/dts/state/visitor.d.ts +6 -0
  93. package/dist/dts/state/watch.d.ts +10 -0
  94. package/dist/dts/styles/css-directive.d.ts +50 -0
  95. package/dist/dts/styles/css.d.ts +34 -0
  96. package/dist/dts/styles/element-styles.d.ts +61 -0
  97. package/dist/dts/styles/host.d.ts +65 -0
  98. package/dist/dts/styles/style-strategy.d.ts +42 -0
  99. package/dist/dts/templating/children.d.ts +62 -0
  100. package/dist/dts/templating/compiler.d.ts +54 -0
  101. package/dist/dts/templating/html-binding-directive.d.ts +155 -0
  102. package/dist/dts/templating/html-directive.d.ts +218 -0
  103. package/dist/dts/templating/html.d.ts +1 -0
  104. package/dist/dts/templating/hydration-view.d.ts +130 -0
  105. package/dist/dts/templating/markup.d.ts +48 -0
  106. package/dist/dts/templating/node-observation.d.ts +99 -0
  107. package/dist/dts/templating/ref.d.ts +23 -0
  108. package/dist/dts/templating/render.d.ts +318 -0
  109. package/dist/dts/templating/repeat.d.ts +131 -0
  110. package/dist/dts/templating/slotted.d.ts +38 -0
  111. package/dist/dts/templating/template.d.ts +221 -0
  112. package/dist/dts/templating/view.d.ts +268 -0
  113. package/dist/dts/templating/when.d.ts +12 -0
  114. package/dist/dts/testing/exports.d.ts +3 -0
  115. package/dist/dts/testing/fakes.d.ts +16 -0
  116. package/dist/dts/testing/fixture.d.ts +84 -0
  117. package/dist/dts/testing/models.d.ts +20 -0
  118. package/dist/dts/testing/timeout.d.ts +7 -0
  119. package/dist/dts/trust/index.d.ts +8 -0
  120. package/dist/dts/trust/types.d.ts +48 -0
  121. package/dist/dts/trust/utils.d.ts +26 -0
  122. package/dist/dts/tsdoc-metadata.json +11 -0
  123. package/dist/dts/utilities.d.ts +76 -0
  124. package/dist/esm/arrays.js +1 -0
  125. package/dist/esm/binding/binding.js +18 -0
  126. package/dist/esm/binding/exports.js +6 -0
  127. package/dist/esm/binding/normalize.js +17 -0
  128. package/dist/esm/binding/one-time.js +21 -0
  129. package/dist/esm/binding/one-way.js +30 -0
  130. package/dist/esm/binding/signal.js +99 -0
  131. package/dist/esm/binding/two-way.js +109 -0
  132. package/dist/esm/command/behavior.js +155 -0
  133. package/dist/esm/command/behaviors/confirm-behavior.js +225 -0
  134. package/dist/esm/command/behaviors/undo-behavior.js +313 -0
  135. package/dist/esm/command/command.js +104 -0
  136. package/dist/esm/command/component-registry.js +107 -0
  137. package/dist/esm/command/components/confirm-dialog.js +370 -0
  138. package/dist/esm/command/index.js +22 -0
  139. package/dist/esm/command/registry.js +755 -0
  140. package/dist/esm/command/schema-validation.js +194 -0
  141. package/dist/esm/command/types.js +86 -0
  142. package/dist/esm/command/validation.js +508 -0
  143. package/dist/esm/command/weak-ref.js +5 -0
  144. package/dist/esm/components/attributes.js +219 -0
  145. package/dist/esm/components/definition-schema-transforms.js +23 -0
  146. package/dist/esm/components/element-controller.js +840 -0
  147. package/dist/esm/components/element-hydration.js +2 -0
  148. package/dist/esm/components/enable-hydration.js +123 -0
  149. package/dist/esm/components/fast-definitions.js +294 -0
  150. package/dist/esm/components/fast-element-registry.js +67 -0
  151. package/dist/esm/components/fast-element.js +82 -0
  152. package/dist/esm/components/hydration-tracker.js +211 -0
  153. package/dist/esm/components/hydration.js +187 -0
  154. package/dist/esm/components/schema.js +253 -0
  155. package/dist/esm/context.js +185 -0
  156. package/dist/esm/debug.js +71 -0
  157. package/dist/esm/declarative/attribute-map.js +122 -0
  158. package/dist/esm/declarative/debug.js +4 -0
  159. package/dist/esm/declarative/index.js +10 -0
  160. package/dist/esm/declarative/interfaces.js +9 -0
  161. package/dist/esm/declarative/observer-map-utilities.js +565 -0
  162. package/dist/esm/declarative/observer-map.js +216 -0
  163. package/dist/esm/declarative/runtime.js +14 -0
  164. package/dist/esm/declarative/syntax.js +36 -0
  165. package/dist/esm/declarative/template-bridge.js +160 -0
  166. package/dist/esm/declarative/template-parser.js +306 -0
  167. package/dist/esm/declarative/template.js +116 -0
  168. package/dist/esm/declarative/utilities.js +1069 -0
  169. package/dist/esm/definition-schema/api.js +129 -0
  170. package/dist/esm/definition-schema/cem.js +89 -0
  171. package/dist/esm/definition-schema/extension.js +53 -0
  172. package/dist/esm/definition-schema/extract.js +167 -0
  173. package/dist/esm/definition-schema/index.js +8 -0
  174. package/dist/esm/definition-schema/storage.js +58 -0
  175. package/dist/esm/definition-schema/types.js +8 -0
  176. package/dist/esm/dev-mode.js +22 -0
  177. package/dist/esm/di/di.js +1441 -0
  178. package/dist/esm/dom-policy.js +374 -0
  179. package/dist/esm/dom.js +101 -0
  180. package/dist/esm/hydration/diagnostics.js +50 -0
  181. package/dist/esm/hydration/exports.js +6 -0
  182. package/dist/esm/hydration/hydration-debugger.js +112 -0
  183. package/dist/esm/hydration/messages.js +84 -0
  184. package/dist/esm/hydration/runtime.js +33 -0
  185. package/dist/esm/hydration/target-builder.js +264 -0
  186. package/dist/esm/index.debug.js +3 -0
  187. package/dist/esm/index.js +49 -0
  188. package/dist/esm/index.rollup.debug.js +6 -0
  189. package/dist/esm/index.rollup.js +4 -0
  190. package/dist/esm/interfaces.js +55 -0
  191. package/dist/esm/metadata.js +57 -0
  192. package/dist/esm/observation/arrays.js +661 -0
  193. package/dist/esm/observation/notifier.js +162 -0
  194. package/dist/esm/observation/observable.js +324 -0
  195. package/dist/esm/observation/update-queue.js +56 -0
  196. package/dist/esm/observation/volatile.js +16 -0
  197. package/dist/esm/platform.js +98 -0
  198. package/dist/esm/registry.js +2 -0
  199. package/dist/esm/render.js +1 -0
  200. package/dist/esm/schema.js +1 -0
  201. package/dist/esm/scoped/detection.js +102 -0
  202. package/dist/esm/scoped/index.js +69 -0
  203. package/dist/esm/scoped/mixin.js +127 -0
  204. package/dist/esm/scoped/registry.js +125 -0
  205. package/dist/esm/scoped/types.js +4 -0
  206. package/dist/esm/state/exports.js +3 -0
  207. package/dist/esm/state/reactive.js +34 -0
  208. package/dist/esm/state/state.js +148 -0
  209. package/dist/esm/state/visitor.js +28 -0
  210. package/dist/esm/state/watch.js +36 -0
  211. package/dist/esm/styles/css-directive.js +36 -0
  212. package/dist/esm/styles/css.js +56 -0
  213. package/dist/esm/styles/element-styles.js +144 -0
  214. package/dist/esm/styles/host.js +1 -0
  215. package/dist/esm/styles/style-strategy.js +1 -0
  216. package/dist/esm/templating/children.js +67 -0
  217. package/dist/esm/templating/compiler.js +359 -0
  218. package/dist/esm/templating/html-binding-directive.js +288 -0
  219. package/dist/esm/templating/html-directive.js +113 -0
  220. package/dist/esm/templating/html.js +1 -0
  221. package/dist/esm/templating/hydration-view.js +228 -0
  222. package/dist/esm/templating/markup.js +83 -0
  223. package/dist/esm/templating/node-observation.js +84 -0
  224. package/dist/esm/templating/ref.js +21 -0
  225. package/dist/esm/templating/render.js +468 -0
  226. package/dist/esm/templating/repeat.js +434 -0
  227. package/dist/esm/templating/slotted.js +49 -0
  228. package/dist/esm/templating/template.js +206 -0
  229. package/dist/esm/templating/view.js +298 -0
  230. package/dist/esm/templating/when.js +22 -0
  231. package/dist/esm/testing/exports.js +3 -0
  232. package/dist/esm/testing/fakes.js +107 -0
  233. package/dist/esm/testing/fixture.js +86 -0
  234. package/dist/esm/testing/models.js +58 -0
  235. package/dist/esm/testing/timeout.js +24 -0
  236. package/dist/esm/trust/index.js +7 -0
  237. package/dist/esm/trust/types.js +6 -0
  238. package/dist/esm/trust/utils.js +126 -0
  239. package/dist/esm/utilities.js +140 -0
  240. package/dist/fast-element.api.json +26798 -0
  241. package/dist/fast-element.d.ts +3985 -0
  242. package/dist/fast-element.debug.js +7604 -0
  243. package/dist/fast-element.debug.min.js +3 -0
  244. package/dist/fast-element.js +7603 -0
  245. package/dist/fast-element.min.js +3 -0
  246. package/dist/fast-element.untrimmed.d.ts +4103 -0
  247. package/dist/observation/arrays/arrays.api.json +2621 -0
  248. package/dist/scoped/scoped.api.json +891 -0
  249. package/dist/trust/trust.api.json +629 -0
  250. package/package.json +21 -23
@@ -0,0 +1,83 @@
1
+ /**
2
+ * A unique per-session random marker string used to create placeholder tokens in HTML.
3
+ * Bindings embedded in template literals are replaced with interpolation markers
4
+ * of the form `fast-xxxxxx{id}fast-xxxxxx` so the compiler can later locate them in the
5
+ * parsed DOM and associate each marker with its ViewBehaviorFactory.
6
+ */
7
+ const marker = `fast-${Math.random().toString(36).substring(2, 8)}`;
8
+ const interpolationStart = `${marker}{`;
9
+ const interpolationEnd = `}${marker}`;
10
+ const interpolationEndLength = interpolationEnd.length;
11
+ let id = 0;
12
+ /** @internal */
13
+ export const nextId = () => `${marker}-${++id}`;
14
+ /**
15
+ * Common APIs related to markup generation.
16
+ * @public
17
+ */
18
+ export const Markup = Object.freeze({
19
+ /**
20
+ * Creates a placeholder string suitable for marking out a location *within*
21
+ * an attribute value or HTML content.
22
+ * @param index - The directive index to create the placeholder for.
23
+ * @remarks
24
+ * Used internally by binding directives.
25
+ */
26
+ interpolation: (id) => `${interpolationStart}${id}${interpolationEnd}`,
27
+ /**
28
+ * Creates a placeholder that manifests itself as an attribute on an
29
+ * element.
30
+ * @param attributeName - The name of the custom attribute.
31
+ * @param index - The directive index to create the placeholder for.
32
+ * @remarks
33
+ * Used internally by attribute directives such as `ref`, `slotted`, and `children`.
34
+ */
35
+ attribute: (id) => `${nextId()}="${interpolationStart}${id}${interpolationEnd}"`,
36
+ /**
37
+ * Creates a placeholder that manifests itself as a marker within the DOM structure.
38
+ * @param index - The directive index to create the placeholder for.
39
+ * @remarks
40
+ * Used internally by structural directives such as `repeat`.
41
+ */
42
+ comment: (id) => `<!--${interpolationStart}${id}${interpolationEnd}-->`,
43
+ });
44
+ /**
45
+ * Common APIs related to content parsing.
46
+ * @public
47
+ */
48
+ export const Parser = Object.freeze({
49
+ /**
50
+ * Parses text content or HTML attribute content, separating out the static strings
51
+ * from the directives.
52
+ * @param value - The content or attribute string to parse.
53
+ * @param factories - A list of directives to search for in the string.
54
+ * @returns A heterogeneous array of static strings interspersed with
55
+ * directives or null if no directives are found in the string.
56
+ */
57
+ parse(value, factories) {
58
+ // Split on the interpolation start marker. If there's only one part,
59
+ // no placeholders exist and we return null to signal "no directives here."
60
+ const parts = value.split(interpolationStart);
61
+ if (parts.length === 1) {
62
+ return null;
63
+ }
64
+ const result = [];
65
+ for (let i = 0, ii = parts.length; i < ii; ++i) {
66
+ const current = parts[i];
67
+ const index = current.indexOf(interpolationEnd);
68
+ let literal;
69
+ if (index === -1) {
70
+ literal = current;
71
+ }
72
+ else {
73
+ const factoryId = current.substring(0, index);
74
+ result.push(factories[factoryId]);
75
+ literal = current.substring(index + interpolationEndLength);
76
+ }
77
+ if (literal !== "") {
78
+ result.push(literal);
79
+ }
80
+ }
81
+ return result;
82
+ },
83
+ });
@@ -0,0 +1,84 @@
1
+ import { emptyArray } from "../platform.js";
2
+ import { StatelessAttachedAttributeDirective, } from "./html-directive.js";
3
+ const selectElements = (value) => value.nodeType === 1;
4
+ /**
5
+ * Creates a function that can be used to filter a Node array, selecting only elements.
6
+ * @param selector - An optional selector to restrict the filter to.
7
+ * @public
8
+ */
9
+ export const elements = (selector) => selector
10
+ ? value => value.nodeType === 1 && value.matches(selector)
11
+ : selectElements;
12
+ /**
13
+ * A base class for node observation.
14
+ * @public
15
+ * @remarks
16
+ * Internally used by the SlottedDirective and the ChildrenDirective.
17
+ */
18
+ export class NodeObservationDirective extends StatelessAttachedAttributeDirective {
19
+ /**
20
+ * The unique id of the factory.
21
+ */
22
+ get id() {
23
+ return this._id;
24
+ }
25
+ set id(value) {
26
+ this._id = value;
27
+ this._controllerProperty = `${value}-c`;
28
+ }
29
+ /**
30
+ * Bind this behavior to the source.
31
+ * @param source - The source to bind to.
32
+ * @param context - The execution context that the binding is operating within.
33
+ * @param targets - The targets that behaviors in a view can attach to.
34
+ */
35
+ bind(controller) {
36
+ const target = controller.targets[this.targetNodeId];
37
+ target[this._controllerProperty] = controller;
38
+ this.updateTarget(controller.source, this.computeNodes(target));
39
+ this.observe(target);
40
+ controller.onUnbind(this);
41
+ }
42
+ /**
43
+ * Unbinds this behavior from the source.
44
+ * @param source - The source to unbind from.
45
+ * @param context - The execution context that the binding is operating within.
46
+ * @param targets - The targets that behaviors in a view can attach to.
47
+ */
48
+ unbind(controller) {
49
+ const target = controller.targets[this.targetNodeId];
50
+ this.updateTarget(controller.source, emptyArray);
51
+ this.disconnect(target);
52
+ target[this._controllerProperty] = null;
53
+ }
54
+ /**
55
+ * Gets the data source for the target.
56
+ * @param target - The target to get the source for.
57
+ * @returns The source.
58
+ */
59
+ getSource(target) {
60
+ return target[this._controllerProperty].source;
61
+ }
62
+ /**
63
+ * Updates the source property with the computed nodes.
64
+ * @param source - The source object to assign the nodes property to.
65
+ * @param value - The nodes to assign to the source object property.
66
+ */
67
+ updateTarget(source, value) {
68
+ source[this.options.property] = value;
69
+ }
70
+ /**
71
+ * Computes the set of nodes that should be assigned to the source property.
72
+ * @param target - The target to compute the nodes for.
73
+ * @returns The computed nodes.
74
+ * @remarks
75
+ * Applies filters if provided.
76
+ */
77
+ computeNodes(target) {
78
+ let nodes = this.getNodes(target);
79
+ if ("filter" in this.options) {
80
+ nodes = nodes.filter(this.options.filter);
81
+ }
82
+ return nodes;
83
+ }
84
+ }
@@ -0,0 +1,21 @@
1
+ import { HTMLDirective, StatelessAttachedAttributeDirective, } from "./html-directive.js";
2
+ /**
3
+ * The runtime behavior for template references.
4
+ * @public
5
+ */
6
+ export class RefDirective extends StatelessAttachedAttributeDirective {
7
+ /**
8
+ * Bind this behavior.
9
+ * @param controller - The view controller that manages the lifecycle of this behavior.
10
+ */
11
+ bind(controller) {
12
+ controller.source[this.options] = controller.targets[this.targetNodeId];
13
+ }
14
+ }
15
+ HTMLDirective.define(RefDirective);
16
+ /**
17
+ * A directive that observes the updates a property with a reference to the element.
18
+ * @param propertyName - The name of the property to assign the reference to.
19
+ * @public
20
+ */
21
+ export const ref = (propertyName) => new RefDirective(propertyName);
@@ -0,0 +1,468 @@
1
+ import { Binding } from "../binding/binding.js";
2
+ import { normalizeBinding } from "../binding/normalize.js";
3
+ import { oneTime } from "../binding/one-time.js";
4
+ import { oneWay } from "../binding/one-way.js";
5
+ import { FASTElementDefinition } from "../components/fast-definitions.js";
6
+ import { isHydratable } from "../components/hydration.js";
7
+ import { isFunction, isString, Message } from "../interfaces.js";
8
+ import { FAST } from "../platform.js";
9
+ import { HTMLDirective, } from "./html-directive.js";
10
+ import { HydrationStage } from "./hydration-view.js";
11
+ import { Markup } from "./markup.js";
12
+ import { html, ViewTemplate, } from "./template.js";
13
+ import { createChildView } from "./view.js";
14
+ /**
15
+ * A Behavior that enables advanced rendering.
16
+ * @public
17
+ */
18
+ export class RenderBehavior {
19
+ /**
20
+ * Creates an instance of RenderBehavior.
21
+ * @param directive - The render directive that created this behavior.
22
+ */
23
+ constructor(directive) {
24
+ this.directive = directive;
25
+ this.location = null;
26
+ this.controller = null;
27
+ this.view = null;
28
+ this.data = null;
29
+ this.dataBindingObserver = directive.dataBinding.createObserver(this, directive);
30
+ this.templateBindingObserver = directive.templateBinding.createObserver(this, directive);
31
+ }
32
+ /**
33
+ * Bind this behavior.
34
+ * @param controller - The view controller that manages the lifecycle of this behavior.
35
+ */
36
+ bind(controller) {
37
+ this.location = controller.targets[this.directive.targetNodeId];
38
+ this.controller = controller;
39
+ this.data = this.dataBindingObserver.bind(controller);
40
+ this.template = this.templateBindingObserver.bind(controller);
41
+ controller.onUnbind(this);
42
+ if (isHydratable(this.template) &&
43
+ isHydratable(controller) &&
44
+ controller.hydrationStage !== HydrationStage.hydrated &&
45
+ !this.view) {
46
+ const viewNodes = controller.bindingViewBoundaries[this.directive.targetNodeId];
47
+ if (viewNodes) {
48
+ this.view = this.template.hydrate(viewNodes.first, viewNodes.last);
49
+ this.bindView(this.view);
50
+ return;
51
+ }
52
+ }
53
+ this.refreshView();
54
+ }
55
+ /**
56
+ * Unbinds this behavior.
57
+ * @param controller - The view controller that manages the lifecycle of this behavior.
58
+ */
59
+ unbind(controller) {
60
+ const view = this.view;
61
+ if (view !== null && view.isComposed) {
62
+ view.unbind();
63
+ view.needsBindOnly = true;
64
+ }
65
+ }
66
+ /**
67
+ * Handles changes from data or template binding observers.
68
+ * Guards against stale notifications that may arrive after the
69
+ * controller's view has been unbound (e.g., when a parent `when`
70
+ * directive tears down and later recreates a child element).
71
+ * @internal
72
+ */
73
+ handleChange(source, observer) {
74
+ // https://github.com/microsoft/fast/issues/7444
75
+ // This guard will be reconsidered in the next major version.
76
+ if (!this.controller.isBound) {
77
+ return;
78
+ }
79
+ if (observer === this.dataBindingObserver) {
80
+ this.data = this.dataBindingObserver.bind(this.controller);
81
+ }
82
+ if (this.directive.templateBindingDependsOnData ||
83
+ observer === this.templateBindingObserver) {
84
+ this.template = this.templateBindingObserver.bind(this.controller);
85
+ }
86
+ this.refreshView();
87
+ }
88
+ bindView(view) {
89
+ // It's possible that the value is the same as the previous template
90
+ // and that there's actually no need to compose it.
91
+ if (!view.isComposed) {
92
+ view.isComposed = true;
93
+ view.bind(this.data);
94
+ view.insertBefore(this.location);
95
+ view.$fastTemplate = this.template;
96
+ }
97
+ else if (view.needsBindOnly) {
98
+ view.needsBindOnly = false;
99
+ view.bind(this.data);
100
+ }
101
+ }
102
+ refreshView() {
103
+ let view = this.view;
104
+ const template = this.template;
105
+ if (view === null) {
106
+ this.view = view = createChildView(template, this.controller);
107
+ this.view.context.parent = this.controller.source;
108
+ this.view.context.parentContext = this.controller.context;
109
+ }
110
+ else {
111
+ // If there is a previous view, but it wasn't created
112
+ // from the same template as the new value, then we
113
+ // need to remove the old view if it's still in the DOM
114
+ // and create a new view from the template.
115
+ if (view.$fastTemplate !== template) {
116
+ if (view.isComposed) {
117
+ view.remove();
118
+ view.unbind();
119
+ }
120
+ this.view = view = createChildView(template, this.controller);
121
+ this.view.context.parent = this.controller.source;
122
+ this.view.context.parentContext = this.controller.context;
123
+ }
124
+ }
125
+ this.bindView(view);
126
+ }
127
+ }
128
+ /**
129
+ * A Directive that enables use of the RenderBehavior.
130
+ * @public
131
+ */
132
+ export class RenderDirective {
133
+ /**
134
+ * Creates an instance of RenderDirective.
135
+ * @param dataBinding - A binding expression that returns the data to render.
136
+ * @param templateBinding - A binding expression that returns the template to use to render the data.
137
+ */
138
+ constructor(dataBinding, templateBinding, templateBindingDependsOnData) {
139
+ this.dataBinding = dataBinding;
140
+ this.templateBinding = templateBinding;
141
+ this.templateBindingDependsOnData = templateBindingDependsOnData;
142
+ }
143
+ /**
144
+ * Creates HTML to be used within a template.
145
+ * @param add - Can be used to add behavior factories to a template.
146
+ */
147
+ createHTML(add) {
148
+ return Markup.comment(add(this));
149
+ }
150
+ /**
151
+ * Creates a behavior.
152
+ * @param targets - The targets available for behaviors to be attached to.
153
+ */
154
+ createBehavior() {
155
+ return new RenderBehavior(this);
156
+ }
157
+ }
158
+ HTMLDirective.define(RenderDirective);
159
+ function isElementRenderOptions(object) {
160
+ return !!object.element || !!object.tagName;
161
+ }
162
+ const typeToInstructionLookup = new Map();
163
+ /* eslint @typescript-eslint/naming-convention: "off"*/
164
+ const defaultAttributes = { ":model": (x) => x };
165
+ const brand = Symbol("RenderInstruction");
166
+ const defaultViewName = "default-view";
167
+ const nullTemplate = html `
168
+ &nbsp;
169
+ `;
170
+ function instructionToTemplate(def) {
171
+ if (def === void 0) {
172
+ return nullTemplate;
173
+ }
174
+ return def.template;
175
+ }
176
+ function resolveTemplateBindingValue(result, dataBinding, source, context) {
177
+ var _a;
178
+ if (isString(result)) {
179
+ return instructionToTemplate(getForInstance(dataBinding.evaluate(source, context), result));
180
+ }
181
+ if (result instanceof Node) {
182
+ return (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
183
+ }
184
+ return result;
185
+ }
186
+ function adaptTemplateBinding(binding, dataBinding) {
187
+ const evaluateTemplate = binding.evaluate;
188
+ const adapter = Object.create(Object.getPrototypeOf(binding));
189
+ for (const propertyName of Object.getOwnPropertyNames(binding)) {
190
+ if (propertyName !== "evaluate") {
191
+ Object.defineProperty(adapter, propertyName, Object.getOwnPropertyDescriptor(binding, propertyName));
192
+ }
193
+ }
194
+ Object.defineProperty(adapter, "evaluate", {
195
+ configurable: true,
196
+ enumerable: true,
197
+ value: (source, context) => resolveTemplateBindingValue(evaluateTemplate(source, context), dataBinding, source, context),
198
+ writable: true,
199
+ });
200
+ return adapter;
201
+ }
202
+ function createElementTemplate(tagName, options) {
203
+ const markup = [];
204
+ const values = [];
205
+ const { attributes, directives, content, policy } = options !== null && options !== void 0 ? options : {};
206
+ markup.push(`<${tagName}`);
207
+ if (attributes) {
208
+ const attrNames = Object.getOwnPropertyNames(attributes);
209
+ for (let i = 0, ii = attrNames.length; i < ii; ++i) {
210
+ const name = attrNames[i];
211
+ if (i === 0) {
212
+ markup[0] = `${markup[0]} ${name}="`;
213
+ }
214
+ else {
215
+ markup.push(`" ${name}="`);
216
+ }
217
+ values.push(attributes[name]);
218
+ }
219
+ markup.push(`"`);
220
+ }
221
+ if (directives) {
222
+ markup[markup.length - 1] += " ";
223
+ for (let i = 0, ii = directives.length; i < ii; ++i) {
224
+ const directive = directives[i];
225
+ markup.push(i > 0 ? "" : " ");
226
+ values.push(directive);
227
+ }
228
+ }
229
+ markup[markup.length - 1] += ">";
230
+ if (content && isFunction(content.create)) {
231
+ values.push(content);
232
+ markup.push(`</${tagName}>`);
233
+ }
234
+ else {
235
+ const lastIndex = markup.length - 1;
236
+ markup[lastIndex] = `${markup[lastIndex]}${content !== null && content !== void 0 ? content : ""}</${tagName}>`;
237
+ }
238
+ return ViewTemplate.create(markup, values, policy);
239
+ }
240
+ function create(options) {
241
+ var _a;
242
+ const name = (_a = options.name) !== null && _a !== void 0 ? _a : defaultViewName;
243
+ let template;
244
+ if (isElementRenderOptions(options)) {
245
+ let tagName = options.tagName;
246
+ if (!tagName) {
247
+ const def = FASTElementDefinition.getByType(options.element);
248
+ if (def) {
249
+ tagName = def.name;
250
+ }
251
+ else {
252
+ throw new Error("Invalid element for model rendering.");
253
+ }
254
+ }
255
+ if (!options.attributes) {
256
+ options.attributes = defaultAttributes;
257
+ }
258
+ template = createElementTemplate(tagName, options);
259
+ }
260
+ else {
261
+ template = options.template;
262
+ }
263
+ return {
264
+ brand,
265
+ type: options.type,
266
+ name,
267
+ template,
268
+ };
269
+ }
270
+ function instanceOf(object) {
271
+ return object && object.brand === brand;
272
+ }
273
+ function register(optionsOrInstruction) {
274
+ let lookup = typeToInstructionLookup.get(optionsOrInstruction.type);
275
+ if (lookup === void 0) {
276
+ typeToInstructionLookup.set(optionsOrInstruction.type, (lookup = Object.create(null)));
277
+ }
278
+ const instruction = instanceOf(optionsOrInstruction)
279
+ ? optionsOrInstruction
280
+ : create(optionsOrInstruction);
281
+ if (lookup[instruction.name] !== void 0) {
282
+ const typeName = instruction.type.name || "(anonymous)";
283
+ FAST.warn(Message.duplicateRenderInstruction, {
284
+ type: typeName,
285
+ name: instruction.name,
286
+ });
287
+ }
288
+ return (lookup[instruction.name] = instruction);
289
+ }
290
+ function getByType(type, name) {
291
+ const entries = typeToInstructionLookup.get(type);
292
+ if (entries === void 0) {
293
+ return void 0;
294
+ }
295
+ return entries[name !== null && name !== void 0 ? name : defaultViewName];
296
+ }
297
+ function getForInstance(object, name) {
298
+ if (object) {
299
+ return getByType(object.constructor, name);
300
+ }
301
+ return void 0;
302
+ }
303
+ /**
304
+ * Provides APIs for creating and interacting with render instructions.
305
+ * @public
306
+ */
307
+ export const RenderInstruction = Object.freeze({
308
+ /**
309
+ * Checks whether the provided object is a RenderInstruction.
310
+ * @param object - The object to check.
311
+ * @returns true if the object is a RenderInstruction; false otherwise
312
+ */
313
+ instanceOf,
314
+ /**
315
+ * Creates a RenderInstruction for a set of options.
316
+ * @param options - The options to use when creating the RenderInstruction.
317
+ * @remarks
318
+ * This API should be used with caution. When providing attributes or content,
319
+ * if not done properly, you can open up the application to XSS attacks. When using this API,
320
+ * provide a strong DOMPolicy that can properly sanitize and also be sure to manually sanitize
321
+ * content and attribute values particularly if they can come from user input.
322
+ */
323
+ create,
324
+ /**
325
+ * Creates a template based on a tag name.
326
+ * @param tagName - The tag name to use when creating the template.
327
+ * @param attributes - The attributes to apply to the element.
328
+ * @param content - The content to insert into the element.
329
+ * @param policy - The DOMPolicy to create the template with.
330
+ * @returns A template based on the provided specifications.
331
+ * @remarks
332
+ * This API should be used with caution. When providing attributes or content,
333
+ * if not done properly, you can open up the application to XSS attacks. When using this API,
334
+ * provide a strong DOMPolicy that can properly sanitize and also be sure to manually sanitize
335
+ * content and attribute values particularly if they can come from user input.
336
+ */
337
+ createElementTemplate,
338
+ /**
339
+ * Creates and registers an instruction.
340
+ * @param options The options to use when creating the RenderInstruction.
341
+ * @remarks
342
+ * A previously created RenderInstruction can also be registered.
343
+ */
344
+ register,
345
+ /**
346
+ * Finds a previously registered RenderInstruction by type and optionally by name.
347
+ * @param type - The type to retrieve the RenderInstruction for.
348
+ * @param name - An optional name used in differentiating between multiple registered instructions.
349
+ * @returns The located RenderInstruction that matches the criteria or undefined if none is found.
350
+ */
351
+ getByType,
352
+ /**
353
+ * Finds a previously registered RenderInstruction for the instance's type and optionally by name.
354
+ * @param object - The instance to retrieve the RenderInstruction for.
355
+ * @param name - An optional name used in differentiating between multiple registered instructions.
356
+ * @returns The located RenderInstruction that matches the criteria or undefined if none is found.
357
+ */
358
+ getForInstance,
359
+ });
360
+ export function renderWith(value, name) {
361
+ return function (type) {
362
+ if (isFunction(value)) {
363
+ register({ type, element: value, name });
364
+ }
365
+ else if (isFunction(value.create)) {
366
+ register({ type, template: value, name });
367
+ }
368
+ else {
369
+ register(Object.assign({ type }, value));
370
+ }
371
+ };
372
+ }
373
+ /**
374
+ * @internal
375
+ */
376
+ export class NodeTemplate {
377
+ constructor(node) {
378
+ this.node = node;
379
+ node.$fastTemplate = this;
380
+ }
381
+ get context() {
382
+ // HACK
383
+ return this;
384
+ }
385
+ bind(source) { }
386
+ unbind() { }
387
+ insertBefore(refNode) {
388
+ refNode.parentNode.insertBefore(this.node, refNode);
389
+ }
390
+ remove() {
391
+ this.node.parentNode.removeChild(this.node);
392
+ }
393
+ create() {
394
+ return this;
395
+ }
396
+ hydrate(first, last) {
397
+ return this;
398
+ }
399
+ }
400
+ /**
401
+ * Creates a RenderDirective for use in advanced rendering scenarios.
402
+ * @param value - The binding expression that returns the data to be rendered. The expression
403
+ * can also return a Node to render directly.
404
+ * @param template - A template to render the data with
405
+ * or a string to indicate which RenderInstruction to use when looking up a RenderInstruction.
406
+ * Expressions can also be provided to dynamically determine either the template or the name.
407
+ * @returns A RenderDirective suitable for use in a template.
408
+ * @remarks
409
+ * If no binding is provided, then a default binding that returns the source is created.
410
+ * If no template is provided, then a binding is created that will use registered
411
+ * RenderInstructions to determine the view.
412
+ * If the template binding returns a string, then it will be used to look up a
413
+ * RenderInstruction to determine the view.
414
+ * @public
415
+ */
416
+ export function render(value, template) {
417
+ let dataBinding;
418
+ if (value === void 0) {
419
+ dataBinding = oneTime((source) => source);
420
+ }
421
+ else {
422
+ dataBinding = normalizeBinding(value);
423
+ }
424
+ let templateBinding;
425
+ let templateBindingDependsOnData = false;
426
+ if (template === void 0) {
427
+ templateBindingDependsOnData = true;
428
+ templateBinding = oneTime((s, c) => {
429
+ var _a;
430
+ const data = dataBinding.evaluate(s, c);
431
+ if (data instanceof Node) {
432
+ return (_a = data.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(data);
433
+ }
434
+ return instructionToTemplate(getForInstance(data));
435
+ });
436
+ }
437
+ else if (isFunction(template)) {
438
+ templateBinding = oneWay((s, c) => {
439
+ var _a;
440
+ let result = template(s, c);
441
+ if (isString(result)) {
442
+ result = instructionToTemplate(getForInstance(dataBinding.evaluate(s, c), result));
443
+ }
444
+ else if (result instanceof Node) {
445
+ result = (_a = result.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(result);
446
+ }
447
+ return result;
448
+ }, void 0, true);
449
+ }
450
+ else if (isString(template)) {
451
+ templateBindingDependsOnData = true;
452
+ templateBinding = oneTime((s, c) => {
453
+ var _a;
454
+ const data = dataBinding.evaluate(s, c);
455
+ if (data instanceof Node) {
456
+ return (_a = data.$fastTemplate) !== null && _a !== void 0 ? _a : new NodeTemplate(data);
457
+ }
458
+ return instructionToTemplate(getForInstance(data, template));
459
+ });
460
+ }
461
+ else if (template instanceof Binding) {
462
+ templateBinding = adaptTemplateBinding(template, dataBinding);
463
+ }
464
+ else {
465
+ templateBinding = oneTime((s, c) => template);
466
+ }
467
+ return new RenderDirective(dataBinding, templateBinding, templateBindingDependsOnData);
468
+ }