@lushly-dev/fast-element 3.0.1-preview.0 → 3.0.1-preview.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 (250) hide show
  1. package/CHANGELOG.md +6 -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 +15 -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 +110 -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 +312 -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 +752 -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 +511 -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 +839 -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 +210 -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 +121 -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 +1440 -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 +63 -0
  192. package/dist/esm/observation/arrays.js +661 -0
  193. package/dist/esm/observation/notifier.js +164 -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 +7618 -0
  243. package/dist/fast-element.debug.min.js +3 -0
  244. package/dist/fast-element.js +7617 -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 +12 -12
@@ -0,0 +1,434 @@
1
+ import { normalizeBinding } from "../binding/normalize.js";
2
+ import { HydrationMarkup, isHydratable } from "../components/hydration.js";
3
+ import { ArrayObserver } from "../observation/arrays.js";
4
+ import { Observable, } from "../observation/observable.js";
5
+ import { emptyArray } from "../platform.js";
6
+ import { HTMLDirective, } from "./html-directive.js";
7
+ import { HydrationStage } from "./hydration-view.js";
8
+ import { Markup } from "./markup.js";
9
+ import { createChildView, HTMLView } from "./view.js";
10
+ const defaultRepeatOptions = Object.freeze({
11
+ positioning: false,
12
+ recycle: true,
13
+ });
14
+ function bindWithoutPositioning(view, items, index, controller) {
15
+ view.context.parent = controller.source;
16
+ view.context.parentContext = controller.context;
17
+ view.bind(items[index]);
18
+ }
19
+ function bindWithPositioning(view, items, index, controller) {
20
+ view.context.parent = controller.source;
21
+ view.context.parentContext = controller.context;
22
+ view.context.length = items.length;
23
+ view.context.index = index;
24
+ view.bind(items[index]);
25
+ }
26
+ function isCommentNode(node) {
27
+ return node.nodeType === Node.COMMENT_NODE;
28
+ }
29
+ function removeNodeRange(first, last) {
30
+ const parentNode = first.parentNode;
31
+ if (parentNode === null) {
32
+ return;
33
+ }
34
+ let current = first;
35
+ while (current !== null) {
36
+ const next = current.nextSibling;
37
+ parentNode.removeChild(current);
38
+ if (current === last) {
39
+ break;
40
+ }
41
+ current = next;
42
+ }
43
+ }
44
+ export class HydrationRepeatError extends Error {
45
+ constructor(
46
+ /**
47
+ * The error message
48
+ */
49
+ message, propertyBag) {
50
+ super(message);
51
+ this.propertyBag = propertyBag;
52
+ }
53
+ }
54
+ /**
55
+ * A behavior that renders a template for each item in an array.
56
+ * @public
57
+ */
58
+ export class RepeatBehavior {
59
+ /**
60
+ * Creates an instance of RepeatBehavior.
61
+ * @param location - The location in the DOM to render the repeat.
62
+ * @param dataBinding - The array to render.
63
+ * @param isItemsBindingVolatile - Indicates whether the items binding has volatile dependencies.
64
+ * @param templateBinding - The template to render for each item.
65
+ * @param isTemplateBindingVolatile - Indicates whether the template binding has volatile dependencies.
66
+ * @param options - Options used to turn on special repeat features.
67
+ */
68
+ constructor(directive) {
69
+ this.directive = directive;
70
+ this.isBound = false;
71
+ this.items = null;
72
+ this.itemsObserver = null;
73
+ this.bindView = bindWithoutPositioning;
74
+ /** @internal */
75
+ this.views = [];
76
+ this.itemsBindingObserver = directive.dataBinding.createObserver(this, directive);
77
+ this.templateBindingObserver = directive.templateBinding.createObserver(this, directive);
78
+ if (directive.options.positioning) {
79
+ this.bindView = bindWithPositioning;
80
+ }
81
+ }
82
+ /**
83
+ * Bind this behavior.
84
+ * @param controller - The view controller that manages the lifecycle of this behavior.
85
+ */
86
+ bind(controller) {
87
+ this.location = controller.targets[this.directive.targetNodeId];
88
+ this.controller = controller;
89
+ this.isBound = true;
90
+ this.items = this.itemsBindingObserver.bind(controller);
91
+ this.template = this.templateBindingObserver.bind(controller);
92
+ this.observeItems(true);
93
+ if (isHydratable(this.template) &&
94
+ isHydratable(controller) &&
95
+ controller.hydrationStage !== HydrationStage.hydrated) {
96
+ this.hydrateViews(this.template);
97
+ }
98
+ else {
99
+ this.refreshAllViews();
100
+ }
101
+ controller.onUnbind(this);
102
+ }
103
+ /**
104
+ * Unbinds this behavior.
105
+ */
106
+ unbind() {
107
+ this.isBound = false;
108
+ if (this.itemsObserver !== null) {
109
+ this.itemsObserver.unsubscribe(this);
110
+ }
111
+ this.unbindAllViews();
112
+ }
113
+ /**
114
+ * Handles changes in the array, its items, and the repeat template.
115
+ * @param source - The source of the change.
116
+ * @param args - The details about what was changed.
117
+ */
118
+ handleChange(source, args) {
119
+ // Notifications queued before unbind must not reobserve a cleared view source.
120
+ if (!this.isBound) {
121
+ return;
122
+ }
123
+ if (args === this.itemsBindingObserver) {
124
+ this.items = this.itemsBindingObserver.bind(this.controller);
125
+ this.observeItems();
126
+ this.refreshAllViews();
127
+ }
128
+ else if (args === this.templateBindingObserver) {
129
+ this.template = this.templateBindingObserver.bind(this.controller);
130
+ this.refreshAllViews(true);
131
+ }
132
+ else if (!args[0]) {
133
+ return;
134
+ }
135
+ else if (args[0].reset) {
136
+ this.refreshAllViews();
137
+ }
138
+ else if (args[0].sorted) {
139
+ this.updateSortedViews(args);
140
+ }
141
+ else {
142
+ this.updateSplicedViews(args);
143
+ }
144
+ }
145
+ observeItems(force = false) {
146
+ if (!this.items) {
147
+ this.items = emptyArray;
148
+ return;
149
+ }
150
+ const oldObserver = this.itemsObserver;
151
+ const newObserver = (this.itemsObserver = Observable.getNotifier(this.items));
152
+ const hasNewObserver = oldObserver !== newObserver;
153
+ if (hasNewObserver && oldObserver !== null) {
154
+ oldObserver.unsubscribe(this);
155
+ }
156
+ if (hasNewObserver || force) {
157
+ newObserver.subscribe(this);
158
+ }
159
+ }
160
+ updateSortedViews(sorts) {
161
+ const views = this.views;
162
+ for (let i = 0, ii = sorts.length; i < ii; ++i) {
163
+ const sortedItems = sorts[i].sorted.slice();
164
+ const unsortedItems = sortedItems.slice().sort();
165
+ for (let j = 0, jj = sortedItems.length; j < jj; ++j) {
166
+ const sortedIndex = sortedItems.find(value => sortedItems[j] === unsortedItems[value]);
167
+ if (sortedIndex !== j) {
168
+ const removedItems = unsortedItems.splice(sortedIndex, 1);
169
+ unsortedItems.splice(j, 0, ...removedItems);
170
+ const neighbor = views[j];
171
+ const location = neighbor ? neighbor.firstChild : this.location;
172
+ views[sortedIndex].remove();
173
+ views[sortedIndex].insertBefore(location);
174
+ const removedViews = views.splice(sortedIndex, 1);
175
+ views.splice(j, 0, ...removedViews);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ updateSplicedViews(splices) {
181
+ const views = this.views;
182
+ const bindView = this.bindView;
183
+ const items = this.items;
184
+ const template = this.template;
185
+ const controller = this.controller;
186
+ const recycle = this.directive.options.recycle;
187
+ const leftoverViews = [];
188
+ let leftoverIndex = 0;
189
+ let availableViews = 0;
190
+ for (let i = 0, ii = splices.length; i < ii; ++i) {
191
+ const splice = splices[i];
192
+ const removed = splice.removed;
193
+ let removeIndex = 0;
194
+ let addIndex = splice.index;
195
+ const end = addIndex + splice.addedCount;
196
+ const removedViews = views.splice(splice.index, removed.length);
197
+ const totalAvailableViews = (availableViews =
198
+ leftoverViews.length + removedViews.length);
199
+ for (; addIndex < end; ++addIndex) {
200
+ const neighbor = views[addIndex];
201
+ const location = neighbor ? neighbor.firstChild : this.location;
202
+ let view;
203
+ if (recycle && availableViews > 0) {
204
+ if (removeIndex <= totalAvailableViews && removedViews.length > 0) {
205
+ view = removedViews[removeIndex];
206
+ removeIndex++;
207
+ }
208
+ else {
209
+ view = leftoverViews[leftoverIndex];
210
+ leftoverIndex++;
211
+ }
212
+ availableViews--;
213
+ }
214
+ else {
215
+ view = createChildView(template, controller);
216
+ }
217
+ views.splice(addIndex, 0, view);
218
+ bindView(view, items, addIndex, controller);
219
+ view.insertBefore(location);
220
+ }
221
+ if (removedViews[removeIndex]) {
222
+ leftoverViews.push(...removedViews.slice(removeIndex));
223
+ }
224
+ }
225
+ for (let i = leftoverIndex, ii = leftoverViews.length; i < ii; ++i) {
226
+ leftoverViews[i].dispose();
227
+ }
228
+ if (this.directive.options.positioning) {
229
+ for (let i = 0, viewsLength = views.length; i < viewsLength; ++i) {
230
+ const context = views[i].context;
231
+ context.length = viewsLength;
232
+ context.index = i;
233
+ }
234
+ }
235
+ }
236
+ refreshAllViews(templateChanged = false) {
237
+ const items = this.items;
238
+ const template = this.template;
239
+ const location = this.location;
240
+ const bindView = this.bindView;
241
+ const controller = this.controller;
242
+ let itemsLength = items.length;
243
+ let views = this.views;
244
+ let viewsLength = views.length;
245
+ if (itemsLength === 0 || templateChanged || !this.directive.options.recycle) {
246
+ // all views need to be removed
247
+ HTMLView.disposeContiguousBatch(views);
248
+ viewsLength = 0;
249
+ }
250
+ if (viewsLength === 0) {
251
+ // all views need to be created
252
+ this.views = views = new Array(itemsLength);
253
+ for (let i = 0; i < itemsLength; ++i) {
254
+ const view = createChildView(template, controller);
255
+ bindView(view, items, i, controller);
256
+ views[i] = view;
257
+ view.insertBefore(location);
258
+ }
259
+ }
260
+ else {
261
+ // attempt to reuse existing views with new data
262
+ let i = 0;
263
+ for (; i < itemsLength; ++i) {
264
+ if (i < viewsLength) {
265
+ const view = views[i];
266
+ if (!view) {
267
+ const serializer = new XMLSerializer();
268
+ throw new HydrationRepeatError(`View is null or undefined inside "${this.location.getRootNode().host.nodeName}".`, {
269
+ index: i,
270
+ hydrationStage: this.controller
271
+ .hydrationStage,
272
+ itemsLength,
273
+ viewsState: views.map(v => (v ? "hydrated" : "empty")),
274
+ viewTemplateString: serializer.serializeToString(template.create().fragment),
275
+ rootNodeContent: serializer.serializeToString(this.location.getRootNode()),
276
+ });
277
+ }
278
+ bindView(view, items, i, controller);
279
+ }
280
+ else {
281
+ const view = createChildView(template, controller);
282
+ bindView(view, items, i, controller);
283
+ views.push(view);
284
+ view.insertBefore(location);
285
+ }
286
+ }
287
+ const removed = views.splice(i, viewsLength - i);
288
+ for (i = 0, itemsLength = removed.length; i < itemsLength; ++i) {
289
+ removed[i].dispose();
290
+ }
291
+ }
292
+ }
293
+ unbindAllViews() {
294
+ const views = this.views;
295
+ for (let i = 0, ii = views.length; i < ii; ++i) {
296
+ const view = views[i];
297
+ if (!view) {
298
+ const serializer = new XMLSerializer();
299
+ throw new HydrationRepeatError(`View is null or undefined inside "${this.location.getRootNode().host.nodeName}".`, {
300
+ index: i,
301
+ hydrationStage: this.controller.hydrationStage,
302
+ viewsState: views.map(v => (v ? "hydrated" : "empty")),
303
+ rootNodeContent: serializer.serializeToString(this.location.getRootNode()),
304
+ });
305
+ }
306
+ view.unbind();
307
+ }
308
+ }
309
+ hydrateViews(template) {
310
+ var _a;
311
+ if (!this.items) {
312
+ return;
313
+ }
314
+ const items = this.items;
315
+ const itemCount = items.length;
316
+ const views = (this.views = new Array(itemCount));
317
+ // First pass: collect all repeat marker pairs by walking backward.
318
+ // Each entry tracks both the item content range and its SSR markers.
319
+ const itemRanges = [];
320
+ let current = this.location.previousSibling;
321
+ while (current !== null) {
322
+ if (!isCommentNode(current) ||
323
+ !HydrationMarkup.isRepeatViewEndMarker(current.data)) {
324
+ current = current.previousSibling;
325
+ continue;
326
+ }
327
+ const endMarker = current;
328
+ endMarker.data = "";
329
+ const end = endMarker.previousSibling;
330
+ if (!end) {
331
+ throw new Error(`Error when hydrating inside "${this.location.getRootNode().host.nodeName}": end should never be null.`);
332
+ }
333
+ // Find matching start marker via balanced counting
334
+ let start = end;
335
+ let depth = 0;
336
+ while (start !== null) {
337
+ if (isCommentNode(start)) {
338
+ if (HydrationMarkup.isRepeatViewEndMarker(start.data)) {
339
+ depth++;
340
+ }
341
+ else if (HydrationMarkup.isRepeatViewStartMarker(start.data)) {
342
+ if (depth === 0) {
343
+ const startMarker = start;
344
+ startMarker.data = "";
345
+ current = startMarker.previousSibling;
346
+ const itemStart = (_a = startMarker.nextSibling) !== null && _a !== void 0 ? _a : endMarker;
347
+ // Empty item: start and end markers are adjacent.
348
+ const itemEnd = end === startMarker ? itemStart : end;
349
+ itemRanges.push({
350
+ start: itemStart,
351
+ end: itemEnd,
352
+ startMarker,
353
+ endMarker,
354
+ });
355
+ break;
356
+ }
357
+ depth--;
358
+ }
359
+ }
360
+ start = start.previousSibling;
361
+ }
362
+ if (!start) {
363
+ throw new Error(`Error when hydrating inside "${this.location.getRootNode().host.nodeName}": repeat start marker not found.`);
364
+ }
365
+ }
366
+ // Ranges were collected backward (last item first).
367
+ // Reverse so index 0 = first SSR item.
368
+ itemRanges.reverse();
369
+ // Hydrate each SSR item at its correct index (0-based from start).
370
+ const hydrationCount = Math.min(itemRanges.length, itemCount);
371
+ for (let i = 0; i < hydrationCount; i++) {
372
+ const { start, end } = itemRanges[i];
373
+ const view = template.hydrate(start, end);
374
+ views[i] = view;
375
+ this.bindView(view, items, i, this.controller);
376
+ }
377
+ for (let i = hydrationCount; i < itemCount; i++) {
378
+ const view = createChildView(template, this.controller);
379
+ views[i] = view;
380
+ this.bindView(view, items, i, this.controller);
381
+ view.insertBefore(this.location);
382
+ }
383
+ for (let i = itemCount, ii = itemRanges.length; i < ii; i++) {
384
+ const { startMarker, endMarker } = itemRanges[i];
385
+ removeNodeRange(startMarker, endMarker);
386
+ }
387
+ }
388
+ }
389
+ /**
390
+ * A directive that configures list rendering.
391
+ * @public
392
+ */
393
+ export class RepeatDirective {
394
+ /**
395
+ * Creates a placeholder string based on the directive's index within the template.
396
+ * @param index - The index of the directive within the template.
397
+ */
398
+ createHTML(add) {
399
+ return Markup.comment(add(this));
400
+ }
401
+ /**
402
+ * Creates an instance of RepeatDirective.
403
+ * @param dataBinding - The binding that provides the array to render.
404
+ * @param templateBinding - The template binding used to obtain a template to render for each item in the array.
405
+ * @param options - Options used to turn on special repeat features.
406
+ */
407
+ constructor(dataBinding, templateBinding, options) {
408
+ this.dataBinding = dataBinding;
409
+ this.templateBinding = templateBinding;
410
+ this.options = options;
411
+ ArrayObserver.enable();
412
+ }
413
+ /**
414
+ * Creates a behavior for the provided target node.
415
+ * @param target - The node instance to create the behavior for.
416
+ */
417
+ createBehavior() {
418
+ return new RepeatBehavior(this);
419
+ }
420
+ }
421
+ HTMLDirective.define(RepeatDirective);
422
+ /**
423
+ * A directive that enables list rendering.
424
+ * @param items - The array to render.
425
+ * @param template - The template or a template binding used obtain a template
426
+ * to render for each item in the array.
427
+ * @param options - Options used to turn on special repeat features.
428
+ * @public
429
+ */
430
+ export function repeat(items, template, options = defaultRepeatOptions) {
431
+ const dataBinding = normalizeBinding(items);
432
+ const templateBinding = normalizeBinding(template);
433
+ return new RepeatDirective(dataBinding, templateBinding, Object.assign(Object.assign({}, defaultRepeatOptions), options));
434
+ }
@@ -0,0 +1,49 @@
1
+ import { isString } from "../interfaces.js";
2
+ import { HTMLDirective } from "./html-directive.js";
3
+ import { NodeObservationDirective, } from "./node-observation.js";
4
+ const slotEvent = "slotchange";
5
+ /**
6
+ * The runtime behavior for slotted node observation.
7
+ * @public
8
+ */
9
+ export class SlottedDirective extends NodeObservationDirective {
10
+ /**
11
+ * Begins observation of the nodes.
12
+ * @param target - The target to observe.
13
+ */
14
+ observe(target) {
15
+ target.addEventListener(slotEvent, this);
16
+ }
17
+ /**
18
+ * Disconnects observation of the nodes.
19
+ * @param target - The target to unobserve.
20
+ */
21
+ disconnect(target) {
22
+ target.removeEventListener(slotEvent, this);
23
+ }
24
+ /**
25
+ * Retrieves the raw nodes that should be assigned to the source property.
26
+ * @param target - The target to get the node to.
27
+ */
28
+ getNodes(target) {
29
+ return target.assignedNodes(this.options);
30
+ }
31
+ /** @internal */
32
+ handleEvent(event) {
33
+ const target = event.currentTarget;
34
+ this.updateTarget(this.getSource(target), this.computeNodes(target));
35
+ }
36
+ }
37
+ HTMLDirective.define(SlottedDirective);
38
+ /**
39
+ * A directive that observes the `assignedNodes()` of a slot and updates a property
40
+ * whenever they change.
41
+ * @param propertyOrOptions - The options used to configure slotted node observation.
42
+ * @public
43
+ */
44
+ export function slotted(propertyOrOptions) {
45
+ if (isString(propertyOrOptions)) {
46
+ propertyOrOptions = { property: propertyOrOptions };
47
+ }
48
+ return new SlottedDirective(propertyOrOptions);
49
+ }
@@ -0,0 +1,206 @@
1
+ import { Binding } from "../binding/binding.js";
2
+ import { oneTime } from "../binding/one-time.js";
3
+ import { oneWay } from "../binding/one-way.js";
4
+ import { isFunction, isString, Message } from "../interfaces.js";
5
+ import { FAST, makeSerializationNoop } from "../platform.js";
6
+ import { Compiler } from "./compiler.js";
7
+ import { HTMLBindingDirective } from "./html-binding-directive.js";
8
+ import { HTMLDirective, } from "./html-directive.js";
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
+ }
54
+ /**
55
+ * A template capable of creating HTMLView instances or rendering directly to DOM.
56
+ * @public
57
+ */
58
+ export class ViewTemplate {
59
+ /**
60
+ * Creates an instance of ViewTemplate.
61
+ * @param html - The html representing what this template will instantiate, including placeholders for directives.
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.
64
+ */
65
+ constructor(html, factories = {}, policy) {
66
+ this.policy = policy;
67
+ this.result = null;
68
+ this.html = html;
69
+ this.factories = factories;
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
+ }
80
+ /**
81
+ * Returns a directive that can inline the template.
82
+ */
83
+ inline() {
84
+ return new InlineTemplateDirective(isString(this.html) ? this.html : this.html.innerHTML, this.factories);
85
+ }
86
+ /**
87
+ * Sets the DOMPolicy for this template.
88
+ * @param policy - The policy to associated with this template.
89
+ * @returns The modified template instance.
90
+ * @remarks
91
+ * The DOMPolicy can only be set once for a template and cannot be
92
+ * set after the template is compiled.
93
+ */
94
+ withPolicy(policy) {
95
+ if (this.result) {
96
+ throw FAST.error(Message.cannotSetTemplatePolicyAfterCompilation);
97
+ }
98
+ if (this.policy) {
99
+ throw FAST.error(Message.onlySetTemplatePolicyOnce);
100
+ }
101
+ this.policy = policy;
102
+ return this;
103
+ }
104
+ /**
105
+ * Creates an HTMLView from this template, binds it to the source, and then appends it to the host.
106
+ * @param source - The data source to bind the template to.
107
+ * @param host - The Element where the template will be rendered.
108
+ * @param hostBindingTarget - An HTML element to target the host bindings at if different from the
109
+ * host that the template is being attached to.
110
+ * @param scope - The shadow root whose scoped custom element registry child
111
+ * elements should be created against, when it has one.
112
+ */
113
+ render(source, host, hostBindingTarget, scope) {
114
+ const view = this.create(hostBindingTarget, scope);
115
+ view.bind(source);
116
+ view.appendTo(host);
117
+ return view;
118
+ }
119
+ /**
120
+ * Creates an HTMLView instance based on this template definition.
121
+ * @param hostBindingTarget - The element that host behaviors will be bound to.
122
+ * @param scope - The shadow root whose scoped custom element registry child
123
+ * elements should be created against, when it has one.
124
+ */
125
+ create(hostBindingTarget, scope) {
126
+ return this.compile().createView(hostBindingTarget, scope);
127
+ }
128
+ /**
129
+ * Processes the tagged template literal's static strings and interpolated values and
130
+ * creates a ViewTemplate.
131
+ *
132
+ * For each interpolated value:
133
+ * 1. Functions (binding expressions, e.g., `x => x.name`) → wrapped in a one-way HTMLBindingDirective
134
+ * 2. Binding instances → wrapped in an HTMLBindingDirective
135
+ * 3. HTMLDirective instances → used as-is
136
+ * 4. Static values (strings, numbers) → wrapped in a one-time HTMLBindingDirective
137
+ *
138
+ * Each directive's createHTML() is called with an `add` callback that registers
139
+ * the factory in the factories record under a unique ID and returns that ID.
140
+ * The directive inserts a placeholder marker (e.g., `fast-abc123{0}fast-abc123`) into
141
+ * the HTML string so the compiler can later find and associate it with the factory.
142
+ *
143
+ * Aspect detection happens here too: the `lastAttributeNameRegex` checks whether
144
+ * the placeholder appears inside an attribute value, and if so, assignAspect()
145
+ * sets the correct DOMAspect (attribute, property, event, etc.) based on the
146
+ * attribute name prefix.
147
+ *
148
+ * @param strings - The static strings to create the template with.
149
+ * @param values - The dynamic values to create the template with.
150
+ * @param policy - The DOMPolicy to associated with the template.
151
+ * @returns A ViewTemplate.
152
+ * @remarks
153
+ * This API should not be used directly under normal circumstances because constructing
154
+ * a template in this way, if not done properly, can open up the application to XSS
155
+ * attacks. When using this API, provide a strong DOMPolicy that can properly sanitize
156
+ * and also be sure to manually sanitize all static strings particularly if they can
157
+ * come from user input.
158
+ */
159
+ static create(strings, values, policy) {
160
+ let html = "";
161
+ const factories = Object.create(null);
162
+ const add = (factory) => {
163
+ var _a;
164
+ const id = (_a = factory.id) !== null && _a !== void 0 ? _a : (factory.id = nextId());
165
+ factories[id] = factory;
166
+ return id;
167
+ };
168
+ for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
169
+ const currentString = strings[i];
170
+ let currentValue = values[i];
171
+ let definition;
172
+ html += currentString;
173
+ if (isFunction(currentValue)) {
174
+ currentValue = new HTMLBindingDirective(oneWay(currentValue));
175
+ }
176
+ else if (currentValue instanceof Binding) {
177
+ currentValue = new HTMLBindingDirective(currentValue);
178
+ }
179
+ else if (!(definition = HTMLDirective.getForInstance(currentValue))) {
180
+ const staticValue = currentValue;
181
+ currentValue = new HTMLBindingDirective(oneTime(() => staticValue));
182
+ }
183
+ html += createHTML(currentValue, currentString, add, definition);
184
+ }
185
+ return new ViewTemplate(html + strings[strings.length - 1], factories, policy);
186
+ }
187
+ }
188
+ makeSerializationNoop(ViewTemplate);
189
+ /**
190
+ * Transforms a template literal string into a ViewTemplate.
191
+ * @param strings - The string fragments that are interpolated with the values.
192
+ * @param values - The values that are interpolated with the string fragments.
193
+ * @remarks
194
+ * The html helper supports interpolation of strings, numbers, binding expressions,
195
+ * other template instances, and Directive instances.
196
+ * @public
197
+ */
198
+ export const html = ((strings, ...values) => {
199
+ if (Array.isArray(strings) && Array.isArray(strings.raw)) {
200
+ return ViewTemplate.create(strings, values);
201
+ }
202
+ throw FAST.error(Message.directCallToHTMLTagNotAllowed);
203
+ });
204
+ html.partial = (html) => {
205
+ return new InlineTemplateDirective(html);
206
+ };