@lushly-dev/fast-element 0.0.0-stage → 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 (257) hide show
  1. package/CHANGELOG.md +1059 -0
  2. package/LICENSE +23 -0
  3. package/README.md +280 -2
  4. package/dist/command/command.api.json +7857 -0
  5. package/dist/context/context.api.json +1084 -0
  6. package/dist/declarative/declarative.api.json +8130 -0
  7. package/dist/definition-schema/definition-schema.api.json +2689 -0
  8. package/dist/di/di.api.json +4945 -0
  9. package/dist/dts/arrays.d.ts +2 -0
  10. package/dist/dts/binding/binding.d.ts +59 -0
  11. package/dist/dts/binding/exports.d.ts +9 -0
  12. package/dist/dts/binding/normalize.d.ts +9 -0
  13. package/dist/dts/binding/one-time.d.ts +11 -0
  14. package/dist/dts/binding/one-way.d.ts +20 -0
  15. package/dist/dts/binding/signal.d.ts +36 -0
  16. package/dist/dts/binding/two-way.d.ts +44 -0
  17. package/dist/dts/command/behavior.d.ts +94 -0
  18. package/dist/dts/command/behaviors/confirm-behavior.d.ts +139 -0
  19. package/dist/dts/command/behaviors/undo-behavior.d.ts +178 -0
  20. package/dist/dts/command/command.d.ts +79 -0
  21. package/dist/dts/command/component-registry.d.ts +50 -0
  22. package/dist/dts/command/components/confirm-dialog.d.ts +117 -0
  23. package/dist/dts/command/index.d.ts +21 -0
  24. package/dist/dts/command/registry.d.ts +201 -0
  25. package/dist/dts/command/schema-validation.d.ts +45 -0
  26. package/dist/dts/command/types.d.ts +332 -0
  27. package/dist/dts/command/validation.d.ts +116 -0
  28. package/dist/dts/command/weak-ref.d.ts +11 -0
  29. package/dist/dts/components/attributes.d.ts +153 -0
  30. package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
  31. package/dist/dts/components/element-controller.d.ts +349 -0
  32. package/dist/dts/components/element-hydration.d.ts +2 -0
  33. package/dist/dts/components/enable-hydration.d.ts +66 -0
  34. package/dist/dts/components/fast-definitions.d.ts +211 -0
  35. package/dist/dts/components/fast-element-registry.d.ts +23 -0
  36. package/dist/dts/components/fast-element.d.ts +91 -0
  37. package/dist/dts/components/hydration-tracker.d.ts +110 -0
  38. package/dist/dts/components/hydration.d.ts +52 -0
  39. package/dist/dts/components/schema.d.ts +205 -0
  40. package/dist/dts/context.d.ts +171 -0
  41. package/dist/dts/debug.d.ts +5 -0
  42. package/dist/dts/declarative/attribute-map.d.ts +58 -0
  43. package/dist/dts/declarative/debug.d.ts +4 -0
  44. package/dist/dts/declarative/index.d.ts +14 -0
  45. package/dist/dts/declarative/interfaces.d.ts +8 -0
  46. package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
  47. package/dist/dts/declarative/observer-map.d.ts +89 -0
  48. package/dist/dts/declarative/runtime.d.ts +5 -0
  49. package/dist/dts/declarative/syntax.d.ts +21 -0
  50. package/dist/dts/declarative/template-bridge.d.ts +33 -0
  51. package/dist/dts/declarative/template-parser.d.ts +98 -0
  52. package/dist/dts/declarative/template.d.ts +9 -0
  53. package/dist/dts/declarative/utilities.d.ts +358 -0
  54. package/dist/dts/definition-schema/api.d.ts +42 -0
  55. package/dist/dts/definition-schema/cem.d.ts +78 -0
  56. package/dist/dts/definition-schema/extension.d.ts +18 -0
  57. package/dist/dts/definition-schema/extract.d.ts +38 -0
  58. package/dist/dts/definition-schema/index.d.ts +9 -0
  59. package/dist/dts/definition-schema/storage.d.ts +35 -0
  60. package/dist/dts/definition-schema/types.d.ts +176 -0
  61. package/dist/dts/dev-mode.d.ts +13 -0
  62. package/dist/dts/di/di.d.ts +894 -0
  63. package/dist/dts/dom-policy.d.ts +101 -0
  64. package/dist/dts/dom.d.ts +88 -0
  65. package/dist/dts/hydration/diagnostics.d.ts +93 -0
  66. package/dist/dts/hydration/exports.d.ts +18 -0
  67. package/dist/dts/hydration/hydration-debugger.d.ts +35 -0
  68. package/dist/dts/hydration/messages.d.ts +62 -0
  69. package/dist/dts/hydration/runtime.d.ts +7 -0
  70. package/dist/dts/hydration/target-builder.d.ts +107 -0
  71. package/dist/dts/index.d.ts +51 -0
  72. package/dist/dts/index.debug.d.ts +1 -0
  73. package/dist/dts/index.rollup.d.ts +1 -0
  74. package/dist/dts/index.rollup.debug.d.ts +1 -0
  75. package/dist/dts/interfaces.d.ts +106 -0
  76. package/dist/dts/metadata.d.ts +26 -0
  77. package/dist/dts/observation/arrays.d.ts +248 -0
  78. package/dist/dts/observation/notifier.d.ts +127 -0
  79. package/dist/dts/observation/observable.d.ts +276 -0
  80. package/dist/dts/observation/update-queue.d.ts +40 -0
  81. package/dist/dts/observation/volatile.d.ts +9 -0
  82. package/dist/dts/platform.d.ts +87 -0
  83. package/dist/dts/registry.d.ts +2 -0
  84. package/dist/dts/render.d.ts +7 -0
  85. package/dist/dts/schema.d.ts +1 -0
  86. package/dist/dts/scoped/detection.d.ts +55 -0
  87. package/dist/dts/scoped/index.d.ts +68 -0
  88. package/dist/dts/scoped/mixin.d.ts +118 -0
  89. package/dist/dts/scoped/registry.d.ts +76 -0
  90. package/dist/dts/scoped/types.d.ts +48 -0
  91. package/dist/dts/state/exports.d.ts +3 -0
  92. package/dist/dts/state/reactive.d.ts +8 -0
  93. package/dist/dts/state/state.d.ts +141 -0
  94. package/dist/dts/state/visitor.d.ts +6 -0
  95. package/dist/dts/state/watch.d.ts +10 -0
  96. package/dist/dts/styles/css-directive.d.ts +50 -0
  97. package/dist/dts/styles/css.d.ts +34 -0
  98. package/dist/dts/styles/element-styles.d.ts +61 -0
  99. package/dist/dts/styles/host.d.ts +65 -0
  100. package/dist/dts/styles/style-strategy.d.ts +42 -0
  101. package/dist/dts/templating/children.d.ts +62 -0
  102. package/dist/dts/templating/compiler.d.ts +54 -0
  103. package/dist/dts/templating/html-binding-directive.d.ts +155 -0
  104. package/dist/dts/templating/html-directive.d.ts +218 -0
  105. package/dist/dts/templating/html.d.ts +1 -0
  106. package/dist/dts/templating/hydration-view.d.ts +130 -0
  107. package/dist/dts/templating/markup.d.ts +48 -0
  108. package/dist/dts/templating/node-observation.d.ts +99 -0
  109. package/dist/dts/templating/ref.d.ts +23 -0
  110. package/dist/dts/templating/render.d.ts +318 -0
  111. package/dist/dts/templating/repeat.d.ts +131 -0
  112. package/dist/dts/templating/slotted.d.ts +38 -0
  113. package/dist/dts/templating/template.d.ts +221 -0
  114. package/dist/dts/templating/view.d.ts +268 -0
  115. package/dist/dts/templating/when.d.ts +12 -0
  116. package/dist/dts/testing/exports.d.ts +3 -0
  117. package/dist/dts/testing/fakes.d.ts +15 -0
  118. package/dist/dts/testing/fixture.d.ts +84 -0
  119. package/dist/dts/testing/models.d.ts +20 -0
  120. package/dist/dts/testing/timeout.d.ts +7 -0
  121. package/dist/dts/trust/index.d.ts +8 -0
  122. package/dist/dts/trust/types.d.ts +48 -0
  123. package/dist/dts/trust/utils.d.ts +26 -0
  124. package/dist/dts/tsdoc-metadata.json +11 -0
  125. package/dist/dts/utilities.d.ts +76 -0
  126. package/dist/esm/arrays.js +1 -0
  127. package/dist/esm/binding/binding.js +18 -0
  128. package/dist/esm/binding/exports.js +6 -0
  129. package/dist/esm/binding/normalize.js +17 -0
  130. package/dist/esm/binding/one-time.js +21 -0
  131. package/dist/esm/binding/one-way.js +30 -0
  132. package/dist/esm/binding/signal.js +99 -0
  133. package/dist/esm/binding/two-way.js +110 -0
  134. package/dist/esm/command/behavior.js +155 -0
  135. package/dist/esm/command/behaviors/confirm-behavior.js +225 -0
  136. package/dist/esm/command/behaviors/undo-behavior.js +312 -0
  137. package/dist/esm/command/command.js +104 -0
  138. package/dist/esm/command/component-registry.js +107 -0
  139. package/dist/esm/command/components/confirm-dialog.js +370 -0
  140. package/dist/esm/command/index.js +22 -0
  141. package/dist/esm/command/registry.js +752 -0
  142. package/dist/esm/command/schema-validation.js +194 -0
  143. package/dist/esm/command/types.js +86 -0
  144. package/dist/esm/command/validation.js +511 -0
  145. package/dist/esm/command/weak-ref.js +5 -0
  146. package/dist/esm/components/attributes.js +219 -0
  147. package/dist/esm/components/definition-schema-transforms.js +23 -0
  148. package/dist/esm/components/element-controller.js +839 -0
  149. package/dist/esm/components/element-hydration.js +2 -0
  150. package/dist/esm/components/enable-hydration.js +123 -0
  151. package/dist/esm/components/fast-definitions.js +294 -0
  152. package/dist/esm/components/fast-element-registry.js +67 -0
  153. package/dist/esm/components/fast-element.js +82 -0
  154. package/dist/esm/components/hydration-tracker.js +210 -0
  155. package/dist/esm/components/hydration.js +187 -0
  156. package/dist/esm/components/schema.js +253 -0
  157. package/dist/esm/context.js +185 -0
  158. package/dist/esm/debug.js +71 -0
  159. package/dist/esm/declarative/attribute-map.js +121 -0
  160. package/dist/esm/declarative/debug.js +4 -0
  161. package/dist/esm/declarative/index.js +10 -0
  162. package/dist/esm/declarative/interfaces.js +9 -0
  163. package/dist/esm/declarative/observer-map-utilities.js +565 -0
  164. package/dist/esm/declarative/observer-map.js +216 -0
  165. package/dist/esm/declarative/runtime.js +14 -0
  166. package/dist/esm/declarative/syntax.js +36 -0
  167. package/dist/esm/declarative/template-bridge.js +160 -0
  168. package/dist/esm/declarative/template-parser.js +306 -0
  169. package/dist/esm/declarative/template.js +116 -0
  170. package/dist/esm/declarative/utilities.js +1069 -0
  171. package/dist/esm/definition-schema/api.js +129 -0
  172. package/dist/esm/definition-schema/cem.js +89 -0
  173. package/dist/esm/definition-schema/extension.js +53 -0
  174. package/dist/esm/definition-schema/extract.js +167 -0
  175. package/dist/esm/definition-schema/index.js +8 -0
  176. package/dist/esm/definition-schema/storage.js +58 -0
  177. package/dist/esm/definition-schema/types.js +8 -0
  178. package/dist/esm/dev-mode.js +22 -0
  179. package/dist/esm/di/di.js +1440 -0
  180. package/dist/esm/dom-policy.js +374 -0
  181. package/dist/esm/dom.js +101 -0
  182. package/dist/esm/hydration/diagnostics.js +50 -0
  183. package/dist/esm/hydration/exports.js +6 -0
  184. package/dist/esm/hydration/hydration-debugger.js +112 -0
  185. package/dist/esm/hydration/messages.js +84 -0
  186. package/dist/esm/hydration/runtime.js +33 -0
  187. package/dist/esm/hydration/target-builder.js +264 -0
  188. package/dist/esm/index.debug.js +3 -0
  189. package/dist/esm/index.js +49 -0
  190. package/dist/esm/index.rollup.debug.js +6 -0
  191. package/dist/esm/index.rollup.js +4 -0
  192. package/dist/esm/interfaces.js +55 -0
  193. package/dist/esm/metadata.js +63 -0
  194. package/dist/esm/observation/arrays.js +661 -0
  195. package/dist/esm/observation/notifier.js +164 -0
  196. package/dist/esm/observation/observable.js +324 -0
  197. package/dist/esm/observation/update-queue.js +56 -0
  198. package/dist/esm/observation/volatile.js +16 -0
  199. package/dist/esm/platform.js +98 -0
  200. package/dist/esm/registry.js +2 -0
  201. package/dist/esm/render.js +1 -0
  202. package/dist/esm/schema.js +1 -0
  203. package/dist/esm/scoped/detection.js +102 -0
  204. package/dist/esm/scoped/index.js +69 -0
  205. package/dist/esm/scoped/mixin.js +127 -0
  206. package/dist/esm/scoped/registry.js +125 -0
  207. package/dist/esm/scoped/types.js +4 -0
  208. package/dist/esm/state/exports.js +3 -0
  209. package/dist/esm/state/reactive.js +34 -0
  210. package/dist/esm/state/state.js +148 -0
  211. package/dist/esm/state/visitor.js +28 -0
  212. package/dist/esm/state/watch.js +36 -0
  213. package/dist/esm/styles/css-directive.js +36 -0
  214. package/dist/esm/styles/css.js +56 -0
  215. package/dist/esm/styles/element-styles.js +144 -0
  216. package/dist/esm/styles/host.js +1 -0
  217. package/dist/esm/styles/style-strategy.js +1 -0
  218. package/dist/esm/templating/children.js +67 -0
  219. package/dist/esm/templating/compiler.js +359 -0
  220. package/dist/esm/templating/html-binding-directive.js +288 -0
  221. package/dist/esm/templating/html-directive.js +113 -0
  222. package/dist/esm/templating/html.js +1 -0
  223. package/dist/esm/templating/hydration-view.js +228 -0
  224. package/dist/esm/templating/markup.js +83 -0
  225. package/dist/esm/templating/node-observation.js +84 -0
  226. package/dist/esm/templating/ref.js +21 -0
  227. package/dist/esm/templating/render.js +468 -0
  228. package/dist/esm/templating/repeat.js +434 -0
  229. package/dist/esm/templating/slotted.js +49 -0
  230. package/dist/esm/templating/template.js +206 -0
  231. package/dist/esm/templating/view.js +298 -0
  232. package/dist/esm/templating/when.js +22 -0
  233. package/dist/esm/testing/exports.js +3 -0
  234. package/dist/esm/testing/fakes.js +107 -0
  235. package/dist/esm/testing/fixture.js +86 -0
  236. package/dist/esm/testing/models.js +58 -0
  237. package/dist/esm/testing/timeout.js +24 -0
  238. package/dist/esm/trust/index.js +7 -0
  239. package/dist/esm/trust/types.js +6 -0
  240. package/dist/esm/trust/utils.js +126 -0
  241. package/dist/esm/utilities.js +140 -0
  242. package/dist/fast-element.api.json +26798 -0
  243. package/dist/fast-element.d.ts +3985 -0
  244. package/dist/fast-element.debug.js +7618 -0
  245. package/dist/fast-element.debug.min.js +3 -0
  246. package/dist/fast-element.js +7617 -0
  247. package/dist/fast-element.min.js +3 -0
  248. package/dist/fast-element.untrimmed.d.ts +4103 -0
  249. package/dist/observation/arrays/arrays.api.json +2621 -0
  250. package/dist/scoped/scoped.api.json +891 -0
  251. package/dist/trust/trust.api.json +629 -0
  252. package/migration/fast-html/rules/README.md +15 -0
  253. package/migration/fast-html/rules/attribute-directives.yml +38 -0
  254. package/migration/fast-html/rules/call-expression-with-event-argument.yml +41 -0
  255. package/migration/fast-html/rules/member-expression.yml +33 -0
  256. package/migration/fast-html/rules/tag-function-to-template-literal.yml +16 -0
  257. package/package.json +233 -3
