@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,36 @@
1
+ import { createTypeRegistry } from "../platform.js";
2
+ const registry = createTypeRegistry();
3
+ /**
4
+ * Instructs the css engine to provide styles during CSS template composition.
5
+ * @public
6
+ */
7
+ export const CSSDirective = Object.freeze({
8
+ /**
9
+ * Gets the directive definition associated with the instance.
10
+ * @param instance - The directive instance to retrieve the definition for.
11
+ */
12
+ getForInstance: registry.getForInstance,
13
+ /**
14
+ * Gets the directive definition associated with the specified type.
15
+ * @param type - The directive type to retrieve the definition for.
16
+ */
17
+ getByType: registry.getByType,
18
+ /**
19
+ * Defines a CSSDirective.
20
+ * @param type - The type to define as a directive.
21
+ */
22
+ define(type) {
23
+ registry.register({ type });
24
+ return type;
25
+ },
26
+ });
27
+ /**
28
+ * Decorator: Defines a CSSDirective.
29
+ * @public
30
+ */
31
+ export function cssDirective() {
32
+ /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
33
+ return function (type) {
34
+ CSSDirective.define(type);
35
+ };
36
+ }
@@ -0,0 +1,56 @@
1
+ import { CSSDirective } from "./css-directive.js";
2
+ import { ElementStyles } from "./element-styles.js";
3
+ function collectStyles(strings, values) {
4
+ const styles = [];
5
+ let cssString = "";
6
+ for (let i = 0, ii = strings.length - 1; i < ii; ++i) {
7
+ cssString += strings[i];
8
+ let value = values[i];
9
+ if (CSSDirective.getForInstance(value) !== void 0) {
10
+ value = value.createCSS();
11
+ }
12
+ if (value instanceof ElementStyles || value instanceof CSSStyleSheet) {
13
+ if (cssString.trim() !== "") {
14
+ styles.push(cssString);
15
+ cssString = "";
16
+ }
17
+ styles.push(value);
18
+ }
19
+ else {
20
+ cssString += value;
21
+ }
22
+ }
23
+ cssString += strings[strings.length - 1];
24
+ if (cssString.trim() !== "") {
25
+ styles.push(cssString);
26
+ }
27
+ return styles;
28
+ }
29
+ /**
30
+ * Transforms a template literal string into styles.
31
+ * @param strings - The string fragments that are interpolated with the values.
32
+ * @param values - The values that are interpolated with the string fragments.
33
+ * @remarks
34
+ * The css helper supports interpolation of static composable styles and CSS directives.
35
+ * @public
36
+ */
37
+ export const css = ((strings, ...values) => {
38
+ return new ElementStyles(collectStyles(strings, values));
39
+ });
40
+ class CSSPartial {
41
+ constructor(styles) {
42
+ this.value =
43
+ styles.length === 0
44
+ ? ""
45
+ : styles.length === 1
46
+ ? styles[0]
47
+ : new ElementStyles(styles);
48
+ }
49
+ createCSS() {
50
+ return this.value;
51
+ }
52
+ }
53
+ CSSDirective.define(CSSPartial);
54
+ css.partial = (strings, ...values) => {
55
+ return new CSSPartial(collectStyles(strings, values));
56
+ };
@@ -0,0 +1,144 @@
1
+ let DefaultStyleStrategy;
2
+ function reduceStyles(styles) {
3
+ return styles.reduce((reduced, current) => {
4
+ if (current instanceof ElementStyles) {
5
+ reduced.push(...reduceStyles(current.styles));
6
+ }
7
+ else {
8
+ reduced.push(current);
9
+ }
10
+ return reduced;
11
+ }, []);
12
+ }
13
+ /**
14
+ * Represents styles that can be applied to a custom element.
15
+ * @public
16
+ */
17
+ export class ElementStyles {
18
+ /**
19
+ * Gets the StyleStrategy associated with these element styles.
20
+ */
21
+ get strategy() {
22
+ if (this._strategy === null) {
23
+ if (!DefaultStyleStrategy) {
24
+ ElementStyles.setDefaultStrategy(ElementStyles.supportsAdoptedStyleSheets
25
+ ? createAdoptedSheetsStrategy()
26
+ : createStyleElementStrategy());
27
+ }
28
+ this.withStrategy(DefaultStyleStrategy);
29
+ }
30
+ return this._strategy;
31
+ }
32
+ /**
33
+ * Creates an instance of ElementStyles.
34
+ * @param styles - The styles that will be associated with elements.
35
+ */
36
+ constructor(styles) {
37
+ this.styles = styles;
38
+ this.targets = new WeakSet();
39
+ this._strategy = null;
40
+ }
41
+ /** @internal */
42
+ addStylesTo(target) {
43
+ this.strategy.addStylesTo(target);
44
+ this.targets.add(target);
45
+ }
46
+ /** @internal */
47
+ removeStylesFrom(target) {
48
+ this.strategy.removeStylesFrom(target);
49
+ this.targets.delete(target);
50
+ }
51
+ /** @internal */
52
+ isAttachedTo(target) {
53
+ return this.targets.has(target);
54
+ }
55
+ /**
56
+ * Sets the strategy that handles adding/removing these styles for an element.
57
+ * @param strategy - The strategy to use.
58
+ */
59
+ withStrategy(Strategy) {
60
+ this._strategy = new Strategy(reduceStyles(this.styles));
61
+ return this;
62
+ }
63
+ /**
64
+ * Sets the default strategy type to use when creating style strategies.
65
+ * @param Strategy - The strategy type to construct.
66
+ */
67
+ static setDefaultStrategy(Strategy) {
68
+ DefaultStyleStrategy = Strategy;
69
+ }
70
+ /**
71
+ * Normalizes a set of composable style options.
72
+ * @param styles - The style options to normalize.
73
+ * @returns A singular ElementStyles instance or undefined.
74
+ */
75
+ static normalize(styles) {
76
+ return styles === void 0
77
+ ? void 0
78
+ : Array.isArray(styles)
79
+ ? new ElementStyles(styles)
80
+ : styles instanceof ElementStyles
81
+ ? styles
82
+ : new ElementStyles([styles]);
83
+ }
84
+ }
85
+ /**
86
+ * Indicates whether the DOM supports the adoptedStyleSheets feature.
87
+ */
88
+ ElementStyles.supportsAdoptedStyleSheets = Array.isArray(document.adoptedStyleSheets) &&
89
+ "replace" in CSSStyleSheet.prototype;
90
+ // Fallback strategy factories used when no strategy has been explicitly set
91
+ // via ElementStyles.setDefaultStrategy (e.g. when importing only from the
92
+ // styles.js subpath without loading element-controller.ts).
93
+ function createAdoptedSheetsStrategy() {
94
+ const cache = new Map();
95
+ return class FallbackAdoptedSheetsStrategy {
96
+ constructor(styles) {
97
+ this.sheets = styles.map(x => {
98
+ if (x instanceof CSSStyleSheet) {
99
+ return x;
100
+ }
101
+ let sheet = cache.get(x);
102
+ if (sheet === void 0) {
103
+ sheet = new CSSStyleSheet();
104
+ sheet.replaceSync(x);
105
+ cache.set(x, sheet);
106
+ }
107
+ return sheet;
108
+ });
109
+ }
110
+ addStylesTo(target) {
111
+ const t = target;
112
+ t.adoptedStyleSheets = [...t.adoptedStyleSheets, ...this.sheets];
113
+ }
114
+ removeStylesFrom(target) {
115
+ const t = target;
116
+ t.adoptedStyleSheets = t.adoptedStyleSheets.filter((x) => this.sheets.indexOf(x) === -1);
117
+ }
118
+ };
119
+ }
120
+ let fallbackStyleId = 0;
121
+ function createStyleElementStrategy() {
122
+ return class FallbackStyleElementStrategy {
123
+ constructor(styles) {
124
+ this.styles = styles;
125
+ this.styleClass = `fast-${++fallbackStyleId}`;
126
+ }
127
+ addStylesTo(target) {
128
+ const t = target === document ? document.body : target;
129
+ for (let i = 0; i < this.styles.length; i++) {
130
+ const element = document.createElement("style");
131
+ element.innerHTML = this.styles[i];
132
+ element.className = this.styleClass;
133
+ t.append(element);
134
+ }
135
+ }
136
+ removeStylesFrom(target) {
137
+ const t = target === document ? document.body : target;
138
+ const styles = t.querySelectorAll(`.${this.styleClass}`);
139
+ for (let i = 0, ii = styles.length; i < ii; ++i) {
140
+ t.removeChild(styles[i]);
141
+ }
142
+ }
143
+ };
144
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,67 @@
1
+ import { isString, noop } from "../interfaces.js";
2
+ import { HTMLDirective } from "./html-directive.js";
3
+ import { NodeObservationDirective, } from "./node-observation.js";
4
+ /**
5
+ * The runtime behavior for child node observation.
6
+ * @public
7
+ */
8
+ export class ChildrenDirective extends NodeObservationDirective {
9
+ /**
10
+ * Creates an instance of ChildrenDirective.
11
+ * @param options - The options to use in configuring the child observation behavior.
12
+ */
13
+ constructor(options) {
14
+ super(options);
15
+ this.observerProperty = Symbol();
16
+ options.childList = true;
17
+ }
18
+ /**
19
+ * Begins observation of the nodes.
20
+ * @param target - The target to observe.
21
+ */
22
+ observe(target) {
23
+ let observer = target[this.observerProperty];
24
+ if (!observer) {
25
+ const handleEvent = (mutations, observer) => {
26
+ this.updateTarget(this.getSource(target), this.computeNodes(target));
27
+ };
28
+ observer = new MutationObserver(handleEvent);
29
+ observer.toJSON = noop;
30
+ target[this.observerProperty] = observer;
31
+ }
32
+ observer.observe(target, this.options);
33
+ }
34
+ /**
35
+ * Disconnects observation of the nodes.
36
+ * @param target - The target to unobserve.
37
+ */
38
+ disconnect(target) {
39
+ const observer = target[this.observerProperty];
40
+ observer.disconnect();
41
+ }
42
+ /**
43
+ * Retrieves the raw nodes that should be assigned to the source property.
44
+ * @param target - The target to get the node to.
45
+ */
46
+ getNodes(target) {
47
+ if ("selector" in this.options) {
48
+ return Array.from(target.querySelectorAll(this.options.selector));
49
+ }
50
+ return Array.from(target.childNodes);
51
+ }
52
+ }
53
+ HTMLDirective.define(ChildrenDirective);
54
+ /**
55
+ * A directive that observes the `childNodes` of an element and updates a property
56
+ * whenever they change.
57
+ * @param propertyOrOptions - The options used to configure child node observation.
58
+ * @public
59
+ */
60
+ export function children(propertyOrOptions) {
61
+ if (isString(propertyOrOptions)) {
62
+ propertyOrOptions = {
63
+ property: propertyOrOptions,
64
+ };
65
+ }
66
+ return new ChildrenDirective(propertyOrOptions);
67
+ }
@@ -0,0 +1,359 @@
1
+ import { oneTime } from "../binding/one-time.js";
2
+ import { oneWay } from "../binding/one-way.js";
3
+ import { DOM } from "../dom.js";
4
+ import { isFunction, isString, Message } from "../interfaces.js";
5
+ import { FAST } from "../platform.js";
6
+ import { HTMLBindingDirective } from "./html-binding-directive.js";
7
+ import { HTMLDirective, } from "./html-directive.js";
8
+ import { nextId, Parser } from "./markup.js";
9
+ import { HTMLView } from "./view.js";
10
+ /**
11
+ * Builds a hierarchical node ID by appending the child index to the parent's ID.
12
+ * For example, the third child of root is "r.2", and its first child is "r.2.0".
13
+ * These IDs are used as property names on the targets prototype so that each
14
+ * binding's target DOM node can be lazily resolved via a chain of childNodes lookups.
15
+ */
16
+ const targetIdFrom = (parentId, nodeIndex) => `${parentId}.${nodeIndex}`;
17
+ const descriptorCache = {};
18
+ // used to prevent creating lots of objects just to track node and index while compiling
19
+ const next = {
20
+ index: 0,
21
+ node: null,
22
+ };
23
+ function tryWarn(name) {
24
+ if (!name.startsWith("fast-")) {
25
+ FAST.warn(Message.hostBindingWithoutHost, { name });
26
+ }
27
+ }
28
+ const warningHost = new Proxy(document.createElement("div"), {
29
+ get(target, property) {
30
+ tryWarn(property);
31
+ const value = Reflect.get(target, property);
32
+ return isFunction(value) ? value.bind(target) : value;
33
+ },
34
+ set(target, property, value) {
35
+ tryWarn(property);
36
+ return Reflect.set(target, property, value);
37
+ },
38
+ });
39
+ class CompilationContext {
40
+ constructor(fragment, directives, policy) {
41
+ this.fragment = fragment;
42
+ this.directives = directives;
43
+ this.policy = policy;
44
+ this.proto = null;
45
+ this.nodeIds = new Set();
46
+ this.descriptors = {};
47
+ this.factories = [];
48
+ }
49
+ addFactory(factory, parentId, nodeId, targetIndex, tagName) {
50
+ var _a, _b;
51
+ if (!this.nodeIds.has(nodeId)) {
52
+ this.nodeIds.add(nodeId);
53
+ this.addTargetDescriptor(parentId, nodeId, targetIndex);
54
+ }
55
+ factory.id = (_a = factory.id) !== null && _a !== void 0 ? _a : nextId();
56
+ factory.targetNodeId = nodeId;
57
+ factory.targetTagName = tagName;
58
+ factory.policy = (_b = factory.policy) !== null && _b !== void 0 ? _b : this.policy;
59
+ this.factories.push(factory);
60
+ }
61
+ freeze() {
62
+ this.proto = Object.create(null, this.descriptors);
63
+ return this;
64
+ }
65
+ /**
66
+ * Registers a lazy getter on the targets prototype that resolves a DOM node
67
+ * by navigating from its parent's childNodes at the given index. Getters are
68
+ * chained: accessing targets["r.0.2"] first resolves targets["r.0"] (which
69
+ * resolves targets["r"]), then returns childNodes[2]. Results are cached so
70
+ * each node is resolved at most once per view instance.
71
+ */
72
+ addTargetDescriptor(parentId, targetId, targetIndex) {
73
+ const descriptors = this.descriptors;
74
+ if (targetId === "r" || // root
75
+ targetId === "h" || // host
76
+ descriptors[targetId]) {
77
+ return;
78
+ }
79
+ if (!descriptors[parentId]) {
80
+ const index = parentId.lastIndexOf(".");
81
+ const grandparentId = parentId.substring(0, index);
82
+ const childIndex = parseInt(parentId.substring(index + 1), 10);
83
+ this.addTargetDescriptor(grandparentId, parentId, childIndex);
84
+ }
85
+ let descriptor = descriptorCache[targetId];
86
+ if (!descriptor) {
87
+ const field = `_${targetId}`;
88
+ descriptorCache[targetId] = descriptor = {
89
+ get() {
90
+ var _a;
91
+ return ((_a = this[field]) !== null && _a !== void 0 ? _a : (this[field] = this[parentId].childNodes[targetIndex]));
92
+ },
93
+ };
94
+ }
95
+ descriptors[targetId] = descriptor;
96
+ }
97
+ /**
98
+ * Creates a new HTMLView by cloning the compiled DocumentFragment and building
99
+ * a targets object. The targets prototype contains lazy getters that resolve
100
+ * each binding's target DOM node via childNodes traversal. Accessing every
101
+ * registered nodeId eagerly triggers the getter chain so all nodes are resolved
102
+ * before behaviors are bound.
103
+ */
104
+ createView(hostBindingTarget, scope) {
105
+ const fragment = scope === void 0
106
+ ? this.fragment.cloneNode(true)
107
+ : cloneIntoScope(this.fragment, scope);
108
+ const targets = Object.create(this.proto);
109
+ targets.r = fragment; // root — the cloned DocumentFragment
110
+ targets.h = hostBindingTarget !== null && hostBindingTarget !== void 0 ? hostBindingTarget : warningHost; // host — the custom element
111
+ for (const id of this.nodeIds) {
112
+ Reflect.get(targets, id); // trigger lazy getter to resolve and cache the DOM node
113
+ }
114
+ return new HTMLView(fragment, this.factories, targets, scope);
115
+ }
116
+ }
117
+ let inertDocument;
118
+ const registryFreeSources = new WeakMap();
119
+ /**
120
+ * Returns a copy of a compiled fragment whose elements have no custom element
121
+ * registry. Elements that already have one (all elements of the fragment that was
122
+ * adopted into the main document have the global registry) keep it when cloned, so
123
+ * a registry can only be chosen for clones of a registry-free source.
124
+ */
125
+ function getRegistryFreeSource(fragment) {
126
+ let source = registryFreeSources.get(fragment);
127
+ if (source === void 0) {
128
+ inertDocument !== null && inertDocument !== void 0 ? inertDocument : (inertDocument = document.implementation.createHTMLDocument(""));
129
+ source = fragment.cloneNode(true);
130
+ inertDocument.adoptNode(source);
131
+ registryFreeSources.set(fragment, source);
132
+ }
133
+ return source;
134
+ }
135
+ /**
136
+ * Clones a compiled fragment so that custom elements inside it are created against
137
+ * the scoped custom element registry of `scope`.
138
+ *
139
+ * @remarks
140
+ * The compiled fragment is adopted into the main document, so a plain `cloneNode`
141
+ * creates its children against the *global* registry and a tag that is only defined
142
+ * in a scoped registry is never upgraded. Only views for hosts that were given a
143
+ * registry take this path (see `ElementController`); every other view keeps using
144
+ * `cloneNode(true)`.
145
+ *
146
+ * - Native scoped registries: `document.importNode` with a `customElementRegistry`,
147
+ * from a registry-free copy of the fragment (created once per template).
148
+ * - `@webcomponents/scoped-custom-element-registry` (0.0.x): `ShadowRoot.importNode`,
149
+ * which the polyfill patches to resolve the scope from the shadow root.
150
+ * - Otherwise: a plain clone.
151
+ */
152
+ function cloneIntoScope(fragment, scope) {
153
+ var _a;
154
+ const scoped = scope;
155
+ const registry = (_a = scoped.customElementRegistry) !== null && _a !== void 0 ? _a : scoped.registry;
156
+ if (registry) {
157
+ // A registry that can `initialize` is the native (or spec-aligned) API.
158
+ if (registry !== globalThis.customElements &&
159
+ typeof registry.initialize === "function") {
160
+ return document.importNode(getRegistryFreeSource(fragment), {
161
+ selfOnly: false,
162
+ customElementRegistry: registry,
163
+ });
164
+ }
165
+ if (typeof scoped.importNode === "function") {
166
+ return scoped.importNode(fragment, true);
167
+ }
168
+ }
169
+ return fragment.cloneNode(true);
170
+ }
171
+ function compileAttributes(context, parentId, node, nodeId, nodeIndex, includeBasicValues = false) {
172
+ const attributes = node.attributes;
173
+ const directives = context.directives;
174
+ for (let i = 0, ii = attributes.length; i < ii; ++i) {
175
+ const attr = attributes[i];
176
+ const attrValue = attr.value;
177
+ const parseResult = Parser.parse(attrValue, directives);
178
+ let result = null;
179
+ if (parseResult === null) {
180
+ if (includeBasicValues) {
181
+ result = new HTMLBindingDirective(oneTime(() => attrValue, context.policy));
182
+ HTMLDirective.assignAspect(result, attr.name);
183
+ }
184
+ }
185
+ else {
186
+ result = Compiler.aggregate(parseResult, context.policy);
187
+ }
188
+ if (result !== null) {
189
+ node.removeAttributeNode(attr);
190
+ i--;
191
+ ii--;
192
+ context.addFactory(result, parentId, nodeId, nodeIndex, node.tagName);
193
+ }
194
+ }
195
+ }
196
+ function compileContent(context, node, parentId, nodeId, nodeIndex) {
197
+ const parseResult = Parser.parse(node.textContent, context.directives);
198
+ if (parseResult === null) {
199
+ next.node = node.nextSibling;
200
+ next.index = nodeIndex + 1;
201
+ return next;
202
+ }
203
+ let currentNode;
204
+ let lastNode = (currentNode = node);
205
+ for (let i = 0, ii = parseResult.length; i < ii; ++i) {
206
+ const currentPart = parseResult[i];
207
+ if (i !== 0) {
208
+ nodeIndex++;
209
+ nodeId = targetIdFrom(parentId, nodeIndex);
210
+ currentNode = lastNode.parentNode.insertBefore(document.createTextNode(""), lastNode.nextSibling);
211
+ }
212
+ if (isString(currentPart)) {
213
+ currentNode.textContent = currentPart;
214
+ }
215
+ else {
216
+ currentNode.textContent = " ";
217
+ HTMLDirective.assignAspect(currentPart);
218
+ context.addFactory(currentPart, parentId, nodeId, nodeIndex, null);
219
+ }
220
+ lastNode = currentNode;
221
+ }
222
+ next.index = nodeIndex + 1;
223
+ next.node = lastNode.nextSibling;
224
+ return next;
225
+ }
226
+ function compileChildren(context, parent, parentId) {
227
+ let nodeIndex = 0;
228
+ let childNode = parent.firstChild;
229
+ while (childNode) {
230
+ const result = compileNode(context, parentId, childNode, nodeIndex);
231
+ childNode = result.node;
232
+ nodeIndex = result.index;
233
+ }
234
+ }
235
+ function compileNode(context, parentId, node, nodeIndex) {
236
+ const nodeId = targetIdFrom(parentId, nodeIndex);
237
+ switch (node.nodeType) {
238
+ case 1: // element node
239
+ compileAttributes(context, parentId, node, nodeId, nodeIndex);
240
+ compileChildren(context, node, nodeId);
241
+ break;
242
+ case 3: // text node
243
+ return compileContent(context, node, parentId, nodeId, nodeIndex);
244
+ case 8: {
245
+ // comment
246
+ const parts = Parser.parse(node.data, context.directives);
247
+ if (parts !== null) {
248
+ context.addFactory(Compiler.aggregate(parts), parentId, nodeId, nodeIndex, null);
249
+ }
250
+ break;
251
+ }
252
+ }
253
+ next.index = nodeIndex + 1;
254
+ next.node = node.nextSibling;
255
+ return next;
256
+ }
257
+ function isMarker(node, directives) {
258
+ return (node &&
259
+ node.nodeType === 8 &&
260
+ Parser.parse(node.data, directives) !== null);
261
+ }
262
+ const templateTag = "TEMPLATE";
263
+ /**
264
+ * Common APIs related to compilation.
265
+ * @public
266
+ */
267
+ export const Compiler = {
268
+ /**
269
+ * Compiles a template and associated directives into a compilation
270
+ * result which can be used to create views.
271
+ * @param html - The html string or template element to compile.
272
+ * @param factories - The behavior factories referenced by the template.
273
+ * @param policy - The security policy to compile the html with.
274
+ * @remarks
275
+ * The template that is provided for compilation is altered in-place
276
+ * and cannot be compiled again. If the original template must be preserved,
277
+ * it is recommended that you clone the original and pass the clone to this API.
278
+ * @public
279
+ */
280
+ compile(html, factories, policy = DOM.policy) {
281
+ let template;
282
+ if (isString(html)) {
283
+ template = document.createElement(templateTag);
284
+ template.innerHTML = policy.createHTML(html);
285
+ const fec = template.content.firstElementChild;
286
+ if (fec !== null && fec.tagName === templateTag) {
287
+ template = fec;
288
+ }
289
+ }
290
+ else {
291
+ template = html;
292
+ }
293
+ if (!template.content.firstChild && !template.content.lastChild) {
294
+ template.content.appendChild(document.createComment(""));
295
+ }
296
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=1111864
297
+ const fragment = document.adoptNode(template.content);
298
+ const context = new CompilationContext(fragment, factories, policy);
299
+ compileAttributes(context, "", template, /* host */ "h", 0, true);
300
+ if (
301
+ // If the first node in a fragment is a marker, that means it's an unstable first node,
302
+ // because something like a when, repeat, etc. could add nodes before the marker.
303
+ // To mitigate this, we insert a stable first node. However, if we insert a node,
304
+ // that will alter the result of the TreeWalker. So, we also need to offset the target index.
305
+ isMarker(fragment.firstChild, factories) ||
306
+ // Or if there is only one node and a directive, it means the template's content
307
+ // is *only* the directive. In that case, HTMLView.dispose() misses any nodes inserted by
308
+ // the directive. Inserting a new node ensures proper disposal of nodes added by the directive.
309
+ (fragment.childNodes.length === 1 && Object.keys(factories).length > 0)) {
310
+ fragment.insertBefore(document.createComment(""), fragment.firstChild);
311
+ }
312
+ compileChildren(context, fragment, /* root */ "r");
313
+ next.node = null; // prevent leaks
314
+ return context.freeze();
315
+ },
316
+ /**
317
+ * Sets the default compilation strategy that will be used by the ViewTemplate whenever
318
+ * it needs to compile a view preprocessed with the html template function.
319
+ * @param strategy - The compilation strategy to use when compiling templates.
320
+ */
321
+ setDefaultStrategy(strategy) {
322
+ this.compile = strategy;
323
+ },
324
+ /**
325
+ * Aggregates an array of strings and directives into a single directive.
326
+ * @param parts - A heterogeneous array of static strings interspersed with
327
+ * directives.
328
+ * @param policy - The security policy to use with the aggregated bindings.
329
+ * @returns A single inline directive that aggregates the behavior of all the parts.
330
+ */
331
+ aggregate(parts, policy = DOM.policy) {
332
+ if (parts.length === 1) {
333
+ return parts[0];
334
+ }
335
+ let sourceAspect;
336
+ let isVolatile = false;
337
+ let bindingPolicy = void 0;
338
+ const partCount = parts.length;
339
+ const finalParts = parts.map((x) => {
340
+ if (isString(x)) {
341
+ return () => x;
342
+ }
343
+ sourceAspect = x.sourceAspect || sourceAspect;
344
+ isVolatile = isVolatile || x.dataBinding.isVolatile;
345
+ bindingPolicy = bindingPolicy || x.dataBinding.policy;
346
+ return x.dataBinding.evaluate;
347
+ });
348
+ const expression = (scope, context) => {
349
+ let output = "";
350
+ for (let i = 0; i < partCount; ++i) {
351
+ output += finalParts[i](scope, context);
352
+ }
353
+ return output;
354
+ };
355
+ const directive = new HTMLBindingDirective(oneWay(expression, bindingPolicy !== null && bindingPolicy !== void 0 ? bindingPolicy : policy, isVolatile));
356
+ HTMLDirective.assignAspect(directive, sourceAspect);
357
+ return directive;
358
+ },
359
+ };