@microsoft/fast-element 2.10.4 → 3.0.0-rc.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 (211) hide show
  1. package/CHANGELOG.md +52 -2
  2. package/README.md +244 -1
  3. package/dist/arrays/arrays.api.json +2621 -0
  4. package/dist/context/context.api.json +13 -13
  5. package/dist/declarative/declarative.api.json +8483 -0
  6. package/dist/di/di.api.json +16 -16
  7. package/dist/dts/__test__/helpers.d.ts +6 -0
  8. package/dist/dts/array-observer.d.ts +2 -0
  9. package/dist/dts/arrays.d.ts +2 -0
  10. package/dist/dts/attr.d.ts +1 -0
  11. package/dist/dts/binding/binding.d.ts +15 -5
  12. package/dist/dts/binding/one-time.d.ts +1 -1
  13. package/dist/dts/binding/one-way.d.ts +1 -1
  14. package/dist/dts/binding/signal.d.ts +6 -6
  15. package/dist/dts/binding/two-way.d.ts +2 -1
  16. package/dist/dts/binding.d.ts +7 -0
  17. package/dist/dts/components/attributes.d.ts +1 -4
  18. package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
  19. package/dist/dts/components/element-controller.d.ts +80 -114
  20. package/dist/dts/components/element-hydration.d.ts +1 -1
  21. package/dist/dts/components/enable-hydration.d.ts +54 -0
  22. package/dist/dts/components/fast-definitions.d.ts +98 -46
  23. package/dist/dts/components/fast-element.d.ts +43 -16
  24. package/dist/dts/components/hydration-tracker.d.ts +83 -0
  25. package/dist/dts/components/hydration.d.ts +23 -53
  26. package/dist/dts/components/schema.d.ts +205 -0
  27. package/dist/dts/context.d.ts +13 -13
  28. package/dist/dts/css.d.ts +3 -0
  29. package/dist/dts/debug.d.ts +5 -1
  30. package/dist/dts/declarative/attribute-map.d.ts +58 -0
  31. package/dist/dts/declarative/debug.d.ts +4 -0
  32. package/dist/dts/declarative/index.d.ts +14 -0
  33. package/dist/dts/declarative/interfaces.d.ts +8 -0
  34. package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
  35. package/dist/dts/declarative/observer-map.d.ts +89 -0
  36. package/dist/dts/declarative/runtime.d.ts +5 -0
  37. package/dist/dts/declarative/syntax.d.ts +21 -0
  38. package/dist/dts/declarative/template-bridge.d.ts +33 -0
  39. package/dist/dts/declarative/template-parser.d.ts +98 -0
  40. package/dist/dts/declarative/template.d.ts +10 -0
  41. package/dist/dts/declarative/utilities.d.ts +358 -0
  42. package/dist/dts/di/di.d.ts +7 -7
  43. package/dist/dts/directives/children.d.ts +2 -0
  44. package/dist/dts/directives/node-observation.d.ts +2 -0
  45. package/dist/dts/directives/ref.d.ts +2 -0
  46. package/dist/dts/directives/repeat.d.ts +4 -0
  47. package/dist/dts/directives/slotted.d.ts +2 -0
  48. package/dist/dts/directives/when.d.ts +3 -0
  49. package/dist/dts/dom-policy.d.ts +23 -5
  50. package/dist/dts/dom.d.ts +4 -16
  51. package/dist/dts/html.d.ts +5 -0
  52. package/dist/dts/hydration/diagnostics.d.ts +93 -0
  53. package/dist/dts/hydration/hydration-debugger.d.ts +35 -0
  54. package/dist/dts/hydration/messages.d.ts +62 -0
  55. package/dist/dts/hydration/runtime.d.ts +7 -0
  56. package/dist/dts/hydration/target-builder.d.ts +40 -12
  57. package/dist/dts/hydration.d.ts +18 -0
  58. package/dist/dts/index.d.ts +42 -42
  59. package/dist/dts/index.debug.d.ts +0 -1
  60. package/dist/dts/index.rollup.debug.d.ts +0 -1
  61. package/dist/dts/interfaces.d.ts +2 -49
  62. package/dist/dts/observable.d.ts +3 -6
  63. package/dist/dts/observation/arrays.d.ts +1 -1
  64. package/dist/dts/observation/observable.d.ts +3 -3
  65. package/dist/dts/observation/update-queue.d.ts +1 -1
  66. package/dist/dts/platform.d.ts +45 -8
  67. package/dist/dts/registry.d.ts +1 -0
  68. package/dist/dts/render.d.ts +7 -0
  69. package/dist/dts/schema.d.ts +1 -0
  70. package/dist/dts/state/exports.d.ts +1 -1
  71. package/dist/dts/state/state.d.ts +2 -2
  72. package/dist/dts/styles/css-directive.d.ts +5 -12
  73. package/dist/dts/styles/css.d.ts +5 -7
  74. package/dist/dts/styles/element-styles.d.ts +0 -10
  75. package/dist/dts/styles.d.ts +6 -0
  76. package/dist/dts/templating/compiler.d.ts +1 -1
  77. package/dist/dts/templating/html-binding-directive.d.ts +10 -2
  78. package/dist/dts/templating/html-directive.d.ts +19 -1
  79. package/dist/dts/templating/hydration-view.d.ts +130 -0
  80. package/dist/dts/templating/render.d.ts +1 -1
  81. package/dist/dts/templating/repeat.d.ts +1 -1
  82. package/dist/dts/templating/template.d.ts +15 -7
  83. package/dist/dts/templating/view.d.ts +25 -102
  84. package/dist/dts/templating.d.ts +10 -0
  85. package/dist/dts/testing/exports.d.ts +2 -2
  86. package/dist/dts/testing/fakes.d.ts +4 -4
  87. package/dist/dts/updates.d.ts +1 -0
  88. package/dist/dts/volatile.d.ts +2 -0
  89. package/dist/esm/__test__/helpers.js +22 -0
  90. package/dist/esm/__test__/setup-node.js +18 -0
  91. package/dist/esm/array-observer.js +1 -0
  92. package/dist/esm/arrays.js +1 -0
  93. package/dist/esm/attr.js +1 -0
  94. package/dist/esm/binding/normalize.js +1 -1
  95. package/dist/esm/binding/signal.js +4 -4
  96. package/dist/esm/binding/two-way.js +3 -3
  97. package/dist/esm/binding.js +4 -0
  98. package/dist/esm/components/attributes.js +18 -11
  99. package/dist/esm/components/definition-schema-transforms.js +23 -0
  100. package/dist/esm/components/element-controller.js +206 -270
  101. package/dist/esm/components/element-hydration.js +1 -1
  102. package/dist/esm/components/enable-hydration.js +124 -0
  103. package/dist/esm/components/fast-definitions.js +219 -56
  104. package/dist/esm/components/fast-element.js +18 -27
  105. package/dist/esm/components/hydration-tracker.js +122 -0
  106. package/dist/esm/components/hydration.js +137 -140
  107. package/dist/esm/components/schema.js +253 -0
  108. package/dist/esm/context.js +6 -6
  109. package/dist/esm/css.js +3 -0
  110. package/dist/esm/debug.js +27 -26
  111. package/dist/esm/declarative/attribute-map.js +122 -0
  112. package/dist/esm/declarative/debug.js +4 -0
  113. package/dist/esm/declarative/index.js +4 -0
  114. package/dist/esm/declarative/interfaces.js +9 -0
  115. package/dist/esm/declarative/observer-map-utilities.js +565 -0
  116. package/dist/esm/declarative/observer-map.js +216 -0
  117. package/dist/esm/declarative/runtime.js +14 -0
  118. package/dist/esm/declarative/syntax.js +36 -0
  119. package/dist/esm/declarative/template-bridge.js +160 -0
  120. package/dist/esm/declarative/template-parser.js +306 -0
  121. package/dist/esm/declarative/template.js +143 -0
  122. package/dist/esm/declarative/utilities.js +1069 -0
  123. package/dist/esm/di/di.js +8 -9
  124. package/dist/esm/directives/children.js +1 -0
  125. package/dist/esm/directives/node-observation.js +1 -0
  126. package/dist/esm/directives/ref.js +1 -0
  127. package/dist/esm/directives/repeat.js +1 -0
  128. package/dist/esm/directives/slotted.js +1 -0
  129. package/dist/esm/directives/when.js +1 -0
  130. package/dist/esm/dom-policy.js +35 -6
  131. package/dist/esm/dom.js +1 -1
  132. package/dist/esm/html.js +2 -0
  133. package/dist/esm/hydration/diagnostics.js +50 -0
  134. package/dist/esm/hydration/hydration-debugger.js +112 -0
  135. package/dist/esm/hydration/messages.js +84 -0
  136. package/dist/esm/hydration/runtime.js +33 -0
  137. package/dist/esm/hydration/target-builder.js +144 -91
  138. package/dist/esm/hydration.js +6 -0
  139. package/dist/esm/index.debug.js +2 -1
  140. package/dist/esm/index.js +38 -29
  141. package/dist/esm/index.rollup.debug.js +3 -2
  142. package/dist/esm/index.rollup.js +1 -1
  143. package/dist/esm/interfaces.js +2 -45
  144. package/dist/esm/metadata.js +2 -8
  145. package/dist/esm/observable.js +1 -4
  146. package/dist/esm/observation/arrays.js +1 -1
  147. package/dist/esm/observation/notifier.js +2 -4
  148. package/dist/esm/observation/observable.js +5 -5
  149. package/dist/esm/observation/update-queue.js +47 -58
  150. package/dist/esm/platform.js +31 -30
  151. package/dist/esm/registry.js +1 -0
  152. package/dist/esm/render.js +1 -0
  153. package/dist/esm/schema.js +1 -0
  154. package/dist/esm/state/exports.js +1 -1
  155. package/dist/esm/styles/css-directive.js +1 -2
  156. package/dist/esm/styles/css.js +15 -56
  157. package/dist/esm/styles/element-styles.js +69 -15
  158. package/dist/esm/styles.js +2 -0
  159. package/dist/esm/templating/html-binding-directive.js +11 -9
  160. package/dist/esm/templating/hydration-view.js +228 -0
  161. package/dist/esm/templating/render.js +39 -18
  162. package/dist/esm/templating/repeat.js +69 -33
  163. package/dist/esm/templating/template.js +7 -7
  164. package/dist/esm/templating/view.js +25 -234
  165. package/dist/esm/templating.js +7 -0
  166. package/dist/esm/testing/exports.js +2 -2
  167. package/dist/esm/testing/fixture.js +2 -2
  168. package/dist/esm/testing/timeout.js +2 -2
  169. package/dist/esm/updates.js +1 -0
  170. package/dist/esm/volatile.js +1 -0
  171. package/dist/fast-element.api.json +14389 -11138
  172. package/dist/fast-element.d.ts +3651 -809
  173. package/dist/fast-element.debug.js +5666 -4722
  174. package/dist/fast-element.debug.min.js +2 -2
  175. package/dist/fast-element.js +5394 -4381
  176. package/dist/fast-element.min.js +2 -2
  177. package/dist/fast-element.untrimmed.d.ts +923 -472
  178. package/dist/hydration/hydration.api.json +6460 -0
  179. package/dist/styles/styles.api.json +2672 -0
  180. package/package.json +165 -45
  181. package/ARCHITECTURE_FASTELEMENT.md +0 -63
  182. package/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md +0 -36
  183. package/ARCHITECTURE_INTRO.md +0 -10
  184. package/ARCHITECTURE_OVERVIEW.md +0 -52
  185. package/ARCHITECTURE_UPDATES.md +0 -11
  186. package/CHANGELOG.json +0 -2275
  187. package/DESIGN.md +0 -510
  188. package/api-extractor.context.json +0 -14
  189. package/api-extractor.di.json +0 -14
  190. package/biome.json +0 -4
  191. package/dist/dts/components/install-hydration.d.ts +0 -1
  192. package/dist/dts/pending-task.d.ts +0 -32
  193. package/dist/dts/styles/css-binding-directive.d.ts +0 -60
  194. package/dist/dts/templating/install-hydratable-view-templates.d.ts +0 -1
  195. package/dist/esm/components/install-hydration.js +0 -3
  196. package/dist/esm/pending-task.js +0 -28
  197. package/dist/esm/polyfills.js +0 -60
  198. package/dist/esm/styles/css-binding-directive.js +0 -76
  199. package/dist/esm/templating/install-hydratable-view-templates.js +0 -23
  200. package/docs/ACKNOWLEDGEMENTS.md +0 -12
  201. package/docs/api-report.api.md +0 -1122
  202. package/docs/context/api-report.api.md +0 -69
  203. package/docs/di/api-report.api.md +0 -315
  204. package/docs/fast-element-2-changes.md +0 -15
  205. package/playwright.config.ts +0 -26
  206. package/scripts/run-api-extractor.js +0 -51
  207. package/test/index.html +0 -11
  208. package/test/main.ts +0 -104
  209. package/test/vite.config.ts +0 -19
  210. package/tsconfig.api-extractor.json +0 -6
  211. /package/dist/dts/{polyfills.d.ts → __test__/setup-node.d.ts} +0 -0
