@microsoft/fast-html 1.0.0-alpha.17 → 1.0.0-alpha.19

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.
@@ -1,7 +1,8 @@
1
1
  import { __awaiter, __decorate, __metadata } from "tslib";
2
2
  import { attr, elements, FAST, FASTElement, FASTElementDefinition, fastElementRegistry, HydratableElementController, ViewTemplate, } from "@microsoft/fast-element";
3
3
  import "@microsoft/fast-element/install-hydratable-view-templates.js";
4
- import { getAllPartials, getExpressionChain, getNextBehavior, pathResolver, resolveWhen, transformInnerHTML, } from "./utilities.js";
4
+ import { bindingResolver, getAllPartials, getExpressionChain, getNextBehavior, resolveWhen, transformInnerHTML, } from "./utilities.js";
5
+ import { ObserverMap } from "./observer-map.js";
5
6
  /**
6
7
  * The <f-template> custom element that will provide view logic to the element
7
8
  */
@@ -13,16 +14,19 @@ class TemplateElement extends FASTElement {
13
14
  const value = elementOptions[key];
14
15
  result[key] = {
15
16
  shadowOptions: (_a = value.shadowOptions) !== null && _a !== void 0 ? _a : TemplateElement.defaultElementOptions.shadowOptions,
17
+ observerMap: value.observerMap,
16
18
  };
17
19
  }
18
- this.elementOptions = result;
20
+ TemplateElement.elementOptions = result;
19
21
  HydratableElementController.install();
20
22
  return this;
21
23
  }