@@ -0,0 +1,2 @@
1
+ export { ElementController } from "./element-controller.js";
2
+ export * from "./hydration.js";
@@ -0,0 +1,123 @@
1
+ import { installHydrationDiagnostic } from "../hydration/diagnostics.js";
2
+ import { ensureHydrationRuntime } from "../hydration/runtime.js";
3
+ import { SourceLifetime } from "../observation/observable.js";
4
+ import { ElementController } from "./element-controller.js";
5
+ import { isHydratable } from "./hydration.js";
6
+ import { HydrationTracker, } from "./hydration-tracker.js";
7
+ export { StopHydration } from "./hydration-tracker.js";
8
+ /**
9
+ * No-op handler used during prerendered bind to discard the
10
+ * upgrade-time burst of attributeChangedCallbacks.
11
+ */
12
+ function noopAttributeHandler() { }
13
+ let tracker = null;
14
+ let hookInstalled = false;
15
+ /**
16
+ * Enables hydration support for prerendered FAST elements.
17
+ *
18
+ * @remarks
19
+ * Call this before any FAST elements connect to the DOM. Hydration
20
+ * logic is not active unless this function is called, keeping
21
+ * `FASTElement` lightweight for client-side-only applications.
22
+ *
23
+ * Safe to call multiple times — the hydration hook is installed once
24
+ * and subsequent calls merge their options into the shared tracker.
25
+ * By default, the hook stops hydrating new prerendered elements after
26
+ * the initial hydration batch completes. Await the returned controller's
27
+ * `whenHydrated()` promise to run code after the active hydration batch
28
+ * completes.
29
+ *
30
+ * Set `stopHydration` to `StopHydration.never` for streaming scenarios
31
+ * that append hydratable Declarative Shadow DOM after the initial batch.
32
+ * In this mode, `whenHydrated` intentionally remains pending because
33
+ * hydration never reaches a global completion point.
34
+ *
35
+ * Pass `debugger: hydrationDebugger()` to swap the default minimal
36
+ * hydration mismatch error message for a rich "Expected / Received"
37
+ * report including the SSR HTML snippet and structured
38
+ * `expected`/`received` fields on `HydrationBindingError` /
39
+ * `HydrationTargetElementError`. The debugger module is tree-shaken
40
+ * out of production hydration bundles unless explicitly imported.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { enableHydration } from "@lushly-dev/fast-element/hydration.js";
45
+ *
46
+ * const hydration = enableHydration();
47
+ *
48
+ * await hydration.whenHydrated();
49
+ * console.log("hydration complete");
50
+ * ```
51
+ *
52
+ * @example Streaming Declarative Shadow DOM
53
+ * ```ts
54
+ * import { enableHydration, StopHydration } from "@lushly-dev/fast-element/hydration.js";
55
+ *
56
+ * enableHydration({
57
+ * stopHydration: StopHydration.never,
58
+ * });
59
+ * ```
60
+ *
61
+ * @example Rich hydration mismatch diagnostics
62
+ * ```ts
63
+ * import { enableHydration, hydrationDebugger } from "@lushly-dev/fast-element/hydration.js";
64
+ *
65
+ * enableHydration({ debugger: hydrationDebugger() });
66
+ * ```
67
+ *
68
+ * @param options - Optional hydration behavior.
69
+ * @public
70
+ */
71
+ export function enableHydration(options) {
72
+ ensureHydrationRuntime();
73
+ if (options === null || options === void 0 ? void 0 : options.debugger) {
74
+ installHydrationDiagnostic(options.debugger.diagnostic);
75
+ }
76
+ if (!hookInstalled) {
77
+ tracker = new HydrationTracker(options !== null && options !== void 0 ? options : {});
78
+ hookInstalled = true;
79
+ const activeTracker = tracker;
80
+ ElementController.installHydrationHook((controller, template, element, host) => {
81
+ if (!activeTracker.shouldHydrate || !isHydratable(template)) {
82
+ return false;
83
+ }
84
+ activeTracker.add(element);
85
+ try {
86
+ const firstChild = host.firstChild;
87
+ const lastChild = host.lastChild;
88
+ const view = template.hydrate(firstChild, lastChild, element);
89
+ controller.view = view;
90
+ const realHandler = controller.onAttributeChangedCallback;
91
+ controller.onAttributeChangedCallback = noopAttributeHandler;
92
+ try {
93
+ view._skipAttrUpdates = true;
94
+ view.isPrerendered = Promise.resolve(true);
95
+ view.isHydrated = Promise.resolve(true);
96
+ view.bind(controller.source);
97
+ view._skipAttrUpdates = false;
98
+ }
99
+ finally {
100
+ controller.onAttributeChangedCallback = realHandler;
101
+ }
102
+ view.sourceLifetime =
103
+ SourceLifetime.coupled;
104
+ controller.hasExistingShadowRoot = false;
105
+ }
106
+ finally {
107
+ activeTracker.remove(element);
108
+ }
109
+ return true;
110
+ });
111
+ }
112
+ else if (options && tracker) {
113
+ // Merge options into existing tracker for subsequent calls
114
+ tracker.mergeOptions(options);
115
+ }
116
+ return tracker;
117
+ }
118
+ /**
119
+ * The attribute used to defer hydration of an element.
120
+ * Retained for intersection observer viewport hydration rendering.
121
+ * @beta
122
+ */
123
+ export const deferHydrationAttribute = "defer-hydration";
@@ -0,0 +1,294 @@
1
+ import { isFunction, isString } from "../interfaces.js";
2
+ import { Observable } from "../observation/observable.js";
3
+ import { ElementStyles } from "../styles/element-styles.js";
4
+ import { AttributeDefinition } from "./attributes.js";
5
+ import { fastElementRegistry } from "./fast-element-registry.js";
6
+ const defaultShadowOptions = { mode: "open" };
7
+ const defaultElementOptions = {};
8
+ const fastElementBaseTypes = new Set();
9
+ function normalizeShadowOptions(options) {
10
+ if (options === null) {
11
+ return void 0;
12
+ }
13
+ const normalized = Object.assign(Object.assign({}, defaultShadowOptions), options);
14
+ if (normalized.customElementRegistry === void 0 && normalized.registry !== void 0) {
15
+ normalized.customElementRegistry = normalized.registry;
16
+ }
17
+ if (normalized.registry === void 0 && normalized.customElementRegistry !== void 0) {
18
+ normalized.registry = normalized.customElementRegistry;
19
+ }
20
+ return normalized;
21
+ }
22
+ const templateResolvers = new WeakMap();
23
+ const pendingTemplateResolutions = new WeakMap();
24
+ const templateResolutionErrors = new WeakMap();
25
+ const extensionRegistries = new WeakMap();
26
+ const registeredExtensions = new Set();
27
+ const lateAttributeLookups = new WeakMap();
28
+ function isFASTElementTemplateResolver(value) {
29
+ return isFunction(value);
30
+ }
31
+ function isPromiseLike(value) {
32
+ return typeof (value === null || value === void 0 ? void 0 : value.then) === "function";
33
+ }
34
+ function finalizeResolvedTemplate(definition, template) {
35
+ pendingTemplateResolutions.delete(definition);
36
+ if (definition.template === void 0 && template !== void 0) {
37
+ definition.template = template;
38
+ }
39
+ if (definition.template !== void 0) {
40
+ templateResolutionErrors.delete(definition);
41
+ templateResolvers.delete(definition);
42
+ return definition.template;
43
+ }
44
+ return void 0;
45
+ }
46
+ /**
47
+ * Applies extension callbacks to a FAST element definition.
48
+ * @internal
49
+ */
50
+ export function applyFASTElementExtensions(definition, registry = definition.registry, extensions) {
51
+ if (registeredExtensions.size === 0 && !(extensions === null || extensions === void 0 ? void 0 : extensions.length)) {
52
+ return;
53
+ }
54
+ const typedDefinition = definition;
55
+ let registries = extensionRegistries.get(typedDefinition);
56
+ if (registries === null || registries === void 0 ? void 0 : registries.has(registry)) {
57
+ return;
58
+ }
59
+ if (registries === void 0) {
60
+ registries = new WeakSet();
61
+ extensionRegistries.set(typedDefinition, registries);
62
+ }
63
+ registries.add(registry);
64
+ for (const extension of registeredExtensions) {
65
+ extension(definition, registry);
66
+ }
67
+ for (const extension of extensions !== null && extensions !== void 0 ? extensions : []) {
68
+ if (!registeredExtensions.has(extension)) {
69
+ extension(definition, registry);
70
+ }
71
+ }
72
+ }
73
+ /**
74
+ * Registers an extension that applies to every subsequently defined FAST element.
75
+ * @param extension - The extension to register.
76
+ * @returns A callback that removes the extension registration.
77
+ * @internal
78
+ */
79
+ export function registerFASTElementExtension(extension) {
80
+ registeredExtensions.add(extension);
81
+ return () => {
82
+ registeredExtensions.delete(extension);
83
+ };
84
+ }
85
+ /**
86
+ * Tracks attribute definitions that were added after the element was already
87
+ * registered with the platform and therefore are not covered by the browser's
88
+ * static observedAttributes snapshot.
89
+ * @internal
90
+ */
91
+ export function trackLateAttributeDefinition(definition, attribute) {
92
+ const typedDefinition = definition;
93
+ let lateAttributeLookup = lateAttributeLookups.get(typedDefinition);
94
+ if (lateAttributeLookup === void 0) {
95
+ const lookup = Object.create(null);
96
+ lateAttributeLookups.set(typedDefinition, lookup);
97
+ lateAttributeLookup = lookup;
98
+ }
99
+ lateAttributeLookup[attribute.attribute] = attribute;
100
+ }
101
+ /**
102
+ * Gets the attribute definitions that were added after platform registration.
103
+ * @internal
104
+ */
105
+ export function getLateAttributeLookup(definition) {
106
+ var _a;
107
+ return ((_a = lateAttributeLookups.get(definition)) !== null && _a !== void 0 ? _a : null);
108
+ }
109
+ /**
110
+ * Resolves the concrete template for a FAST element definition when the
111
+ * definition was composed with a template resolver.
112
+ * @internal
113
+ */
114
+ export function resolveFASTElementTemplate(definition) {
115
+ if (definition.template !== void 0) {
116
+ templateResolutionErrors.delete(definition);
117
+ return definition.template;
118
+ }
119
+ const pendingResolution = pendingTemplateResolutions.get(definition);
120
+ if (pendingResolution) {
121
+ return pendingResolution;
122
+ }
123
+ const templateResolver = templateResolvers.get(definition);
124
+ if (!templateResolver) {
125
+ return void 0;
126
+ }
127
+ templateResolutionErrors.delete(definition);
128
+ let template;
129
+ try {
130
+ template = templateResolver(definition);
131
+ }
132
+ catch (error) {
133
+ templateResolutionErrors.set(definition, error);
134
+ throw error;
135
+ }
136
+ if (isPromiseLike(template)) {
137
+ const resolution = Promise.resolve(template)
138
+ .then(resolvedTemplate => finalizeResolvedTemplate(definition, resolvedTemplate))
139
+ .catch(error => {
140
+ pendingTemplateResolutions.delete(definition);
141
+ templateResolutionErrors.set(definition, error);
142
+ throw error;
143
+ });
144
+ pendingTemplateResolutions.set(definition, resolution);
145
+ return resolution;
146
+ }
147
+ return finalizeResolvedTemplate(definition, template);
148
+ }
149
+ /**
150
+ * Indicates whether a definition still has a pending template resolver.
151
+ * @internal
152
+ */
153
+ export function hasFASTElementTemplateResolver(definition) {
154
+ return templateResolvers.has(definition);
155
+ }
156
+ /**
157
+ * Gets any pending template resolution error for a FAST element definition.
158
+ * @internal
159
+ */
160
+ export function getFASTElementTemplateError(definition) {
161
+ return templateResolutionErrors.get(definition);
162
+ }
163
+ /**
164
+ * Sets or clears the template resolution error for a FAST element definition.
165
+ * @internal
166
+ */
167
+ export function setFASTElementTemplateError(definition, error) {
168
+ const typedDefinition = definition;
169
+ if (error === void 0) {
170
+ templateResolutionErrors.delete(typedDefinition);
171
+ return;
172
+ }
173
+ templateResolutionErrors.set(typedDefinition, error);
174
+ }
175
+ /**
176
+ * Defines metadata for a FASTElement.
177
+ * @public
178
+ */
179
+ export class FASTElementDefinition {
180
+ /**
181
+ * Indicates if this element has been defined in at least one registry.
182
+ */
183
+ get isDefined() {
184
+ return this.platformDefined;
185
+ }
186
+ constructor(type, nameOrConfig = type
187
+ .definition) {
188
+ var _a;
189
+ this.platformDefined = false;
190
+ if (isString(nameOrConfig)) {
191
+ nameOrConfig = { name: nameOrConfig };
192
+ }
193
+ this.type = type;
194
+ this.name = nameOrConfig.name;
195
+ this.registry = (_a = nameOrConfig.registry) !== null && _a !== void 0 ? _a : customElements;
196
+ if (isFASTElementTemplateResolver(nameOrConfig.template)) {
197
+ templateResolvers.set(this, nameOrConfig.template);
198
+ }
199
+ else {
200
+ this.template = nameOrConfig.template;
201
+ }
202
+ const proto = type.prototype;
203
+ const attributes = AttributeDefinition.collect(type, nameOrConfig.attributes);
204
+ const observedAttributes = new Array(attributes.length);
205
+ const propertyLookup = {};
206
+ const attributeLookup = {};
207
+ for (let i = 0, ii = attributes.length; i < ii; ++i) {
208
+ const current = attributes[i];
209
+ observedAttributes[i] = current.attribute;
210
+ propertyLookup[current.name] = current;
211
+ attributeLookup[current.attribute] = current;
212
+ Observable.defineProperty(proto, current);
213
+ }
214
+ Reflect.defineProperty(type, "observedAttributes", {
215
+ value: observedAttributes,
216
+ enumerable: true,
217
+ });
218
+ this.attributes = attributes;
219
+ this.propertyLookup = propertyLookup;
220
+ this.attributeLookup = attributeLookup;
221
+ this.shadowOptions = normalizeShadowOptions(nameOrConfig.shadowOptions);
222
+ this.elementOptions =
223
+ nameOrConfig.elementOptions === void 0
224
+ ? defaultElementOptions
225
+ : Object.assign(Object.assign({}, defaultElementOptions), nameOrConfig.elementOptions);
226
+ this.styles = ElementStyles.normalize(nameOrConfig.styles);
227
+ this.schema = nameOrConfig.schema;
228
+ fastElementRegistry.register(this);
229
+ }
230
+ /**
231
+ * Defines a custom element based on this definition.
232
+ * @param registry - The element registry to define the element in.
233
+ * @param extensions - An optional array of extension callbacks to invoke
234
+ * with this definition before platform registration.
235
+ * @remarks
236
+ * This operation is idempotent per registry.
237
+ */
238
+ define(registry = this.registry, extensions) {
239
+ const type = this.type;
240
+ if (!registry.get(this.name)) {
241
+ applyFASTElementExtensions(this, registry, extensions);
242
+ if (this.template === void 0 && templateResolvers.has(this)) {
243
+ void Promise.resolve()
244
+ .then(() => resolveFASTElementTemplate(this))
245
+ .then(template => {
246
+ if (template !== void 0 && !registry.get(this.name)) {
247
+ this.platformDefined = true;
248
+ registry.define(this.name, type, this.elementOptions);
249
+ }
250
+ })
251
+ .catch(error => {
252
+ setFASTElementTemplateError(this, error);
253
+ Observable.notify(this, "template");
254
+ });
255
+ return this;
256
+ }
257
+ this.platformDefined = true;
258
+ registry.define(this.name, type, this.elementOptions);
259
+ }
260
+ return this;
261
+ }
262
+ /**
263
+ * Creates an instance of FASTElementDefinition.
264
+ * @param type - The type this definition is being created for.
265
+ * @param nameOrDef - The name of the element to define or a config object
266
+ * that describes the element to define.
267
+ */
268
+ static compose(type, nameOrDef) {
269
+ const definition = fastElementBaseTypes.has(type) || fastElementRegistry.getByType(type)
270
+ ? new FASTElementDefinition(class extends type {
271
+ }, nameOrDef)
272
+ : new FASTElementDefinition(type, nameOrDef);
273
+ return Promise.resolve(definition);
274
+ }
275
+ /**
276
+ * Registers a FASTElement base type.
277
+ * @param type - The type to register as a base type.
278
+ * @internal
279
+ */
280
+ static registerBaseType(type) {
281
+ fastElementBaseTypes.add(type);
282
+ }
283
+ }
284
+ /**
285
+ * Gets the element definition associated with the specified type.
286
+ * @param type - The custom element type to retrieve the definition for.
287
+ */
288
+ FASTElementDefinition.getByType = fastElementRegistry.getByType;
289
+ /**
290
+ * Gets the element definition associated with the instance.
291
+ * @param instance - The custom element instance to retrieve the definition for.
292
+ */
293
+ FASTElementDefinition.getForInstance = fastElementRegistry.getForInstance;
294
+ Observable.defineProperty(FASTElementDefinition.prototype, "template");
@@ -0,0 +1,67 @@
1
+ import { Observable } from "../observation/observable.js";
2
+ import { createTypeRegistry } from "../platform.js";
3
+ const globalRegisteredTypes = {};
4
+ const registeredTypesByRegistry = new WeakMap();
5
+ const typeRegistry = createTypeRegistry();
6
+ /**
7
+ * The FAST custom element registry.
8
+ * @remarks
9
+ * This registry stores FAST element definitions by constructor so consumers can
10
+ * look up the `FASTElementDefinition` associated with an element type, instance,
11
+ * or registered tag name.
12
+ * @public
13
+ */
14
+ export const fastElementRegistry = Object.freeze({
15
+ register(definition) {
16
+ if (!typeRegistry.register(definition)) {
17
+ return false;
18
+ }
19
+ const registeredTypes = getRegisteredTypes(definition.registry);
20
+ if (!Object.prototype.hasOwnProperty.call(registeredTypes, definition.name)) {
21
+ Observable.defineProperty(registeredTypes, definition.name);
22
+ }
23
+ registeredTypes[definition.name] = definition.type;
24
+ return true;
25
+ },
26
+ getByType: typeRegistry.getByType,
27
+ getForInstance: typeRegistry.getForInstance,
28
+ whenRegistered,
29
+ });
30
+ function getRegisteredTypes(registry = customElements) {
31
+ if (registry === customElements) {
32
+ return globalRegisteredTypes;
33
+ }
34
+ let registeredTypes = registeredTypesByRegistry.get(registry);
35
+ if (!registeredTypes) {
36
+ registeredTypes = {};
37
+ registeredTypesByRegistry.set(registry, registeredTypes);
38
+ }
39
+ return registeredTypes;
40
+ }
41
+ function getDefinitionForType(type) {
42
+ return type === void 0 ? void 0 : fastElementRegistry.getByType(type);
43
+ }
44
+ function whenRegistered(name, registry = customElements) {
45
+ const registeredTypes = getRegisteredTypes(registry);
46
+ if (!Object.prototype.hasOwnProperty.call(registeredTypes, name)) {
47
+ Observable.defineProperty(registeredTypes, name);
48
+ }
49
+ const definition = getDefinitionForType(registeredTypes[name]);
50
+ if (definition !== void 0) {
51
+ return Promise.resolve(definition);
52
+ }
53
+ return new Promise(resolve => {
54
+ const notifier = Observable.getNotifier(registeredTypes);
55
+ const subscriber = {
56
+ handleChange: () => {
57
+ const definition = getDefinitionForType(registeredTypes[name]);
58
+ if (definition === void 0) {
59
+ return;
60
+ }
61
+ notifier.unsubscribe(subscriber, name);
62
+ resolve(definition);
63
+ },
64
+ };
65
+ notifier.subscribe(subscriber, name);
66
+ });
67
+ }
@@ -0,0 +1,82 @@
1
+ import { isFunction } from "../interfaces.js";
2
+ import { ElementController } from "./element-controller.js";
3
+ import { applyFASTElementExtensions, FASTElementDefinition, resolveFASTElementTemplate, } from "./fast-definitions.js";
4
+ /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
5
+ function createFASTElement(BaseType) {
6
+ const type = class extends BaseType {
7
+ constructor() {
8
+ /* eslint-disable-next-line */
9
+ super();
10
+ ElementController.forCustomElement(this);
11
+ }
12
+ $emit(type, detail, options) {
13
+ return this.$fastController.emit(type, detail, options);
14
+ }
15
+ connectedCallback() {
16
+ this.$fastController.connect();
17
+ }
18
+ disconnectedCallback() {
19
+ this.$fastController.disconnect();
20
+ }
21
+ attributeChangedCallback(name, oldValue, newValue) {
22
+ this.$fastController.onAttributeChangedCallback(name, oldValue, newValue);
23
+ }
24
+ };
25
+ FASTElementDefinition.registerBaseType(type);
26
+ return type;
27
+ }
28
+ function isPromiseLike(value) {
29
+ return typeof (value === null || value === void 0 ? void 0 : value.then) === "function";
30
+ }
31
+ function define(type, nameOrDef, extensions) {
32
+ if (Array.isArray(nameOrDef)) {
33
+ extensions = nameOrDef;
34
+ nameOrDef = undefined;
35
+ }
36
+ const composePromise = isFunction(type)
37
+ ? FASTElementDefinition.compose(type, nameOrDef)
38
+ : FASTElementDefinition.compose(this, type);
39
+ return composePromise.then(def => {
40
+ applyFASTElementExtensions(def, def.registry, extensions);
41
+ const template = resolveFASTElementTemplate(def);
42
+ if (isPromiseLike(template)) {
43
+ return template.then(() => def.define().type);
44
+ }
45
+ return def.define().type;
46
+ });
47
+ }
48
+ function from(BaseType) {
49
+ return createFASTElement(BaseType);
50
+ }
51
+ /**
52
+ * A minimal base class for FASTElements that also provides
53
+ * static helpers for working with FASTElements.
54
+ * @public
55
+ */
56
+ export const FASTElement = Object.assign(createFASTElement(HTMLElement), {
57
+ /**
58
+ * Creates a new FASTElement base class inherited from the
59
+ * provided base type.
60
+ * @param BaseType - The base element type to inherit from.
61
+ */
62
+ from,
63
+ /**
64
+ * Defines a platform custom element based on the provided type and definition.
65
+ * @param type - The custom element type to define.
66
+ * @param nameOrDef - The name of the element to define or a definition object
67
+ * that describes the element to define.
68
+ */
69
+ define,
70
+ });
71
+ /**
72
+ * Decorator: Defines a platform custom element based on `FASTElement`.
73
+ * @param nameOrDef - The name of the element to define or a definition object
74
+ * that describes the element to define.
75
+ * @public
76
+ */
77
+ export function customElement(nameOrDef) {
78
+ /* eslint-disable-next-line @typescript-eslint/explicit-function-return-type */
79
+ return function (type) {
80
+ define(type, nameOrDef);
81
+ };
82
+ }