@@ -0,0 +1,306 @@
1
+ import { children } from "../templating/children.js";
2
+ import { elements } from "../templating/node-observation.js";
3
+ import { ref } from "../templating/ref.js";
4
+ import { repeat } from "../templating/repeat.js";
5
+ import { slotted } from "../templating/slotted.js";
6
+ import { ViewTemplate } from "../templating/template.js";
7
+ import { when } from "../templating/when.js";
8
+ import { ensureDeclarativeRuntime } from "./runtime.js";
9
+ import { bindingResolver, contextPrefixDot, getBooleanBinding, getExpressionChain, getNextBehavior, getRootPropertyName, parseEventArgs, } from "./utilities.js";
10
+ /**
11
+ * Tracks string segments accumulated during template parsing and maintains
12
+ * a running concatenation so that `bindingResolver` can receive the full
13
+ * preceding HTML without an O(N) `join("")` at every binding site.
14
+ */
15
+ class StringsAccumulator {
16
+ constructor() {
17
+ this.segments = [];
18
+ this._previousString = "";
19
+ }
20
+ push(segment) {
21
+ this.segments.push(segment);
22
+ this._previousString += segment;
23
+ }
24
+ /**
25
+ * The full concatenation of all segments pushed so far.
26
+ * Used by `bindingResolver` to detect child-element attribute bindings.
27
+ */
28
+ get previousString() {
29
+ return this._previousString;
30
+ }
31
+ }
32
+ /**
33
+ * Converts declarative HTML template markup into the `strings` and `values`
34
+ * arrays that `ViewTemplate.create()` consumes.
35
+ *
36
+ * This class is intentionally stateless across invocations — all mutable
37
+ * parsing state lives on the call stack or in the `TemplateResolutionContext`.
38
+ *
39
+ * The parsing pipeline is fully synchronous — no promises are allocated
40
+ * during template resolution.
41
+ * @public
42
+ */
43
+ export class TemplateParser {
44
+ /**
45
+ * Parse declarative HTML into strings and values for ViewTemplate creation.
46
+ * @param innerHTML - The transformed innerHTML to parse.
47
+ * @param schema - The Schema instance for property tracking.
48
+ * @returns The resolved strings and values.
49
+ */
50
+ parse(innerHTML, schema) {
51
+ return this.resolveStringsAndValues(null, innerHTML, {
52
+ parentContext: null,
53
+ level: 0,
54
+ schema,
55
+ });
56
+ }
57
+ /**
58
+ * Create a ViewTemplate from resolved strings and values.
59
+ * @param strings - The strings array.
60
+ * @param values - The interpreted values.
61
+ */
62
+ createTemplate(strings, values) {
63
+ ensureDeclarativeRuntime();
64
+ return ViewTemplate.create(strings, values);
65
+ }
66
+ /**
67
+ * Resolve strings and values from an innerHTML string.
68
+ * @param rootPropertyName - The root property name for schema registration.
69
+ * @param innerHTML - The innerHTML.
70
+ * @param context - The template resolution context.
71
+ */
72
+ resolveStringsAndValues(rootPropertyName, innerHTML, context) {
73
+ const strings = new StringsAccumulator();
74
+ const values = [];
75
+ this.resolveInnerHTML(rootPropertyName, innerHTML, strings, values, context);
76
+ strings.segments.raw = strings.segments.map(value => String.raw({ raw: value }));
77
+ return {
78
+ strings: strings.segments,
79
+ values,
80
+ };
81
+ }
82
+ /**
83
+ * Resolve a template directive (when/repeat).
84
+ * @param rootPropertyName - The root property name for schema registration.
85
+ * @param behaviorConfig - The directive behavior configuration object.
86
+ * @param externalValues - The interpreted values from the parent.
87
+ * @param innerHTML - The innerHTML.
88
+ * @param context - The template resolution context.
89
+ */
90
+ resolveTemplateDirective(rootPropertyName, behaviorConfig, externalValues, innerHTML, context) {
91
+ switch (behaviorConfig.name) {
92
+ case "when": {
93
+ const expressionChain = getExpressionChain(behaviorConfig.value);
94
+ const whenLogic = getBooleanBinding(rootPropertyName, expressionChain, context.parentContext, context.level, context.schema);
95
+ const { strings, values } = this.resolveStringsAndValues(rootPropertyName, innerHTML.slice(behaviorConfig.openingTagEndIndex, behaviorConfig.closingTagStartIndex), context);
96
+ externalValues.push(when(whenLogic, this.createTemplate(strings, values)));
97
+ break;
98
+ }
99
+ case "repeat": {
100
+ const valueAttr = behaviorConfig.value.split(" "); // syntax {{x in y}}
101
+ const updatedLevel = context.level + 1;
102
+ rootPropertyName = getRootPropertyName(rootPropertyName, valueAttr[2], context.parentContext, behaviorConfig.name);
103
+ const binding = bindingResolver(null, rootPropertyName, valueAttr[2], context.parentContext, behaviorConfig.name, context.schema, valueAttr[0], context.level);
104
+ const repeatContext = {
105
+ parentContext: valueAttr[0],
106
+ level: updatedLevel,
107
+ schema: context.schema,
108
+ };
109
+ const { strings, values } = this.resolveStringsAndValues(rootPropertyName, innerHTML.slice(behaviorConfig.openingTagEndIndex, behaviorConfig.closingTagStartIndex), repeatContext);
110
+ externalValues.push(repeat((x, c) => binding(x, c), this.createTemplate(strings, values)));
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ /**
116
+ * Resolve an attribute directive (children/slotted/ref).
117
+ * @param name - The name of the directive.
118
+ * @param propName - The property name to pass to the directive.
119
+ * @param externalValues - The interpreted values from the parent.
120
+ */
121
+ resolveAttributeDirective(name, propName, externalValues) {
122
+ switch (name) {
123
+ case "children": {
124
+ externalValues.push(children(propName));
125
+ break;
126
+ }
127
+ case "slotted": {
128
+ const parts = propName.trim().split(" filter ");
129
+ const slottedOption = {
130
+ property: parts[0],
131
+ };
132
+ if (parts[1]) {
133
+ if (parts[1].startsWith("elements(")) {
134
+ let params = parts[1].replace("elements(", "");
135
+ params = params.substring(0, params.lastIndexOf(")"));
136
+ Object.assign(slottedOption, {
137
+ filter: elements(params || undefined),
138
+ });
139
+ }
140
+ }
141
+ externalValues.push(slotted(slottedOption));
142
+ break;
143
+ }
144
+ case "ref": {
145
+ externalValues.push(ref(propName));
146
+ break;
147
+ }
148
+ }
149
+ }
150
+ /**
151
+ * Resolve an access binding — shared by content bindings, boolean-attribute
152
+ * fallback, and default attribute bindings.
153
+ * @returns An object with the resolved binding function and the updated rootPropertyName.
154
+ */
155
+ resolveAccessBinding(rootPropertyName, propName, previousStrings, context) {
156
+ rootPropertyName = getRootPropertyName(rootPropertyName, propName, context.parentContext, "access");
157
+ const resolved = bindingResolver(previousStrings, rootPropertyName, propName, context.parentContext, "access", context.schema, context.parentContext, context.level);
158
+ return {
159
+ binding: (x, c) => resolved(x, c),
160
+ rootPropertyName,
161
+ };
162
+ }
163
+ /**
164
+ * Resolve an event binding (the "\@" aspect).
165
+ * @returns An object with the event binding function and the updated rootPropertyName.
166
+ */
167
+ resolveEventBinding(rootPropertyName, innerHTML, behaviorConfig, strings, context) {
168
+ const bindingHTML = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
169
+ const openingParenthesis = bindingHTML.indexOf("(");
170
+ const closingParenthesis = bindingHTML.indexOf(")");
171
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex -
172
+ (closingParenthesis - openingParenthesis) -
173
+ 1);
174
+ const type = "event";
175
+ rootPropertyName = getRootPropertyName(rootPropertyName, propName, context.parentContext, type);
176
+ const argsString = bindingHTML.slice(openingParenthesis + 1, closingParenthesis);
177
+ const previousString = strings.previousString;
178
+ const resolved = bindingResolver(previousString, rootPropertyName, propName, context.parentContext, type, context.schema, context.parentContext, context.level);
179
+ const isContextPath = propName.startsWith(contextPrefixDot);
180
+ const getOwner = isContextPath
181
+ ? (_x, c) => {
182
+ const ownerPath = propName.split(".").slice(1, -1);
183
+ return ownerPath.reduce((prev, item) => prev === null || prev === void 0 ? void 0 : prev[item], c);
184
+ }
185
+ : (x, _c) => x;
186
+ const parsedArgs = parseEventArgs(argsString);
187
+ const argResolvers = parsedArgs.map((parsedArg) => {
188
+ switch (parsedArg.type) {
189
+ case "event":
190
+ return (_x, c) => c.event;
191
+ case "context":
192
+ return (_x, c) => c;
193
+ case "binding":
194
+ return bindingResolver(previousString, rootPropertyName, parsedArg.rawArg, context.parentContext, type, context.schema, context.parentContext, context.level);
195
+ }
196
+ });
197
+ return {
198
+ binding: (x, c) => resolved(x, c).bind(getOwner(x, c))(...argResolvers.map(resolve => resolve(x, c))),
199
+ rootPropertyName,
200
+ };
201
+ }
202
+ /**
203
+ * Resolve a content data binding (`{{expression}}` in text content).
204
+ */
205
+ resolveContentBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context) {
206
+ strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex));
207
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
208
+ const result = this.resolveAccessBinding(rootPropertyName, propName, strings.previousString, context);
209
+ rootPropertyName = result.rootPropertyName;
210
+ values.push(result.binding);
211
+ this.resolveInnerHTML(rootPropertyName, innerHTML.slice(behaviorConfig.closingEndIndex, innerHTML.length), strings, values, context);
212
+ }
213
+ /**
214
+ * Resolve an attribute data binding (`{{expression}}` in an HTML attribute).
215
+ * Dispatches to event, expression, or access binding handlers based on aspect.
216
+ */
217
+ resolveAttributeBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context) {
218
+ strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex));
219
+ let attributeBinding;
220
+ const aspect = behaviorConfig.subtype === "attribute" ? behaviorConfig.aspect : null;
221
+ switch (aspect) {
222
+ case "@": {
223
+ const result = this.resolveEventBinding(rootPropertyName, innerHTML, behaviorConfig, strings, context);
224
+ attributeBinding = result.binding;
225
+ rootPropertyName = result.rootPropertyName;
226
+ break;
227
+ }
228
+ case "?": {
229
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
230
+ const expressionChain = getExpressionChain(propName);
231
+ if (expressionChain === null || expressionChain === void 0 ? void 0 : expressionChain.expression.operator) {
232
+ attributeBinding = getBooleanBinding(rootPropertyName, expressionChain, context.parentContext, context.level, context.schema);
233
+ }
234
+ else {
235
+ const result = this.resolveAccessBinding(rootPropertyName, propName, strings.previousString, context);
236
+ attributeBinding = result.binding;
237
+ rootPropertyName = result.rootPropertyName;
238
+ }
239
+ break;
240
+ }
241
+ default: {
242
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
243
+ const result = this.resolveAccessBinding(rootPropertyName, propName, strings.previousString, context);
244
+ attributeBinding = result.binding;
245
+ rootPropertyName = result.rootPropertyName;
246
+ }
247
+ }
248
+ values.push(attributeBinding);
249
+ this.resolveInnerHTML(rootPropertyName, innerHTML.slice(behaviorConfig.closingEndIndex, innerHTML.length), strings, values, context);
250
+ }
251
+ /**
252
+ * Resolve an attribute directive binding (`f-children`, `f-slotted`, `f-ref`).
253
+ */
254
+ resolveAttributeDirectiveBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context) {
255
+ strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex - behaviorConfig.name.length - 4));
256
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
257
+ this.resolveAttributeDirective(behaviorConfig.name, propName, values);
258
+ this.resolveInnerHTML(rootPropertyName, innerHTML.slice(behaviorConfig.closingEndIndex + 1, innerHTML.length), strings, values, context);
259
+ }
260
+ /**
261
+ * Dispatcher for data binding resolution. Routes to the appropriate handler
262
+ * based on the binding subtype.
263
+ */
264
+ resolveDataBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context) {
265
+ switch (behaviorConfig.subtype) {
266
+ case "content":
267
+ this.resolveContentBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context);
268
+ break;
269
+ case "attribute":
270
+ this.resolveAttributeBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context);
271
+ break;
272
+ case "attributeDirective":
273
+ this.resolveAttributeDirectiveBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context);
274
+ break;
275
+ }
276
+ }
277
+ /**
278
+ * Resolver of the innerHTML string. Finds the next binding or directive
279
+ * in the HTML and dispatches to the appropriate handler.
280
+ * @param rootPropertyName - The root property name for schema registration.
281
+ * @param innerHTML - The innerHTML to parse.
282
+ * @param strings - Accumulator for literal HTML segments and running previous-string.
283
+ * @param values - The values array (accumulates binding functions and directives).
284
+ * @param context - The template resolution context.
285
+ */
286
+ resolveInnerHTML(rootPropertyName, innerHTML, strings, values, context) {
287
+ const behaviorConfig = getNextBehavior(innerHTML);
288
+ if (behaviorConfig === null) {
289
+ strings.push(innerHTML);
290
+ }
291
+ else {
292
+ switch (behaviorConfig.type) {
293
+ case "dataBinding": {
294
+ this.resolveDataBinding(rootPropertyName, innerHTML, strings, values, behaviorConfig, context);
295
+ break;
296
+ }
297
+ case "templateDirective": {
298
+ strings.push(innerHTML.slice(0, behaviorConfig.openingTagStartIndex));
299
+ this.resolveTemplateDirective(rootPropertyName, behaviorConfig, values, innerHTML, context);
300
+ this.resolveInnerHTML(rootPropertyName, innerHTML.slice(behaviorConfig.closingTagEndIndex, innerHTML.length), strings, values, context);
301
+ break;
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
@@ -0,0 +1,143 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { getDefinitionSchemaTransforms } from "../components/definition-schema-transforms.js";
11
+ import { Schema } from "../components/schema.js";
12
+ import { FAST } from "../platform.js";
13
+ import { Message } from "./interfaces.js";
14
+ import { ensureDeclarativeRuntime } from "./runtime.js";
15
+ import { declarativeTemplateBridge } from "./template-bridge.js";
16
+ import { TemplateParser } from "./template-parser.js";
17
+ import { escapeBracesInCodeElements, transformInnerHTML } from "./utilities.js";
18
+ const templateElementName = "f-template";
19
+ const ensuredTemplateElements = new WeakMap();
20
+ function isTemplateElementConstructor(value) {
21
+ return value === FTemplateElement || (value === null || value === void 0 ? void 0 : value.prototype) instanceof FTemplateElement;
22
+ }
23
+ function ensureTemplateElementDefined(registry) {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const ensured = ensuredTemplateElements.get(registry);
26
+ if (ensured) {
27
+ return ensured;
28
+ }
29
+ const definitionPromise = Promise.resolve().then(() => {
30
+ const existing = registry.get(templateElementName);
31
+ if (existing !== void 0) {
32
+ if (isTemplateElementConstructor(existing)) {
33
+ return;
34
+ }
35
+ throw new Error("The <f-template> element is already defined in this registry by a different implementation.");
36
+ }
37
+ const RegisteredTemplateElement = class extends FTemplateElement {
38
+ get registry() {
39
+ return registry;
40
+ }
41
+ };
42
+ registry.define(templateElementName, RegisteredTemplateElement);
43
+ });
44
+ const pending = definitionPromise.catch(error => {
45
+ ensuredTemplateElements.delete(registry);
46
+ throw error;
47
+ });
48
+ ensuredTemplateElements.set(registry, pending);
49
+ return pending;
50
+ });
51
+ }
52
+ function chainLifecycleCallback(first, second) {
53
+ if (!first) {
54
+ return second;
55
+ }
56
+ if (!second) {
57
+ return first;
58
+ }
59
+ return (...args) => {
60
+ first(...args);
61
+ second(...args);
62
+ };
63
+ }
64
+ /**
65
+ * Returns a declarative template resolver that waits for the matching
66
+ * `<f-template>` element and resolves it into a concrete `ViewTemplate`.
67
+ *
68
+ * @param callbacks - Optional per-element lifecycle callbacks.
69
+ * @public
70
+ */
71
+ export function declarativeTemplate(callbacks) {
72
+ ensureDeclarativeRuntime();
73
+ return (definition) => __awaiter(this, void 0, void 0, function* () {
74
+ if (callbacks) {
75
+ const existing = definition.lifecycleCallbacks;
76
+ definition.lifecycleCallbacks = {
77
+ elementDidRegister: chainLifecycleCallback(existing === null || existing === void 0 ? void 0 : existing.elementDidRegister, callbacks.elementDidRegister),
78
+ templateWillUpdate: chainLifecycleCallback(existing === null || existing === void 0 ? void 0 : existing.templateWillUpdate, callbacks.templateWillUpdate),
79
+ templateDidUpdate: chainLifecycleCallback(existing === null || existing === void 0 ? void 0 : existing.templateDidUpdate, callbacks.templateDidUpdate),
80
+ elementDidDefine: chainLifecycleCallback(existing === null || existing === void 0 ? void 0 : existing.elementDidDefine, callbacks.elementDidDefine),
81
+ elementWillHydrate: chainLifecycleCallback(existing === null || existing === void 0 ? void 0 : existing.elementWillHydrate, callbacks.elementWillHydrate),
82
+ elementDidHydrate: chainLifecycleCallback(existing === null || existing === void 0 ? void 0 : existing.elementDidHydrate, callbacks.elementDidHydrate),
83
+ };
84
+ }
85
+ yield ensureTemplateElementDefined(definition.registry);
86
+ return declarativeTemplateBridge.requestTemplate(definition);
87
+ });
88
+ }
89
+ class FTemplateElement extends HTMLElement {
90
+ get registry() {
91
+ return customElements;
92
+ }
93
+ get name() {
94
+ var _a;
95
+ return (_a = this.getAttribute("name")) !== null && _a !== void 0 ? _a : undefined;
96
+ }
97
+ set name(value) {
98
+ if (value == null) {
99
+ this.removeAttribute("name");
100
+ return;
101
+ }
102
+ this.setAttribute("name", value);
103
+ }
104
+ connectedCallback() {
105
+ declarativeTemplateBridge.registerPublisher(this.registry, this.name, this);
106
+ }
107
+ disconnectedCallback() {
108
+ declarativeTemplateBridge.unregisterPublisher(this.registry, this.name, this);
109
+ }
110
+ attributeChangedCallback(attributeName, previousName, nextName) {
111
+ if (attributeName !== "name" || !this.isConnected || previousName === nextName) {
112
+ return;
113
+ }
114
+ declarativeTemplateBridge.movePublisher(this.registry, previousName !== null && previousName !== void 0 ? previousName : undefined, nextName !== null && nextName !== void 0 ? nextName : undefined, this);
115
+ }
116
+ publishTemplate(definition) {
117
+ var _a, _b, _c, _d;
118
+ var _e;
119
+ ensureDeclarativeRuntime();
120
+ const name = definition.name;
121
+ const templates = Array.from(this.children).filter((child) => child.tagName === "TEMPLATE");
122
+ if (templates.length > 1) {
123
+ throw FAST.error(Message.moreThanOneTemplateProvided, {
124
+ name,
125
+ });
126
+ }
127
+ if (templates.length === 0) {
128
+ throw FAST.error(Message.noTemplateProvided, { name });
129
+ }
130
+ (_b = (_a = definition.lifecycleCallbacks) === null || _a === void 0 ? void 0 : _a.elementDidRegister) === null || _b === void 0 ? void 0 : _b.call(_a, name);
131
+ (_d = (_c = definition.lifecycleCallbacks) === null || _c === void 0 ? void 0 : _c.templateWillUpdate) === null || _d === void 0 ? void 0 : _d.call(_c, name);
132
+ const schema = (_e = definition.schema) !== null && _e !== void 0 ? _e : new Schema(name);
133
+ definition.schema = schema;
134
+ const innerHTML = transformInnerHTML(escapeBracesInCodeElements(this.innerHTML));
135
+ const parser = new TemplateParser();
136
+ const { strings, values } = parser.parse(innerHTML, schema);
137
+ for (const transform of getDefinitionSchemaTransforms(definition)) {
138
+ transform({ definition, schema });
139
+ }
140
+ return parser.createTemplate(strings, values);
141
+ }
142
+ }
143
+ FTemplateElement.observedAttributes = ["name"];