@microsoft/webui-framework 0.0.24 → 0.0.26
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 +209 -53
- package/dist/component-asset/asset.d.ts +4 -2
- package/dist/component-asset/asset.js +19 -3
- package/dist/component-asset/generated-manifest.d.ts +1 -0
- package/dist/component-asset/generated-manifest.js +32 -0
- package/dist/component-asset/loader.d.ts +2 -1
- package/dist/component-asset/loader.js +98 -22
- package/dist/component-asset/manifest.d.ts +2 -1
- package/dist/component-asset.d.ts +1 -1
- package/dist/component-asset.js +12 -2
- package/dist/element/link-styles.d.ts +20 -0
- package/dist/element/link-styles.js +1030 -0
- package/dist/element/markers.d.ts +4 -0
- package/dist/element/markers.js +60 -5
- package/dist/element/styles.d.ts +39 -1
- package/dist/element/styles.js +623 -13
- package/dist/element/types.d.ts +5 -3
- package/dist/element.js +9 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/interaction-hydration.d.ts +8 -0
- package/dist/interaction-hydration.js +167 -0
- package/dist/static-host.js +43 -1
- package/dist/streaming-activation.d.ts +2 -2
- package/dist/streaming-activation.js +4 -2
- package/dist/streaming-bootstrap.d.ts +2 -2
- package/dist/streaming-bootstrap.js +7 -1
- package/dist/streaming-cleanup.d.ts +1 -0
- package/dist/streaming-cleanup.js +66 -14
- package/dist/streaming-coordinator.d.ts +3 -2
- package/dist/streaming-coordinator.js +107 -47
- package/dist/streaming-deferred.d.ts +14 -4
- package/dist/streaming-deferred.js +200 -87
- package/dist/streaming-dom.d.ts +12 -3
- package/dist/streaming-dom.js +41 -27
- package/dist/streaming-mode.d.ts +5 -0
- package/dist/streaming-mode.js +4 -0
- package/dist/streaming-protocol.d.ts +19 -3
- package/dist/streaming-protocol.js +4 -3
- package/dist/streaming-spans.d.ts +9 -0
- package/dist/streaming-spans.js +200 -0
- package/dist/template-content.d.ts +17 -0
- package/dist/template-content.js +106 -0
- package/dist/template-element.d.ts +17 -2
- package/dist/template-element.js +493 -177
- package/dist/template-events.d.ts +7 -0
- package/dist/template-events.js +7 -1
- package/dist/template-types.d.ts +1 -2
- package/dist/template.d.ts +15 -8
- package/dist/template.js +79 -16
- package/package.json +9 -3
- package/dist/component-asset/resources.d.ts +0 -4
- package/dist/component-asset/resources.js +0 -83
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { getTemplate, prepareAssetTemplateData, registerTemplateData, } from '../template.js';
|
|
2
|
-
import { readComponentAssetModule, sameComponents, validateAsset, } from './asset.js';
|
|
3
|
-
import {
|
|
2
|
+
import { prepareAssetComponentStyles, readComponentAssetModule, sameComponents, validateAsset, } from './asset.js';
|
|
3
|
+
import { hasRegisteredComponentStyleResource, registerPreparedComponentStyles, sameComponentStyleClosure, sameComponentStyleResource, validateComponentStylesRegistration, } from '../element/styles.js';
|
|
4
|
+
import { prepareComponentStyleLinks, prepareRegisteredLinkStyles, } from '../element/link-styles.js';
|
|
4
5
|
const assetModulePromises = new Map();
|
|
5
|
-
export function loadComponentAsset(tag,
|
|
6
|
-
|
|
6
|
+
export function loadComponentAsset(tag, source) {
|
|
7
|
+
if (typeof source === 'function') {
|
|
8
|
+
return Promise.resolve()
|
|
9
|
+
.then(source)
|
|
10
|
+
.then(imported => registerRootAsset(tag, `component asset loader for <${tag}>`, imported));
|
|
11
|
+
}
|
|
12
|
+
const assetUrl = new URL(source, document.baseURI);
|
|
7
13
|
const href = assetUrl.href;
|
|
8
14
|
return loadAssetModule(href, () => import(assetUrl.href))
|
|
9
15
|
.then(imported => registerRootAsset(tag, href, imported));
|
|
@@ -17,10 +23,27 @@ async function registerRootAsset(expectedRoot, href, imported) {
|
|
|
17
23
|
validateExternalComponents(asset);
|
|
18
24
|
const root = prepareComponentPayload(asset);
|
|
19
25
|
const chunks = await prepareAssetImports(asset.imports);
|
|
26
|
+
const graph = [...chunks, root];
|
|
27
|
+
validatePreparedGraph(graph);
|
|
28
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
29
|
+
registerComponentResources(chunks[i]);
|
|
30
|
+
}
|
|
31
|
+
registerComponentResources(root);
|
|
32
|
+
let pendingStyles;
|
|
20
33
|
for (let i = 0; i < chunks.length; i++) {
|
|
21
|
-
|
|
34
|
+
const ready = chunks[i].linkStyles;
|
|
35
|
+
if (!ready)
|
|
36
|
+
continue;
|
|
37
|
+
(pendingStyles ??= []).push(ready);
|
|
22
38
|
}
|
|
23
|
-
|
|
39
|
+
if (root.linkStyles)
|
|
40
|
+
(pendingStyles ??= []).push(root.linkStyles);
|
|
41
|
+
if (pendingStyles)
|
|
42
|
+
await Promise.all(pendingStyles);
|
|
43
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
44
|
+
registerComponentTemplates(chunks[i]);
|
|
45
|
+
}
|
|
46
|
+
registerComponentTemplates(root);
|
|
24
47
|
}
|
|
25
48
|
function loadAssetModule(href, load) {
|
|
26
49
|
let promise = assetModulePromises.get(href);
|
|
@@ -57,19 +80,83 @@ function importAndPrepareChunk(assetImport) {
|
|
|
57
80
|
});
|
|
58
81
|
}
|
|
59
82
|
function prepareComponentPayload(asset) {
|
|
83
|
+
const componentStyles = prepareAssetComponentStyles(asset.componentStyles);
|
|
60
84
|
prepareAssetTemplateData(asset.templates, asset.templateFunctions);
|
|
85
|
+
const templateLinkStyles = prepareRegisteredLinkStyles(asset.templates);
|
|
86
|
+
const componentStyleLinks = prepareComponentStyleLinks(componentStyles);
|
|
87
|
+
let linkStyles = templateLinkStyles;
|
|
88
|
+
if (templateLinkStyles && componentStyleLinks) {
|
|
89
|
+
linkStyles = Promise.all([templateLinkStyles, componentStyleLinks]).then(() => { });
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
linkStyles = templateLinkStyles ?? componentStyleLinks;
|
|
93
|
+
}
|
|
61
94
|
return {
|
|
62
95
|
asset,
|
|
63
|
-
|
|
96
|
+
componentStyles,
|
|
97
|
+
linkStyles,
|
|
64
98
|
};
|
|
65
99
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
100
|
+
function registerComponentResources(prepared) {
|
|
101
|
+
registerPreparedComponentStyles(prepared.componentStyles);
|
|
102
|
+
}
|
|
103
|
+
function registerComponentTemplates(prepared) {
|
|
104
|
+
const { asset } = prepared;
|
|
68
105
|
if (componentsAlreadyRegistered(asset.components))
|
|
69
106
|
return;
|
|
70
|
-
registerAssetStyles(styles, readNonce());
|
|
71
107
|
registerTemplateData(asset.templates, asset.templateFunctions);
|
|
72
|
-
|
|
108
|
+
}
|
|
109
|
+
function validatePreparedGraph(graph) {
|
|
110
|
+
const resources = new Map();
|
|
111
|
+
const closures = new Map();
|
|
112
|
+
const provided = new Set();
|
|
113
|
+
for (let i = 0; i < graph.length; i++) {
|
|
114
|
+
const prepared = graph[i];
|
|
115
|
+
validateComponentStylesRegistration(prepared.componentStyles);
|
|
116
|
+
for (const component of prepared.asset.components)
|
|
117
|
+
provided.add(component);
|
|
118
|
+
const styles = prepared.componentStyles;
|
|
119
|
+
for (const id of Object.keys(styles.resources)) {
|
|
120
|
+
const resource = styles.resources[id];
|
|
121
|
+
const current = resources.get(id);
|
|
122
|
+
if (current && !sameComponentStyleResource(current, resource)) {
|
|
123
|
+
throw new Error(`[WebUI] Conflicting component style resource "${id}".`);
|
|
124
|
+
}
|
|
125
|
+
resources.set(id, resource);
|
|
126
|
+
}
|
|
127
|
+
for (const root of Object.keys(styles.closures)) {
|
|
128
|
+
const closure = styles.closures[root];
|
|
129
|
+
const current = closures.get(root);
|
|
130
|
+
if (current && !sameComponentStyleClosure(current, closure)) {
|
|
131
|
+
throw new Error(`[WebUI] Conflicting component style closure "${root}".`);
|
|
132
|
+
}
|
|
133
|
+
closures.set(root, closure);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
for (let i = 0; i < graph.length; i++) {
|
|
137
|
+
const styles = graph[i].componentStyles;
|
|
138
|
+
for (const root of Object.keys(styles.closures)) {
|
|
139
|
+
for (const id of styles.closures[root]) {
|
|
140
|
+
if (!resources.has(id) &&
|
|
141
|
+
!hasRegisteredComponentStyleResource(id)) {
|
|
142
|
+
throw new Error(`[WebUI] Component style closure "${root}" references missing resource "${id}".`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const missing = [];
|
|
148
|
+
for (let i = 0; i < graph.length; i++) {
|
|
149
|
+
const asset = graph[i].asset;
|
|
150
|
+
for (const required of asset.requiredComponents) {
|
|
151
|
+
if (provided.has(required) || getTemplate(required))
|
|
152
|
+
continue;
|
|
153
|
+
if (missing.indexOf(required) < 0)
|
|
154
|
+
missing.push(required);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (missing.length === 0)
|
|
158
|
+
return;
|
|
159
|
+
throw new Error(`[WebUI] Component asset is missing required templ${missing.length === 1 ? 'ate' : 'ates'} ${missing.map(tag => `<${tag}>`).join(', ')}. Load the application entry bundle and protocol before deferred component assets.`);
|
|
73
160
|
}
|
|
74
161
|
function componentsAlreadyRegistered(components) {
|
|
75
162
|
if (components.length === 0)
|
|
@@ -91,14 +178,3 @@ function validateExternalComponents(asset) {
|
|
|
91
178
|
return;
|
|
92
179
|
throw new Error(`[WebUI] Component asset requires entr${missing.length === 1 ? 'y template' : 'y templates'} ${missing.map(tag => `<${tag}>`).join(', ')}. Load the application entry bundle and protocol before deferred component assets.`);
|
|
93
180
|
}
|
|
94
|
-
function validateRequiredComponents(asset) {
|
|
95
|
-
const missing = [];
|
|
96
|
-
for (let i = 0; i < asset.requiredComponents.length; i++) {
|
|
97
|
-
const component = asset.requiredComponents[i];
|
|
98
|
-
if (!getTemplate(component))
|
|
99
|
-
missing.push(component);
|
|
100
|
-
}
|
|
101
|
-
if (missing.length === 0)
|
|
102
|
-
return;
|
|
103
|
-
throw new Error(`[WebUI] Component asset is missing required template${missing.length === 1 ? '' : 's'}: ${missing.map(tag => `<${tag}>`).join(', ')}. Ensure the application entry bundle and protocol are loaded before deferred component assets.`);
|
|
104
|
-
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export type ComponentAssetState = Record<string, unknown>;
|
|
2
|
+
export type ComponentAssetSource = string | URL | (() => Promise<unknown>);
|
|
2
3
|
export interface ComponentAssetManifestEntry<Data extends ComponentAssetState = ComponentAssetState> {
|
|
3
|
-
asset:
|
|
4
|
+
asset: ComponentAssetSource;
|
|
4
5
|
module?: () => Promise<unknown>;
|
|
5
6
|
data?: () => Promise<Data>;
|
|
6
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ComponentAssetManifest, ComponentAssetRegistry } from './component-asset/manifest.js';
|
|
2
2
|
export type { ComponentAsset, ComponentAssetImport, } from './component-asset/asset.js';
|
|
3
|
-
export type { ComponentAssetCreateOptions, ComponentAssetManifest, ComponentAssetManifestEntry, ComponentAssetPreload, ComponentAssetRegistry, ComponentAssetState, } from './component-asset/manifest.js';
|
|
3
|
+
export type { ComponentAssetCreateOptions, ComponentAssetManifest, ComponentAssetManifestEntry, ComponentAssetPreload, ComponentAssetRegistry, ComponentAssetSource, ComponentAssetState, } from './component-asset/manifest.js';
|
|
4
4
|
export declare function defineComponentAssets(manifest: ComponentAssetManifest): ComponentAssetRegistry;
|
package/dist/component-asset.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { loadComponentAsset } from './component-asset/loader.js';
|
|
2
|
+
import { takeGeneratedComponentAssetStyles } from './component-asset/generated-manifest.js';
|
|
3
|
+
import { preloadComponentAssetStyles } from './element/link-styles.js';
|
|
2
4
|
export function defineComponentAssets(manifest) {
|
|
3
5
|
const preloads = new Map();
|
|
4
6
|
function preload(tag) {
|
|
@@ -9,6 +11,10 @@ export function defineComponentAssets(manifest) {
|
|
|
9
11
|
if (!entry) {
|
|
10
12
|
throw new Error(`[WebUI] No component asset manifest entry for <${tag}>.`);
|
|
11
13
|
}
|
|
14
|
+
const styles = takeGeneratedComponentAssetStyles(tag);
|
|
15
|
+
if (styles) {
|
|
16
|
+
preloadComponentAssetStyles(styles);
|
|
17
|
+
}
|
|
12
18
|
const next = {
|
|
13
19
|
asset: loadComponentAsset(tag, entry.asset),
|
|
14
20
|
};
|
|
@@ -18,8 +24,12 @@ export function defineComponentAssets(manifest) {
|
|
|
18
24
|
if (entry.data) {
|
|
19
25
|
next.data = entry.data();
|
|
20
26
|
}
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
const evictFailedResources = () => {
|
|
28
|
+
if (preloads.get(tag) === next)
|
|
29
|
+
preloads.delete(tag);
|
|
30
|
+
};
|
|
31
|
+
next.asset.catch(evictFailedResources);
|
|
32
|
+
next.module?.catch(evictFailedResources);
|
|
23
33
|
next.data?.catch(() => { });
|
|
24
34
|
preloads.set(tag, next);
|
|
25
35
|
return next;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { TemplateBlockMeta, TemplateMeta } from '../template-types.js';
|
|
2
|
+
import type { ComponentStyles } from './styles.js';
|
|
3
|
+
interface ElementBinding {
|
|
4
|
+
readonly element: Element;
|
|
5
|
+
}
|
|
6
|
+
interface DeferredContentCallbacks {
|
|
7
|
+
readonly afterAppend?: () => void;
|
|
8
|
+
readonly beforeAppend?: () => void;
|
|
9
|
+
readonly hasAuthorHydrationLifecycle?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function prepareTemplateLinkStyles(meta: TemplateBlockMeta): Promise<void> | undefined;
|
|
12
|
+
export declare function prepareRegisteredLinkStyles(templates: Record<string, TemplateMeta>): Promise<void> | undefined;
|
|
13
|
+
export declare function prepareComponentStyleLinks(styles: ComponentStyles): Promise<void> | undefined;
|
|
14
|
+
export declare function preloadComponentAssetStyles(hrefs: readonly string[]): Promise<void> | undefined;
|
|
15
|
+
export declare function installComponentLinkStyles(host: HTMLElement, root: ShadowRoot, links: readonly HTMLLinkElement[]): void;
|
|
16
|
+
export declare function templateMayContainLinkStyles(meta: TemplateBlockMeta): boolean;
|
|
17
|
+
export declare function installTemplateLinkStyles(host: HTMLElement, meta: TemplateMeta, shadowRoot: ShadowRoot | null, stagingRoot: ParentNode, bindings: readonly ElementBinding[], deferredCallbacks?: DeferredContentCallbacks): boolean;
|
|
18
|
+
export declare function cancelTemplateLinkStyleMount(root: ShadowRoot): boolean;
|
|
19
|
+
export declare function rewriteCssUrls(cssText: string, stylesheetHref: string): string | undefined;
|
|
20
|
+
export {};
|