@microsoft/webui-framework 0.0.28 → 0.0.30
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.
- package/README.md +20 -2
- package/dist/decorators.js +42 -8
- package/dist/element/style-catalog.d.ts +33 -0
- package/dist/element/style-catalog.js +154 -0
- package/dist/element/styles.d.ts +2 -29
- package/dist/element/styles.js +4 -157
- package/dist/element.d.ts +12 -0
- package/dist/element.js +122 -1
- package/dist/lifecycle.js +4 -0
- package/dist/static-host.js +2 -1
- package/dist/streaming-bootstrap.js +2 -2
- package/dist/streaming-deferred.js +44 -15
- package/dist/streaming-install.js +3 -2
- package/dist/streaming-mode.d.ts +2 -1
- package/dist/streaming-mode.js +4 -1
- package/dist/streaming-template-hosts.d.ts +5 -0
- package/dist/streaming-template-hosts.js +39 -0
- package/dist/template-content.d.ts +1 -0
- package/dist/template-content.js +6 -2
- package/dist/template-element.d.ts +4 -2
- package/dist/template-element.js +66 -47
- package/dist/template-registry.d.ts +29 -0
- package/dist/template-registry.js +228 -0
- package/dist/template.d.ts +1 -25
- package/dist/template.js +4 -206
- package/dist/trusted-types-policy.d.ts +4 -0
- package/dist/trusted-types-policy.js +62 -0
- package/package.json +5 -5
package/dist/template-element.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { deferTemplateDefinition, getTemplate } from './template.js';
|
|
2
|
-
import { cloneTemplateContent, } from './template-content.js';
|
|
2
|
+
import { cloneTemplateContent, getTemplateFragment, } from './template-content.js';
|
|
3
3
|
import { hydrationStart, hydrationEnd } from './lifecycle.js';
|
|
4
|
-
import { ACTIVATION_ACTIVATED, ACTIVATION_ANCESTOR_BARRIER, ACTIVATION_MISSING_TEMPLATE, ACTIVATION_STATIC_HOST_OPT_OUT, isStreamingHydrationMode,
|
|
4
|
+
import { ACTIVATION_ACTIVATED, ACTIVATION_ANCESTOR_BARRIER, ACTIVATION_MISSING_TEMPLATE, ACTIVATION_STATIC_HOST_OPT_OUT, isStreamingHydrationMode, resumeStreamingRoot, STREAMED_HOST_ATTR, STREAMING_BOUNDARY_ACTIVATE, } from './streaming-mode.js';
|
|
5
5
|
import { createRepeatKeyState, seedHydratedRepeatKeys, syncRepeat, dotWalk, } from './element/diff.js';
|
|
6
6
|
import { collectItemMarkers, nextElement, findByOrdinal, buildSSRIndex, collectTemplateElements, MARKER_COND_START, MARKER_COND_END, rawMarker, } from './element/markers.js';
|
|
7
7
|
import { claimSsrComponentStyles, installComponentStyles, isComponentStyleMarker, } from './element/styles.js';
|
|
@@ -10,7 +10,6 @@ import { ATTR_KIND_BOOLEAN, ATTR_KIND_COMPLEX, ATTR_KIND_TEMPLATE, hasNativeLive
|
|
|
10
10
|
import { templateHasRoot, templateRootForAttribute } from './template-roots.js';
|
|
11
11
|
const DEV = typeof __WEBUI_DEV__ === 'undefined' || __WEBUI_DEV__;
|
|
12
12
|
const rootTagCache = new WeakMap();
|
|
13
|
-
const templateDOMCache = new WeakMap();
|
|
14
13
|
const tplOrdinalCache = new WeakMap();
|
|
15
14
|
const textMarkerBoundaryCache = new WeakMap();
|
|
16
15
|
const NO_TEXT_MARKER_BOUNDARIES = new Int32Array(0);
|
|
@@ -149,15 +148,6 @@ function childNodesArray(parent) {
|
|
|
149
148
|
result[i] = children[i];
|
|
150
149
|
return result;
|
|
151
150
|
}
|
|
152
|
-
function getTemplateDom(meta) {
|
|
153
|
-
let cached = templateDOMCache.get(meta);
|
|
154
|
-
if (cached)
|
|
155
|
-
return cached;
|
|
156
|
-
const div = document.createElement('div');
|
|
157
|
-
div.innerHTML = meta.h;
|
|
158
|
-
templateDOMCache.set(meta, div);
|
|
159
|
-
return div;
|
|
160
|
-
}
|
|
161
151
|
function installTemplateObservedAttributes(ctor, tagName, meta = getTemplate(tagName)) {
|
|
162
152
|
if (!meta)
|
|
163
153
|
return;
|
|
@@ -214,6 +204,8 @@ function hasAuthoredMember(instance, key) {
|
|
|
214
204
|
}
|
|
215
205
|
return false;
|
|
216
206
|
}
|
|
207
|
+
const MOUNTED = 1;
|
|
208
|
+
const HYDRATION_NOTIFIED = 2;
|
|
217
209
|
export class TemplateElement extends HTMLElement {
|
|
218
210
|
constructor() {
|
|
219
211
|
super(...arguments);
|
|
@@ -222,7 +214,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
222
214
|
this.$hydrated = false;
|
|
223
215
|
this.$deferredClientMount = false;
|
|
224
216
|
this.$resetClientShadow = false;
|
|
225
|
-
this.$
|
|
217
|
+
this.$mountPhase = 0;
|
|
226
218
|
this.$deferredSSR = false;
|
|
227
219
|
this.$activatingDeferredSSR = false;
|
|
228
220
|
this.$hasUnknownScopes = false;
|
|
@@ -295,11 +287,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
295
287
|
this.$hasAncestorBoundaryState = undefined;
|
|
296
288
|
}
|
|
297
289
|
$resumeRetainedRoot() {
|
|
298
|
-
|
|
299
|
-
if (typeof resume !== 'function')
|
|
300
|
-
return false;
|
|
301
|
-
resume.call(this);
|
|
302
|
-
return true;
|
|
290
|
+
return resumeStreamingRoot?.(this) ?? false;
|
|
303
291
|
}
|
|
304
292
|
static define(tagName) {
|
|
305
293
|
const ctor = this;
|
|
@@ -336,6 +324,8 @@ export class TemplateElement extends HTMLElement {
|
|
|
336
324
|
hydrationStart();
|
|
337
325
|
try {
|
|
338
326
|
this.$ready = true;
|
|
327
|
+
this.$syncAuthoredAttributes();
|
|
328
|
+
this.$notifyHydrated();
|
|
339
329
|
this.$update();
|
|
340
330
|
}
|
|
341
331
|
finally {
|
|
@@ -343,7 +333,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
343
333
|
}
|
|
344
334
|
return;
|
|
345
335
|
}
|
|
346
|
-
if (!this.$
|
|
336
|
+
if (!this.$mountPhase &&
|
|
347
337
|
isStreamingHydrationMode() &&
|
|
348
338
|
this.hasAttribute(STREAMED_HOST_ATTR)) {
|
|
349
339
|
this.$deferredSSR = true;
|
|
@@ -360,7 +350,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
360
350
|
return;
|
|
361
351
|
}
|
|
362
352
|
this.$meta = meta;
|
|
363
|
-
if (this.$
|
|
353
|
+
if (this.$mountPhase) {
|
|
364
354
|
this.$remount(meta);
|
|
365
355
|
}
|
|
366
356
|
else {
|
|
@@ -448,7 +438,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
448
438
|
this.$applyPendingParentState(isSSR);
|
|
449
439
|
}
|
|
450
440
|
if (isSSR) {
|
|
451
|
-
this.$root = this.$hydrate(root, meta,
|
|
441
|
+
this.$root = this.$hydrate(root, meta, getTemplateFragment(meta));
|
|
452
442
|
}
|
|
453
443
|
else {
|
|
454
444
|
clientRoot = this.$createStagingRoot(meta);
|
|
@@ -870,10 +860,14 @@ export class TemplateElement extends HTMLElement {
|
|
|
870
860
|
hydratedCallback() {
|
|
871
861
|
}
|
|
872
862
|
$notifyHydrated() {
|
|
873
|
-
if (this.$
|
|
863
|
+
if (!this.$mountPhase)
|
|
864
|
+
this.$mountPhase = MOUNTED;
|
|
865
|
+
if (!this.$reconcileAuthoredState())
|
|
874
866
|
return;
|
|
875
|
-
this.$
|
|
876
|
-
|
|
867
|
+
if (this.$mountPhase === MOUNTED) {
|
|
868
|
+
this.$mountPhase = HYDRATION_NOTIFIED;
|
|
869
|
+
this.hydratedCallback();
|
|
870
|
+
}
|
|
877
871
|
}
|
|
878
872
|
$finishHydration() {
|
|
879
873
|
let callbackFailed = false;
|
|
@@ -1045,40 +1039,65 @@ export class TemplateElement extends HTMLElement {
|
|
|
1045
1039
|
this.$flush(true);
|
|
1046
1040
|
}
|
|
1047
1041
|
$flushUpdates() {
|
|
1042
|
+
if (this.$mountPhase === MOUNTED)
|
|
1043
|
+
this.$notifyHydrated();
|
|
1048
1044
|
if (this.$pendingFlush)
|
|
1049
1045
|
this.$flush();
|
|
1050
1046
|
}
|
|
1047
|
+
$reconcileAuthoredState() {
|
|
1048
|
+
return true;
|
|
1049
|
+
}
|
|
1050
|
+
$canRunAuthoredEffects() {
|
|
1051
|
+
return this.$hydrated && this.$root !== null && this.$ready &&
|
|
1052
|
+
!this.$deferredClientMount && this.isConnected;
|
|
1053
|
+
}
|
|
1051
1054
|
$flush(requireKnownState = this.$guardUnknownState === true) {
|
|
1052
1055
|
if (!this.$ready || !this.$root) {
|
|
1053
1056
|
this.$dirtyPaths = null;
|
|
1054
1057
|
this.$pendingFlush = false;
|
|
1055
1058
|
return;
|
|
1056
1059
|
}
|
|
1057
|
-
|
|
1058
|
-
this.$
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1060
|
+
try {
|
|
1061
|
+
if (!this.$pathIndex)
|
|
1062
|
+
this.$buildPathIndex();
|
|
1063
|
+
if (!this.$pathIndex)
|
|
1064
|
+
return;
|
|
1065
|
+
while (this.$dirtyPaths && this.$dirtyPaths.size > 0) {
|
|
1066
|
+
const dirty = this.$dirtyPaths;
|
|
1067
|
+
this.$dirtyPaths = null;
|
|
1068
|
+
const paths = dirty.values();
|
|
1069
|
+
try {
|
|
1070
|
+
for (const path of paths) {
|
|
1071
|
+
if (!this.$pathIndex)
|
|
1072
|
+
this.$buildPathIndex();
|
|
1073
|
+
const entry = this.$pathIndex?.get(path);
|
|
1074
|
+
if (entry) {
|
|
1075
|
+
this.$updateBindings(entry.texts, entry.attrs, entry.conds, entry.repeats, requireKnownState);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
catch (error) {
|
|
1080
|
+
for (const path of paths)
|
|
1081
|
+
(this.$dirtyPaths ??= new Set()).add(path);
|
|
1082
|
+
throw error;
|
|
1083
|
+
}
|
|
1065
1084
|
if (!this.$pathIndex)
|
|
1066
1085
|
this.$buildPathIndex();
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
this.$updateBindings(
|
|
1086
|
+
if (this.$wildcardBindings) {
|
|
1087
|
+
const wc = this.$wildcardBindings;
|
|
1088
|
+
this.$updateBindings(wc.texts, wc.attrs, wc.conds, wc.repeats, requireKnownState);
|
|
1070
1089
|
}
|
|
1090
|
+
if (!this.$pathIndex)
|
|
1091
|
+
this.$buildPathIndex();
|
|
1071
1092
|
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
this.$
|
|
1093
|
+
}
|
|
1094
|
+
finally {
|
|
1095
|
+
this.$pendingFlush = false;
|
|
1096
|
+
if (this.$dirtyPaths?.size) {
|
|
1097
|
+
this.$pendingFlush = true;
|
|
1098
|
+
queueMicrotask(() => this.$flush());
|
|
1077
1099
|
}
|
|
1078
|
-
if (!this.$pathIndex)
|
|
1079
|
-
this.$buildPathIndex();
|
|
1080
1100
|
}
|
|
1081
|
-
this.$pendingFlush = false;
|
|
1082
1101
|
}
|
|
1083
1102
|
$recordPreReadyWrite(path) {
|
|
1084
1103
|
if (!this.$preReadyWrites)
|
|
@@ -1391,7 +1410,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1391
1410
|
const marker = repMarkers ? repMarkers[i] : null;
|
|
1392
1411
|
const ssrParent = (marker ? marker.parentNode : ssrElements[parentIndex]) ?? ssrRoot;
|
|
1393
1412
|
const blockMeta = this.$block(blockIndex);
|
|
1394
|
-
const blockTplDom = blockMeta ?
|
|
1413
|
+
const blockTplDom = blockMeta ? getTemplateFragment(blockMeta) : null;
|
|
1395
1414
|
const rootTag = blockMeta
|
|
1396
1415
|
&& blockTplDom?.childNodes.length === 1
|
|
1397
1416
|
&& blockTplDom.children.length === 1
|
|
@@ -1540,7 +1559,7 @@ export class TemplateElement extends HTMLElement {
|
|
|
1540
1559
|
}
|
|
1541
1560
|
$hydrateCondContent(condAnchor, blockMeta, scope) {
|
|
1542
1561
|
const rootTag = this.$rootTag(blockMeta);
|
|
1543
|
-
const tplDom =
|
|
1562
|
+
const tplDom = getTemplateFragment(blockMeta);
|
|
1544
1563
|
if (rootTag && tplDom.children.length === 1 && !this.$hasRootStructuralSlot(blockMeta)) {
|
|
1545
1564
|
const el = nextElement(condAnchor);
|
|
1546
1565
|
if (el) {
|
|
@@ -1871,11 +1890,11 @@ export class TemplateElement extends HTMLElement {
|
|
|
1871
1890
|
const range = document.createRange();
|
|
1872
1891
|
range.setStartAfter(b.node);
|
|
1873
1892
|
range.setEndBefore(b.rawEnd);
|
|
1893
|
+
const fragment = val !== '' ? range.createContextualFragment(val) : undefined;
|
|
1874
1894
|
range.deleteContents();
|
|
1875
1895
|
let rawNodes;
|
|
1876
1896
|
const rawOwner = b.rawOwner;
|
|
1877
|
-
if (
|
|
1878
|
-
const fragment = range.createContextualFragment(val);
|
|
1897
|
+
if (fragment) {
|
|
1879
1898
|
if (rawOwner && b.node.parentNode === rawOwner.container) {
|
|
1880
1899
|
rawNodes = childNodesArray(fragment);
|
|
1881
1900
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type { CompiledAttrGroupMeta, CompiledAttrMeta, CompiledAttrPart, CompiledCondition, CompiledConditionFn, CompiledConditionalMeta, CompiledEventArg, CompiledEventArgs, CompiledEventBindingMeta, CompiledEventGroupMeta, SerializedCompiledCondition, TemplateCondition, CompiledTextRunMeta, TemplateBlockMeta, TemplateMeta, TemplateNodeIndex, TemplateSlot, } from './template-types.js';
|
|
2
|
+
import { type ComponentStyles } from './element/style-catalog.js';
|
|
3
|
+
import type { CompiledConditionFn, TemplateMeta } from './template-types.js';
|
|
4
|
+
declare let prepareResources: ((templates: Record<string, TemplateMeta>) => Promise<void> | undefined) | undefined;
|
|
5
|
+
type DefinitionPreparation = (templates: Record<string, TemplateMeta>, names: readonly string[]) => Promise<void> | undefined;
|
|
6
|
+
export declare function installTemplateResourcePreparation(prepare: NonNullable<typeof prepareResources>): void;
|
|
7
|
+
export declare function installTemplateDefinitionPreparation(prepare: DefinitionPreparation | null): void;
|
|
8
|
+
declare global {
|
|
9
|
+
interface WebUIRuntimeGlobal {
|
|
10
|
+
state?: Record<string, unknown>;
|
|
11
|
+
templates?: Record<string, TemplateMeta>;
|
|
12
|
+
templateFns?: Record<string, CompiledConditionFn[]>;
|
|
13
|
+
componentAssetStyles?: Record<string, readonly string[]>;
|
|
14
|
+
templateHostExclusions?: Set<string>;
|
|
15
|
+
componentStyles?: ComponentStyles;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
interface Window {
|
|
19
|
+
__webui?: WebUIRuntimeGlobal;
|
|
20
|
+
__webuiRegisterComponentStyles?: (value: unknown) => Promise<void> | undefined;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export declare function getTemplate(name: string): TemplateMeta | undefined;
|
|
24
|
+
export declare function getTemplateRegistry(): Record<string, TemplateMeta> | undefined;
|
|
25
|
+
export declare function registerTemplateData(templates: Record<string, TemplateMeta>, templateFns?: Record<string, CompiledConditionFn[]>, componentStylesValue?: ComponentStyles | unknown): void;
|
|
26
|
+
export declare function prepareAssetTemplateData(templates: Record<string, TemplateMeta>, templateFns?: Record<string, CompiledConditionFn[]>): void;
|
|
27
|
+
export declare function deferTemplateDefinition(tagName: string, ctor: Function, define: () => void): void;
|
|
28
|
+
export declare function releaseSSRBootstrapState(): void;
|
|
29
|
+
export declare function releaseNonRoutedSSRBootstrapState(): void;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { dispatchTemplatesRegistered, templateRegistrationDetail, TEMPLATES_REGISTERED_EVENT, } from './template-events.js';
|
|
2
|
+
import { prepareComponentStyles, registerComponentStyles, registerPreparedComponentStyles, validateComponentStylesRegistration, } from './element/style-catalog.js';
|
|
3
|
+
import { registerTrustedTemplateBlock } from './trusted-types-policy.js';
|
|
4
|
+
const WEBUI_DATA_ID = 'webui-data';
|
|
5
|
+
const HYDRATION_COMPLETE_EVENT = 'webui:hydration-complete';
|
|
6
|
+
const TEMPLATE_FN_COUNT = Symbol.for('microsoft.webui.templateFnCount');
|
|
7
|
+
const normalizedTemplates = new WeakSet();
|
|
8
|
+
const assetNormalizedTemplates = new WeakSet();
|
|
9
|
+
let webuiDataLoaded = false;
|
|
10
|
+
function runtimeTemplateFnCount(registry) {
|
|
11
|
+
const count = registry[TEMPLATE_FN_COUNT];
|
|
12
|
+
if (typeof count === 'number')
|
|
13
|
+
return count;
|
|
14
|
+
const initialized = Object.keys(registry).length;
|
|
15
|
+
registry[TEMPLATE_FN_COUNT] = initialized;
|
|
16
|
+
return initialized;
|
|
17
|
+
}
|
|
18
|
+
const pendingTemplateDefinitions = new Map();
|
|
19
|
+
let prepareResources;
|
|
20
|
+
let prepareDefinitions;
|
|
21
|
+
export function installTemplateResourcePreparation(prepare) {
|
|
22
|
+
prepareResources = prepare;
|
|
23
|
+
}
|
|
24
|
+
export function installTemplateDefinitionPreparation(prepare) {
|
|
25
|
+
if (prepareDefinitions !== null)
|
|
26
|
+
prepareDefinitions = prepare;
|
|
27
|
+
}
|
|
28
|
+
function acceptTemplateData(templates, templateFns, componentStyles) {
|
|
29
|
+
validateComponentStylesRegistration(componentStyles);
|
|
30
|
+
prepareTemplateData(templates, templateFns);
|
|
31
|
+
if (componentStyles) {
|
|
32
|
+
registerPreparedComponentStyles(componentStyles);
|
|
33
|
+
}
|
|
34
|
+
const w = window;
|
|
35
|
+
if (!w.__webui)
|
|
36
|
+
w.__webui = {};
|
|
37
|
+
if (!w.__webui.templates)
|
|
38
|
+
w.__webui.templates = {};
|
|
39
|
+
const names = Object.keys(templates);
|
|
40
|
+
for (let i = 0; i < names.length; i++) {
|
|
41
|
+
const tag = names[i];
|
|
42
|
+
w.__webui.templates[tag] = templates[tag];
|
|
43
|
+
}
|
|
44
|
+
for (let i = 0; i < names.length; i++) {
|
|
45
|
+
const pending = pendingTemplateDefinitions.get(names[i]);
|
|
46
|
+
if (!pending)
|
|
47
|
+
continue;
|
|
48
|
+
pendingTemplateDefinitions.delete(names[i]);
|
|
49
|
+
pending.define();
|
|
50
|
+
}
|
|
51
|
+
return names;
|
|
52
|
+
}
|
|
53
|
+
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
54
|
+
if (window.__webui?.componentStyles) {
|
|
55
|
+
registerComponentStyles(window.__webui.componentStyles);
|
|
56
|
+
}
|
|
57
|
+
window.addEventListener(TEMPLATES_REGISTERED_EVENT, (event) => {
|
|
58
|
+
const detail = templateRegistrationDetail(event);
|
|
59
|
+
if (!detail?.templates)
|
|
60
|
+
return;
|
|
61
|
+
const styles = detail.componentStyles === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: prepareComponentStyles(detail.componentStyles);
|
|
64
|
+
const templates = detail.templates;
|
|
65
|
+
const names = acceptTemplateData(templates, undefined, styles);
|
|
66
|
+
const definitions = detail.waitUntil
|
|
67
|
+
? prepareDefinitions?.(templates, names)
|
|
68
|
+
: undefined;
|
|
69
|
+
if (definitions) {
|
|
70
|
+
detail.waitUntil?.(definitions.then(() => prepareResources?.(templates)));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const ready = prepareResources?.(templates);
|
|
74
|
+
if (ready)
|
|
75
|
+
detail.waitUntil?.(ready);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
window.addEventListener(HYDRATION_COMPLETE_EVENT, releaseNonRoutedSSRBootstrapState, { once: true });
|
|
79
|
+
}
|
|
80
|
+
export function getTemplate(name) {
|
|
81
|
+
let meta = window.__webui?.templates?.[name];
|
|
82
|
+
if (!meta) {
|
|
83
|
+
loadWebUIDataBlock();
|
|
84
|
+
meta = window.__webui?.templates?.[name];
|
|
85
|
+
}
|
|
86
|
+
if (meta)
|
|
87
|
+
normalizeTemplate(name, meta);
|
|
88
|
+
return meta;
|
|
89
|
+
}
|
|
90
|
+
export function getTemplateRegistry() {
|
|
91
|
+
loadWebUIDataBlock();
|
|
92
|
+
return window.__webui?.templates;
|
|
93
|
+
}
|
|
94
|
+
export function registerTemplateData(templates, templateFns, componentStylesValue) {
|
|
95
|
+
const componentStyles = prepareComponentStyles(componentStylesValue);
|
|
96
|
+
if (acceptTemplateData(templates, templateFns, componentStyles).length > 0) {
|
|
97
|
+
dispatchTemplatesRegistered(templates);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function prepareTemplateData(templates, templateFns) {
|
|
101
|
+
const names = Object.keys(templates);
|
|
102
|
+
for (let i = 0; i < names.length; i++) {
|
|
103
|
+
const name = names[i];
|
|
104
|
+
normalizeTemplate(name, templates[name], templateFns?.[name]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function prepareAssetTemplateData(templates, templateFns) {
|
|
108
|
+
const names = Object.keys(templates);
|
|
109
|
+
for (let i = 0; i < names.length; i++) {
|
|
110
|
+
const name = names[i];
|
|
111
|
+
const meta = templates[name];
|
|
112
|
+
if (assetNormalizedTemplates.has(meta))
|
|
113
|
+
continue;
|
|
114
|
+
normalizeTemplateConditions(name, meta, templateFns?.[name] ?? []);
|
|
115
|
+
normalizedTemplates.add(meta);
|
|
116
|
+
assetNormalizedTemplates.add(meta);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function deferTemplateDefinition(tagName, ctor, define) {
|
|
120
|
+
const pending = pendingTemplateDefinitions.get(tagName);
|
|
121
|
+
if (pending) {
|
|
122
|
+
if (pending.ctor === ctor) {
|
|
123
|
+
throw new Error(`[WebUI] <${tagName}> is already pending definition.`);
|
|
124
|
+
}
|
|
125
|
+
throw new Error(`[WebUI] <${tagName}> already has a pending authored definition.`);
|
|
126
|
+
}
|
|
127
|
+
pendingTemplateDefinitions.set(tagName, { ctor, define });
|
|
128
|
+
}
|
|
129
|
+
function loadWebUIDataBlock() {
|
|
130
|
+
if (webuiDataLoaded || window.__webui?.state !== undefined || typeof document === 'undefined')
|
|
131
|
+
return;
|
|
132
|
+
const el = document.getElementById(WEBUI_DATA_ID);
|
|
133
|
+
if (!el) {
|
|
134
|
+
webuiDataLoaded = true;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const text = el.textContent;
|
|
138
|
+
if (text) {
|
|
139
|
+
const templateFns = window.__webui?.templateFns;
|
|
140
|
+
const componentAssetStyles = window.__webui?.componentAssetStyles;
|
|
141
|
+
const parsed = JSON.parse(text);
|
|
142
|
+
if (templateFns)
|
|
143
|
+
parsed.templateFns = templateFns;
|
|
144
|
+
if (componentAssetStyles)
|
|
145
|
+
parsed.componentAssetStyles = componentAssetStyles;
|
|
146
|
+
window.__webui = parsed;
|
|
147
|
+
el.remove();
|
|
148
|
+
webuiDataLoaded = true;
|
|
149
|
+
if (parsed.componentStyles !== undefined) {
|
|
150
|
+
registerComponentStyles(parsed.componentStyles);
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
el.remove();
|
|
155
|
+
webuiDataLoaded = true;
|
|
156
|
+
}
|
|
157
|
+
export function releaseSSRBootstrapState() {
|
|
158
|
+
const runtime = window.__webui;
|
|
159
|
+
if (runtime?.state !== undefined) {
|
|
160
|
+
delete runtime.state;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export function releaseNonRoutedSSRBootstrapState() {
|
|
164
|
+
const runtime = window.__webui;
|
|
165
|
+
if (runtime?.chain === undefined &&
|
|
166
|
+
runtime?.templateHostExclusions === undefined) {
|
|
167
|
+
releaseSSRBootstrapState();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
function normalizeTemplate(name, meta, suppliedFns) {
|
|
171
|
+
if (normalizedTemplates.has(meta))
|
|
172
|
+
return;
|
|
173
|
+
const runtimeFns = window.__webui?.templateFns;
|
|
174
|
+
const fns = suppliedFns ?? runtimeFns?.[name] ?? [];
|
|
175
|
+
normalizeTemplateConditions(name, meta, fns);
|
|
176
|
+
normalizedTemplates.add(meta);
|
|
177
|
+
if (suppliedFns === undefined && runtimeFns?.[name] === fns) {
|
|
178
|
+
let remaining = runtimeTemplateFnCount(runtimeFns);
|
|
179
|
+
delete runtimeFns[name];
|
|
180
|
+
remaining--;
|
|
181
|
+
runtimeFns[TEMPLATE_FN_COUNT] = remaining;
|
|
182
|
+
if (remaining === 0 && window.__webui) {
|
|
183
|
+
const liveCount = Object.keys(runtimeFns).length;
|
|
184
|
+
if (liveCount === 0) {
|
|
185
|
+
delete window.__webui.templateFns;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
runtimeFns[TEMPLATE_FN_COUNT] = liveCount;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function normalizeTemplateConditions(name, meta, fns) {
|
|
194
|
+
const stack = [meta];
|
|
195
|
+
while (stack.length > 0) {
|
|
196
|
+
const block = stack.pop();
|
|
197
|
+
if (!block)
|
|
198
|
+
continue;
|
|
199
|
+
registerTrustedTemplateBlock(block);
|
|
200
|
+
if (block.a) {
|
|
201
|
+
for (let i = 0; i < block.a.length; i++) {
|
|
202
|
+
const attr = block.a[i];
|
|
203
|
+
if (attr[1] === 2)
|
|
204
|
+
normalizeCondition(name, attr[2], fns);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (block.c) {
|
|
208
|
+
for (let i = 0; i < block.c.length; i++) {
|
|
209
|
+
normalizeCondition(name, block.c[i][0], fns);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const children = block.b;
|
|
213
|
+
if (children) {
|
|
214
|
+
for (let i = 0; i < children.length; i++)
|
|
215
|
+
stack.push(children[i]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function normalizeCondition(tagName, condition, fns) {
|
|
220
|
+
const first = condition[0];
|
|
221
|
+
if (typeof first === 'function')
|
|
222
|
+
return;
|
|
223
|
+
const fn = fns[first];
|
|
224
|
+
if (typeof fn !== 'function') {
|
|
225
|
+
throw new Error(`[WebUI] Missing condition closure ${first} for <${tagName}>.`);
|
|
226
|
+
}
|
|
227
|
+
condition[0] = fn;
|
|
228
|
+
}
|
package/dist/template.d.ts
CHANGED
|
@@ -1,25 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
import { type ComponentStyles } from './element/styles.js';
|
|
3
|
-
import type { CompiledConditionFn, TemplateMeta } from './template-types.js';
|
|
4
|
-
declare global {
|
|
5
|
-
interface WebUIRuntimeGlobal {
|
|
6
|
-
state?: Record<string, unknown>;
|
|
7
|
-
templates?: Record<string, TemplateMeta>;
|
|
8
|
-
templateFns?: Record<string, CompiledConditionFn[]>;
|
|
9
|
-
componentAssetStyles?: Record<string, readonly string[]>;
|
|
10
|
-
templateHostExclusions?: Set<string>;
|
|
11
|
-
componentStyles?: ComponentStyles;
|
|
12
|
-
[key: string]: unknown;
|
|
13
|
-
}
|
|
14
|
-
interface Window {
|
|
15
|
-
__webui?: WebUIRuntimeGlobal;
|
|
16
|
-
__webuiRegisterComponentStyles?: (value: unknown) => Promise<void> | undefined;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export declare function getTemplate(name: string): TemplateMeta | undefined;
|
|
20
|
-
export declare function getTemplateRegistry(): Record<string, TemplateMeta> | undefined;
|
|
21
|
-
export declare function registerTemplateData(templates: Record<string, TemplateMeta>, templateFns?: Record<string, CompiledConditionFn[]>, componentStylesValue?: ComponentStyles | unknown): void;
|
|
22
|
-
export declare function prepareAssetTemplateData(templates: Record<string, TemplateMeta>, templateFns?: Record<string, CompiledConditionFn[]>): void;
|
|
23
|
-
export declare function deferTemplateDefinition(tagName: string, ctor: Function, define: () => void): void;
|
|
24
|
-
export declare function releaseSSRBootstrapState(): void;
|
|
25
|
-
export declare function releaseNonRoutedSSRBootstrapState(): void;
|
|
1
|
+
export * from './template-registry.js';
|