22
24
  constructor() {
23
25
  super();
24
26
  this.partials = {};
25
- if (!!TemplateElement.elementOptions) {
27
+ // Ensure elementOptions is initialized if it's empty
28
+ if (!TemplateElement.elementOptions ||
29
+ Object.keys(TemplateElement.elementOptions).length === 0) {
26
30
  TemplateElement.options();
27
31
  }
28
32
  }
@@ -31,30 +35,37 @@ class TemplateElement extends FASTElement {
31
35
  * @param name - The name of the custom element to set options for.
32
36
  */
33
37
  static setOptions(name) {
34
- if (!!!TemplateElement.elementOptions[name]) {
38
+ if (!TemplateElement.elementOptions[name]) {
35
39
  TemplateElement.elementOptions[name] = TemplateElement.defaultElementOptions;
36
40
  }
37
41
  }
38
42
  connectedCallback() {
39
43
  super.connectedCallback();
40
- if (this.name) {
44
+ if (typeof this.name === "string") {
41
45
  FASTElementDefinition.registerAsync(this.name).then((value) => __awaiter(this, void 0, void 0, function* () {
42
- var _a, _b;
43
- if (this.name && !!!((_a = TemplateElement.elementOptions) === null || _a === void 0 ? void 0 : _a[this.name])) {
46
+ var _a, _b, _c, _d;
47
+ if (!((_a = TemplateElement.elementOptions) === null || _a === void 0 ? void 0 : _a[this.name])) {
44
48
  TemplateElement.setOptions(this.name);
45
49
  }
50
+ if (((_b = TemplateElement.elementOptions[this.name]) === null || _b === void 0 ? void 0 : _b.observerMap) ===
51
+ "all") {
52
+ this.observerMap = new ObserverMap(value.prototype);
53
+ }
46
54
  const registeredFastElement = fastElementRegistry.getByType(value);
47
55
  const template = this.getElementsByTagName("template").item(0);
48
56
  if (template) {
49
57
  const innerHTML = yield transformInnerHTML(this.innerHTML);
50
58
  yield this.resolveAllPartials(innerHTML);
51
- const { strings, values } = yield this.resolveStringsAndValues(innerHTML);
59
+ // Cache paths during template processing (pass undefined if observerMap is not available)
60
+ const { strings, values } = yield this.resolveStringsAndValues(innerHTML, false, null, 0, this.observerMap);
61
+ // Define the root properties cached in the observer map as observable (only if observerMap exists)
62
+ (_c = this.observerMap) === null || _c === void 0 ? void 0 : _c.defineProperties();
52
63
  if (registeredFastElement) {
53
64
  // all new elements will get the updated template
54
65
  registeredFastElement.template = this.resolveTemplateOrBehavior(strings, values);
55
66
  // set shadow options as defined by the f-template
56
67
  registeredFastElement.shadowOptions =
57
- (_b = TemplateElement.elementOptions[this.name]) === null || _b === void 0 ? void 0 : _b.shadowOptions;
68
+ (_d = TemplateElement.elementOptions[this.name]) === null || _d === void 0 ? void 0 : _d.shadowOptions;
58
69
  }
59
70
  }
60
71
  else {
@@ -67,12 +78,13 @@ class TemplateElement extends FASTElement {
67
78
  * Resolve strings and values from an innerHTML string
68
79
  * @param innerHTML - The innerHTML.
69
80
  * @param self - Indicates that this should refer to itself instead of a property when creating bindings.
81
+ * @param observerMap - ObserverMap instance for caching binding paths (optional).
70
82
  */
71
- resolveStringsAndValues(innerHTML, self = false) {
83
+ resolveStringsAndValues(innerHTML, self = false, parentContext, level, observerMap) {
72
84
  return __awaiter(this, void 0, void 0, function* () {
73
85
  const strings = [];
74
86
  const values = []; // these can be bindings, directives, etc.
75
- yield this.resolveInnerHTML(innerHTML, strings, values, self);
87
+ yield this.resolveInnerHTML(innerHTML, strings, values, self, parentContext, level, observerMap);
76
88
  strings.raw = strings.map(value => String.raw({ raw: value }));
77
89
  return {
78
90
  strings,
@@ -93,28 +105,30 @@ class TemplateElement extends FASTElement {
93
105
  * @param behaviorConfig - The directive behavior configuration object.
94
106
  * @param externalValues - The interpreted values from the parent.
95
107
  * @param innerHTML - The innerHTML.
108
+ * @param self - Indicates that this should refer to itself instead of a property when creating bindings.
109
+ * @param observerMap - ObserverMap instance for caching binding paths (optional).
96
110
  */
97
- resolveTemplateDirective(behaviorConfig, externalValues, innerHTML, self = false) {
111
+ resolveTemplateDirective(behaviorConfig, externalValues, innerHTML, self = false, parentContext, level, observerMap) {
98
112
  var _a;
99
113
  return __awaiter(this, void 0, void 0, function* () {
100
114
  switch (behaviorConfig.name) {
101
- case "when":
102
- {
103
- const { strings, values } = yield this.resolveStringsAndValues(innerHTML.slice(behaviorConfig.openingTagEndIndex, behaviorConfig.closingTagStartIndex), self);
104
- const { when } = yield import("@microsoft/fast-element");
105
- const expressionChain = getExpressionChain(behaviorConfig.value);
106
- const whenLogic = resolveWhen(self, expressionChain);
107
- externalValues.push(when(whenLogic, this.resolveTemplateOrBehavior(strings, values)));
108
- }
115
+ case "when": {
116
+ const { when } = yield import("@microsoft/fast-element");
117
+ const expressionChain = getExpressionChain(behaviorConfig.value);
118
+ const whenLogic = resolveWhen(self, expressionChain, parentContext, level, observerMap);
119
+ const { strings, values } = yield this.resolveStringsAndValues(innerHTML.slice(behaviorConfig.openingTagEndIndex, behaviorConfig.closingTagStartIndex), self, parentContext, level, observerMap);
120
+ externalValues.push(when(whenLogic, this.resolveTemplateOrBehavior(strings, values)));
109
121
  break;
110
- case "repeat":
111
- {
112
- const valueAttr = behaviorConfig.value.split(" "); // syntax {{x in y}}
113
- const { strings, values } = yield this.resolveStringsAndValues(innerHTML.slice(behaviorConfig.openingTagEndIndex, behaviorConfig.closingTagStartIndex), true);
114
- const { repeat } = yield import("@microsoft/fast-element");
115
- externalValues.push(repeat((x, c) => pathResolver(valueAttr[2], self)(x, c), this.resolveTemplateOrBehavior(strings, values)));
116
- }
122
+ }
123
+ case "repeat": {
124
+ const valueAttr = behaviorConfig.value.split(" "); // syntax {{x in y}}
125
+ const updatedLevel = level + 1;
126
+ const { repeat } = yield import("@microsoft/fast-element");
127
+ const binding = bindingResolver(valueAttr[2], self, parentContext, "repeat", observerMap !== null && observerMap !== void 0 ? observerMap : null, valueAttr[0], level);
128
+ const { strings, values } = yield this.resolveStringsAndValues(innerHTML.slice(behaviorConfig.openingTagEndIndex, behaviorConfig.closingTagStartIndex), true, valueAttr[0], updatedLevel, observerMap);
129
+ externalValues.push(repeat((x, c) => binding(x, c), this.resolveTemplateOrBehavior(strings, values)));
117
130
  break;
131
+ }
118
132
  case "apply": {
119
133
  const openingTag = innerHTML.slice(behaviorConfig.openingTagStartIndex, behaviorConfig.openingTagEndIndex);
120
134
  const partial = (_a = openingTag
@@ -124,7 +138,8 @@ class TemplateElement extends FASTElement {
124
138
  })) === null || _a === void 0 ? void 0 : _a.split('"')[1];
125
139
  if (partial) {
126
140
  const { when } = yield import("@microsoft/fast-element");
127
- externalValues.push(when((x, c) => pathResolver(behaviorConfig.value, self)(x, c), () => this.partials[partial]));
141
+ const binding = bindingResolver(behaviorConfig.value, self, parentContext, "access", observerMap !== null && observerMap !== void 0 ? observerMap : null, null, level);
142
+ externalValues.push(when((x, c) => binding(x, c), () => this.partials[partial]));
128
143
  }
129
144
  }
130
145
  }
@@ -139,37 +154,34 @@ class TemplateElement extends FASTElement {
139
154
  resolveAttributeDirective(name, propName, externalValues) {
140
155
  return __awaiter(this, void 0, void 0, function* () {
141
156
  switch (name) {
142
- case "children":
143
- {
144
- const { children } = yield import("@microsoft/fast-element");
145
- externalValues.push(children(propName));
146
- }
157
+ case "children": {
158
+ const { children } = yield import("@microsoft/fast-element");
159
+ externalValues.push(children(propName));
147
160
  break;
148
- case "slotted":
149
- {
150
- const { slotted } = yield import("@microsoft/fast-element");
151
- const parts = propName.trim().split(" filter ");
152
- const slottedOption = {
153
- property: parts[0],
154
- };
155
- if (parts[1]) {
156
- if (parts[1].startsWith("elements(")) {
157
- let params = parts[1].replace("elements(", "");
158
- params = params.substring(0, params.lastIndexOf(")"));
159
- Object.assign(slottedOption, {
160
- filter: elements(params || undefined),
161
- });
162
- }
161
+ }
162
+ case "slotted": {
163
+ const { slotted } = yield import("@microsoft/fast-element");
164
+ const parts = propName.trim().split(" filter ");
165
+ const slottedOption = {
166
+ property: parts[0],
167
+ };
168
+ if (parts[1]) {
169
+ if (parts[1].startsWith("elements(")) {
170
+ let params = parts[1].replace("elements(", "");
171
+ params = params.substring(0, params.lastIndexOf(")"));
172
+ Object.assign(slottedOption, {
173
+ filter: elements(params || undefined),
174
+ });
163
175
  }
164
- externalValues.push(slotted(slottedOption));
165
176
  }
177
+ externalValues.push(slotted(slottedOption));
166
178
  break;
167
- case "ref":
168
- {
169
- const { ref } = yield import("@microsoft/fast-element");
170
- externalValues.push(ref(propName));
171
- }
179
+ }
180
+ case "ref": {
181
+ const { ref } = yield import("@microsoft/fast-element");
182
+ externalValues.push(ref(propName));
172
183
  break;
184
+ }
173
185
  }
174
186
  });
175
187
  }
@@ -180,20 +192,21 @@ class TemplateElement extends FASTElement {
180
192
  * @param values - The interpreted values.
181
193
  * @param self - Indicates that this should refer to itself instead of a property when creating bindings.
182
194
  * @param behaviorConfig - The binding behavior configuration object.
195
+ * @param observerMap - ObserverMap instance for caching binding paths (optional).
183
196
  */
184
- resolveDataBinding(innerHTML, strings, values, self = false, behaviorConfig) {
197
+ resolveDataBinding(innerHTML, strings, values, self = false, behaviorConfig, parentContext, level, observerMap) {
185
198
  return __awaiter(this, void 0, void 0, function* () {
186
199
  switch (behaviorConfig.subtype) {
187
- case "content":
188
- {
189
- strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex));
190
- const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
191
- const binding = (x, c) => pathResolver(propName, self)(x, c);
192
- values.push(binding);
193
- yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingEndIndex, innerHTML.length), strings, values, self);
194
- }
200
+ case "content": {
201
+ strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex));
202
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
203
+ const binding = bindingResolver(propName, self, parentContext, "access", observerMap !== null && observerMap !== void 0 ? observerMap : null, null, level);
204
+ const contentBinding = (x, c) => binding(x, c);
205
+ values.push(contentBinding);
206
+ yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingEndIndex, innerHTML.length), strings, values, self, parentContext, level, observerMap);
195
207
  break;
196
- case "attribute":
208
+ }
209
+ case "attribute": {
197
210
  strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex));
198
211
  if (behaviorConfig.aspect === "@") {
199
212
  const bindingHTML = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
@@ -203,28 +216,30 @@ class TemplateElement extends FASTElement {
203
216
  (closingParenthesis - openingParenthesis) -
204
217
  1);
205
218
  const arg = bindingHTML.slice(openingParenthesis + 1, closingParenthesis);
206
- const binding = (x, c) => pathResolver(propName, self)(x, c).bind(x)(...(arg === "e" ? [c.event] : []), ...(arg !== "e" && arg !== ""
207
- ? [pathResolver(arg)(x, c)]
219
+ const binding = bindingResolver(propName, self, parentContext, "event", observerMap !== null && observerMap !== void 0 ? observerMap : null, null, level);
220
+ const attributeBinding = (x, c) => binding(x, c).bind(x)(...(arg === "e" ? [c.event] : []), ...(arg !== "e" && arg !== ""
221
+ ? [
222
+ bindingResolver(arg, self, parentContext, "event", observerMap !== null && observerMap !== void 0 ? observerMap : null, null, level)(x, c),
223
+ ]
208
224
  : []));
209
- values.push(binding);
225
+ values.push(attributeBinding);
210
226
  }
211
227
  else {
212
228
  const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
213
- const binding = (x, c) => pathResolver(propName, self)(x, c);
214
- values.push(binding);
229
+ const binding = bindingResolver(propName, self, parentContext, "access", observerMap !== null && observerMap !== void 0 ? observerMap : null, null, level);
230
+ const attributeBinding = (x, c) => binding(x, c);
231
+ values.push(attributeBinding);
215
232
  }
216
- yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingEndIndex, innerHTML.length), strings, values, self);
233
+ yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingEndIndex, innerHTML.length), strings, values, self, parentContext, level, observerMap);
217
234
  break;
218
- case "attributeDirective":
219
- {
220
- strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex -
221
- behaviorConfig.name.length -
222
- 4));
223
- const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
224
- yield this.resolveAttributeDirective(behaviorConfig.name, propName, values);
225
- yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingEndIndex + 1, innerHTML.length), strings, values, self);
226
- }
235
+ }
236
+ case "attributeDirective": {
237
+ strings.push(innerHTML.slice(0, behaviorConfig.openingStartIndex - behaviorConfig.name.length - 4));
238
+ const propName = innerHTML.slice(behaviorConfig.openingEndIndex, behaviorConfig.closingStartIndex);
239
+ yield this.resolveAttributeDirective(behaviorConfig.name, propName, values);
240
+ yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingEndIndex + 1, innerHTML.length), strings, values, self, parentContext, level, observerMap);
227
241
  break;
242
+ }
228
243
  }
229
244
  });
230
245
  }
@@ -234,8 +249,9 @@ class TemplateElement extends FASTElement {
234
249
  * @param strings - The strings array.
235
250
  * @param values - The interpreted values.
236
251
  * @param self - Indicates that this should refer to itself instead of a property when creating bindings.
252
+ * @param observerMap - ObserverMap instance for caching binding paths (optional).
237
253
  */
238
- resolveInnerHTML(innerHTML, strings, values, self = false) {
254
+ resolveInnerHTML(innerHTML, strings, values, self = false, parentContext, level, observerMap) {
239
255
  return __awaiter(this, void 0, void 0, function* () {
240
256
  const behaviorConfig = getNextBehavior(innerHTML);
241
257
  if (behaviorConfig === null) {
@@ -243,14 +259,16 @@ class TemplateElement extends FASTElement {
243
259
  }
244
260
  else {
245
261
  switch (behaviorConfig.type) {
246
- case "dataBinding":
247
- yield this.resolveDataBinding(innerHTML, strings, values, self, behaviorConfig);
262
+ case "dataBinding": {
263
+ yield this.resolveDataBinding(innerHTML, strings, values, self, behaviorConfig, parentContext, level, observerMap);
248
264
  break;
249
- case "templateDirective":
265
+ }
266
+ case "templateDirective": {
250
267
  strings.push(innerHTML.slice(0, behaviorConfig.openingTagStartIndex));
251
- yield this.resolveTemplateDirective(behaviorConfig, values, innerHTML, self);
252
- yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingTagEndIndex, innerHTML.length), strings, values, self);
268
+ yield this.resolveTemplateDirective(behaviorConfig, values, innerHTML, self, parentContext, level, observerMap);
269
+ yield this.resolveInnerHTML(innerHTML.slice(behaviorConfig.closingTagEndIndex, innerHTML.length), strings, values, self, parentContext, level, observerMap);
253
270
  break;
271
+ }
254
272
  }
255
273
  }
256
274
  });
@@ -263,7 +281,7 @@ class TemplateElement extends FASTElement {
263
281
  return __awaiter(this, void 0, void 0, function* () {
264
282
  const allPartials = Object.entries(getAllPartials(unresolvedInnerHTML));
265
283
  for (let i = 0, partialLength = allPartials.length; i < partialLength; i++) {
266
- const { strings, values } = yield this.resolveStringsAndValues(allPartials[i][1].innerHTML);
284
+ const { strings, values } = yield this.resolveStringsAndValues(allPartials[i][1].innerHTML, undefined, null, 0, this.observerMap);
267
285
  this.partials[allPartials[i][0]] = this.resolveTemplateOrBehavior(strings, values);
268
286
  }
269
287
  });