@vmz/core 0.1.20 → 0.1.21
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/dist/direct-host-box.d.ts +26 -0
- package/dist/direct-host-box.js +41 -0
- package/dist/dom-core.d.ts +2 -0
- package/dist/dom-core.js +15 -16
- package/dist/dom-ssr.js +15 -9
- package/dist/unknown-component.d.ts +40 -0
- package/dist/unknown-component.js +112 -0
- package/package.json +7 -7
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct host box model (`ui-direct-host-box`).
|
|
3
|
+
* Chip hosts opt into `display: contents`; block surfaces keep a real layout box.
|
|
4
|
+
*/
|
|
5
|
+
/** @type {ReadonlySet<string>} */
|
|
6
|
+
export declare const INLINE_HOST_CONTENTS: Set<string>;
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} name
|
|
9
|
+
* @param {{ __vmzHostBox?: string } | null | undefined} Ctor
|
|
10
|
+
* @returns {'contents' | 'block'}
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveDirectHostBox(name: any, Ctor: any): any;
|
|
13
|
+
/**
|
|
14
|
+
* Apply host box to a live DOM element (create / hydrate / resume).
|
|
15
|
+
* @param {HTMLElement} host
|
|
16
|
+
* @param {string} name
|
|
17
|
+
* @param {{ __vmzHostBox?: string } | null | undefined} Ctor
|
|
18
|
+
*/
|
|
19
|
+
export declare function applyDirectHostBox(host: any, name: any, Ctor: any): void;
|
|
20
|
+
/**
|
|
21
|
+
* SSR attrs fragment for host box (only when contents).
|
|
22
|
+
* @param {string} name
|
|
23
|
+
* @param {{ __vmzHostBox?: string } | null | undefined} Ctor
|
|
24
|
+
* @returns {string | null}
|
|
25
|
+
*/
|
|
26
|
+
export declare function directHostBoxStyleAttr(name: any, Ctor: any): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Direct host box model (`ui-direct-host-box`).
|
|
3
|
+
* Chip hosts opt into `display: contents`; block surfaces keep a real layout box.
|
|
4
|
+
*/
|
|
5
|
+
/** @type {ReadonlySet<string>} */
|
|
6
|
+
export const INLINE_HOST_CONTENTS = new Set(['Button', 'Badge', 'Link', 'Tag', 'Icon']);
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} name
|
|
9
|
+
* @param {{ __vmzHostBox?: string } | null | undefined} Ctor
|
|
10
|
+
* @returns {'contents' | 'block'}
|
|
11
|
+
*/
|
|
12
|
+
export function resolveDirectHostBox(name, Ctor) {
|
|
13
|
+
const explicit = Ctor && typeof Ctor.__vmzHostBox === 'string' ? Ctor.__vmzHostBox : null;
|
|
14
|
+
if (explicit === 'contents' || explicit === 'block')
|
|
15
|
+
return explicit;
|
|
16
|
+
if (INLINE_HOST_CONTENTS.has(String(name || '')))
|
|
17
|
+
return 'contents';
|
|
18
|
+
return 'block';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Apply host box to a live DOM element (create / hydrate / resume).
|
|
22
|
+
* @param {HTMLElement} host
|
|
23
|
+
* @param {string} name
|
|
24
|
+
* @param {{ __vmzHostBox?: string } | null | undefined} Ctor
|
|
25
|
+
*/
|
|
26
|
+
export function applyDirectHostBox(host, name, Ctor) {
|
|
27
|
+
if (!host || !host.style)
|
|
28
|
+
return;
|
|
29
|
+
if (resolveDirectHostBox(name, Ctor) === 'contents') {
|
|
30
|
+
host.style.display = 'contents';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* SSR attrs fragment for host box (only when contents).
|
|
35
|
+
* @param {string} name
|
|
36
|
+
* @param {{ __vmzHostBox?: string } | null | undefined} Ctor
|
|
37
|
+
* @returns {string | null}
|
|
38
|
+
*/
|
|
39
|
+
export function directHostBoxStyleAttr(name, Ctor) {
|
|
40
|
+
return resolveDirectHostBox(name, Ctor) === 'contents' ? 'display:contents' : null;
|
|
41
|
+
}
|
package/dist/dom-core.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* Mount and client patches run that same schedule (SSR/hydrate/resume in dom-ssr).
|
|
7
7
|
* Field writes only run registered dep patches — never re-create structure.
|
|
8
8
|
*/
|
|
9
|
+
export { applyDirectHostBox, INLINE_HOST_CONTENTS, resolveDirectHostBox } from './direct-host-box.js';
|
|
10
|
+
export { createUnknownComponentElement, markUnknownComponentHost, serializeUnknownComponentNode, UNKNOWN_COMPONENT_ERROR, } from './unknown-component.js';
|
|
9
11
|
/** @param {boolean} [on] */
|
|
10
12
|
export declare function __vmzPrecisionEnable(on?: boolean): void;
|
|
11
13
|
/** @param {boolean} [on] */
|
package/dist/dom-core.js
CHANGED
|
@@ -7,14 +7,12 @@
|
|
|
7
7
|
* Mount and client patches run that same schedule (SSR/hydrate/resume in dom-ssr).
|
|
8
8
|
* Field writes only run registered dep patches — never re-create structure.
|
|
9
9
|
*/
|
|
10
|
+
import { applyDirectHostBox } from './direct-host-box.js';
|
|
11
|
+
import { createUnknownComponentElement } from './unknown-component.js';
|
|
12
|
+
export { applyDirectHostBox, INLINE_HOST_CONTENTS, resolveDirectHostBox } from './direct-host-box.js';
|
|
13
|
+
export { createUnknownComponentElement, markUnknownComponentHost, serializeUnknownComponentNode, UNKNOWN_COMPONENT_ERROR, } from './unknown-component.js';
|
|
10
14
|
/** @type {Record<string, new (props?: object) => any>} */
|
|
11
15
|
const components = Object.create(null);
|
|
12
|
-
/**
|
|
13
|
-
* Inline chip hosts that opt into `display: contents` (`ui-direct-host-box`).
|
|
14
|
-
* Block surfaces (DataTable / shells / overlays) must keep a real layout box.
|
|
15
|
-
* @type {Set<string>}
|
|
16
|
-
*/
|
|
17
|
-
const INLINE_HOST_CONTENTS = new Set(['Button', 'Badge', 'Link', 'Tag', 'Icon']);
|
|
18
16
|
/**
|
|
19
17
|
* Precision lab counters (test / MCP / benchmarks — not a user API).
|
|
20
18
|
* Primary keys: BindingId (IR). `*ByDep` is transitional stable-string adapter.
|
|
@@ -452,22 +450,23 @@ export const directApi = {
|
|
|
452
450
|
// resume: resume on schedule; EventEntry may lazy-load chunk via __vmzLoadComponent.
|
|
453
451
|
scheduleClientOn(host, String(client), async () => {
|
|
454
452
|
const Ctor = await resolveComponent(name);
|
|
455
|
-
if (!Ctor)
|
|
456
|
-
|
|
453
|
+
if (!Ctor) {
|
|
454
|
+
// Replace placeholder island with leaf error node (do not throw page).
|
|
455
|
+
const err = createUnknownComponentElement(name, 'island');
|
|
456
|
+
host.replaceWith(err);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
457
459
|
await resume(Ctor, host, { props: resolved, state: {} });
|
|
458
460
|
});
|
|
459
461
|
return host;
|
|
460
462
|
}
|
|
461
463
|
const Ctor = components[name];
|
|
462
|
-
if (!Ctor)
|
|
463
|
-
|
|
464
|
-
// Inline chips opt into no-box host (`ui-direct-host-box`). Block surfaces
|
|
465
|
-
// (tables/shells/overlays) keep a real box — default `contents` breaks
|
|
466
|
-
// hit-testing / slot hosts (DataTable select timed out in ui-automation).
|
|
467
|
-
const hostBox = Ctor.__vmzHostBox;
|
|
468
|
-
if (hostBox === 'contents' || (hostBox == null && INLINE_HOST_CONTENTS.has(String(name)))) {
|
|
469
|
-
host.style.display = 'contents';
|
|
464
|
+
if (!Ctor) {
|
|
465
|
+
return createUnknownComponentElement(name, 'client');
|
|
470
466
|
}
|
|
467
|
+
// Inline chips → `display: contents` (`ui-direct-host-box`). Block surfaces
|
|
468
|
+
// keep a real box (DataTable select timed out when defaulting everything).
|
|
469
|
+
applyDirectHostBox(host, name, Ctor);
|
|
471
470
|
const child = createInstance(Ctor, resolved);
|
|
472
471
|
if (!(Ctor.__vmzDirect && typeof Ctor.__vmzCreate === 'function')) {
|
|
473
472
|
throw new Error(`vmz:dom direct component <${name}> requires __vmzCreate (rebuild child with Direct)`);
|
package/dist/dom-ssr.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* VMZ DOM SSR / hydrate / resume — precise patches, no VDOM diff.
|
|
4
4
|
* Imports client DOM primitives from ./dom-core.js for tree-shakeable browser entry.
|
|
5
5
|
*/
|
|
6
|
+
import { applyDirectHostBox, directHostBoxStyleAttr } from './direct-host-box.js';
|
|
6
7
|
import { applyDomAttr, applyPreservedState, BOOLEAN_HTML_ATTRS, createInstance, destroy, directApi, eventPropHandlerName, getRegisteredComponent, hasMeaningfulChild, isEventEntryStrategy, mount, noteDomCreate, resolveComponent, runDirectCreate, scheduleClientOn, settlePendingChildMounts, snapshotInstanceState, stripFns, } from './dom-core.js';
|
|
8
|
+
import { markUnknownComponentHost, serializeUnknownComponentNode } from './unknown-component.js';
|
|
7
9
|
/** @type {Error | null} last linkedom resolve failure (for clear SSR errors) */
|
|
8
10
|
let _ssrDocumentLastError = null;
|
|
9
11
|
/**
|
|
@@ -742,8 +744,9 @@ const serializeApi = {
|
|
|
742
744
|
},
|
|
743
745
|
component(hostInst, name, props, client) {
|
|
744
746
|
const Ctor = getRegisteredComponent(name);
|
|
745
|
-
if (!Ctor)
|
|
746
|
-
|
|
747
|
+
if (!Ctor) {
|
|
748
|
+
return serializeUnknownComponentNode(name);
|
|
749
|
+
}
|
|
747
750
|
/** @type {Record<string, any>} */
|
|
748
751
|
const resolved = {};
|
|
749
752
|
for (const [k, v] of Object.entries(props || {})) {
|
|
@@ -788,6 +791,9 @@ const serializeApi = {
|
|
|
788
791
|
'data-vmz-props': JSON.stringify(stripFns(resolved)),
|
|
789
792
|
'data-vmz-resume': JSON.stringify(resume),
|
|
790
793
|
};
|
|
794
|
+
const boxStyle = directHostBoxStyleAttr(name, Ctor);
|
|
795
|
+
if (boxStyle)
|
|
796
|
+
attrs.style = boxStyle;
|
|
791
797
|
if (isEventEntryStrategy(String(client))) {
|
|
792
798
|
attrs['data-vmz-entry'] = 'event';
|
|
793
799
|
}
|
|
@@ -810,11 +816,9 @@ const serializeApi = {
|
|
|
810
816
|
const node = Ctor.__vmzCreate.call(child, serializeApi);
|
|
811
817
|
/** @type {Record<string, string>} */
|
|
812
818
|
const attrs = { 'data-vmz': name };
|
|
813
|
-
const
|
|
814
|
-
if (
|
|
815
|
-
|
|
816
|
-
attrs.style = 'display:contents';
|
|
817
|
-
}
|
|
819
|
+
const boxStyle = directHostBoxStyleAttr(name, Ctor);
|
|
820
|
+
if (boxStyle)
|
|
821
|
+
attrs.style = boxStyle;
|
|
818
822
|
return {
|
|
819
823
|
__kind: 'el',
|
|
820
824
|
tag: 'div',
|
|
@@ -892,6 +896,8 @@ export async function resume(Component, container, slice = null) {
|
|
|
892
896
|
destroy(container.__vmzInst);
|
|
893
897
|
container.__vmzInst = null;
|
|
894
898
|
}
|
|
899
|
+
const hostName = container.getAttribute('data-vmz') || container.getAttribute('data-vmz-island') || Component.name || '';
|
|
900
|
+
applyDirectHostBox(container, hostName, Component);
|
|
895
901
|
const props = parsed.props || {};
|
|
896
902
|
const inst = createInstance(Component, props);
|
|
897
903
|
if (parsed.state)
|
|
@@ -935,7 +941,7 @@ export function resumeIslands(root = globalThis.document) {
|
|
|
935
941
|
scheduleClientOn(el, strategy, async () => {
|
|
936
942
|
const Ctor = await resolveComponent(name);
|
|
937
943
|
if (!Ctor) {
|
|
938
|
-
|
|
944
|
+
markUnknownComponentHost(el, name, 'resume');
|
|
939
945
|
return;
|
|
940
946
|
}
|
|
941
947
|
await resume(Ctor, el);
|
|
@@ -961,7 +967,7 @@ export function attachEventEntries(root = globalThis.document) {
|
|
|
961
967
|
scheduleClientOn(el, strategy, async () => {
|
|
962
968
|
const Ctor = await resolveComponent(name);
|
|
963
969
|
if (!Ctor) {
|
|
964
|
-
|
|
970
|
+
markUnknownComponentHost(el, name, 'event-entry');
|
|
965
971
|
return;
|
|
966
972
|
}
|
|
967
973
|
await resume(Ctor, el);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unknown Direct component resilience (`ssr-unknown-component-error-node`).
|
|
3
|
+
* Leaf failure → subtree error node; do not throw out of document SSR.
|
|
4
|
+
*/
|
|
5
|
+
/** @type {string} */
|
|
6
|
+
export declare const UNKNOWN_COMPONENT_ERROR = "unknown-component";
|
|
7
|
+
/**
|
|
8
|
+
* Append a leaf diagnostic for tooling (does not replace the error node).
|
|
9
|
+
* @param {string} name
|
|
10
|
+
* @param {string} [via]
|
|
11
|
+
*/
|
|
12
|
+
export declare function noteUnknownComponent(name: any, via?: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* SSR serialize-tree error node (keeps document HTTP 200).
|
|
15
|
+
* @param {string} name
|
|
16
|
+
*/
|
|
17
|
+
export declare function serializeUnknownComponentNode(name: any): {
|
|
18
|
+
__kind: string;
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs: {
|
|
21
|
+
'data-vmz-error': string;
|
|
22
|
+
'data-vmz-component': string;
|
|
23
|
+
};
|
|
24
|
+
children: any[];
|
|
25
|
+
appendChild(c: any): void;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Live DOM error host (client create / schedule).
|
|
29
|
+
* @param {string} name
|
|
30
|
+
* @param {string} [via]
|
|
31
|
+
* @returns {HTMLElement}
|
|
32
|
+
*/
|
|
33
|
+
export declare function createUnknownComponentElement(name: any, via?: string): HTMLDivElement;
|
|
34
|
+
/**
|
|
35
|
+
* Mark an existing island host as unknown (resume / EventEntry).
|
|
36
|
+
* @param {HTMLElement} el
|
|
37
|
+
* @param {string} name
|
|
38
|
+
* @param {string} [via]
|
|
39
|
+
*/
|
|
40
|
+
export declare function markUnknownComponentHost(el: any, name: any, via?: string): void;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unknown Direct component resilience (`ssr-unknown-component-error-node`).
|
|
3
|
+
* Leaf failure → subtree error node; do not throw out of document SSR.
|
|
4
|
+
*/
|
|
5
|
+
/** @type {string} */
|
|
6
|
+
export const UNKNOWN_COMPONENT_ERROR = 'unknown-component';
|
|
7
|
+
/**
|
|
8
|
+
* @returns {boolean}
|
|
9
|
+
*/
|
|
10
|
+
function isDevSurface() {
|
|
11
|
+
try {
|
|
12
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
13
|
+
if (process.env.VMZ_DEV === '1' || process.env.VMZ_DEV === 'true')
|
|
14
|
+
return true;
|
|
15
|
+
if (process.env.NODE_ENV === 'development')
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
/* ignore */
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Append a leaf diagnostic for tooling (does not replace the error node).
|
|
26
|
+
* @param {string} name
|
|
27
|
+
* @param {string} [via]
|
|
28
|
+
*/
|
|
29
|
+
export function noteUnknownComponent(name, via = 'ssr') {
|
|
30
|
+
const detail = { kind: UNKNOWN_COMPONENT_ERROR, component: String(name || ''), via };
|
|
31
|
+
try {
|
|
32
|
+
if (typeof console !== 'undefined' && typeof console.error === 'function') {
|
|
33
|
+
console.error(`vmz:dom unknown component <${name} /> (${via})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* ignore */
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const g = typeof globalThis !== 'undefined' ? globalThis : null;
|
|
41
|
+
if (!g)
|
|
42
|
+
return;
|
|
43
|
+
if (!Array.isArray(g.__VMZ_COMPONENT_ERRORS__)) {
|
|
44
|
+
g.__VMZ_COMPONENT_ERRORS__ = [];
|
|
45
|
+
}
|
|
46
|
+
/** @type {unknown[]} */
|
|
47
|
+
const bag = g.__VMZ_COMPONENT_ERRORS__;
|
|
48
|
+
bag.push(detail);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* ignore */
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* SSR serialize-tree error node (keeps document HTTP 200).
|
|
56
|
+
* @param {string} name
|
|
57
|
+
*/
|
|
58
|
+
export function serializeUnknownComponentNode(name) {
|
|
59
|
+
noteUnknownComponent(name, 'ssr');
|
|
60
|
+
/** @type {Record<string, string>} */
|
|
61
|
+
const attrs = {
|
|
62
|
+
'data-vmz-error': UNKNOWN_COMPONENT_ERROR,
|
|
63
|
+
'data-vmz-component': String(name || ''),
|
|
64
|
+
};
|
|
65
|
+
/** @type {any[]} */
|
|
66
|
+
const children = [];
|
|
67
|
+
if (isDevSurface()) {
|
|
68
|
+
children.push({
|
|
69
|
+
__kind: 'text',
|
|
70
|
+
value: `Unknown component <${name} />`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
__kind: 'el',
|
|
75
|
+
tag: 'div',
|
|
76
|
+
attrs,
|
|
77
|
+
children,
|
|
78
|
+
appendChild(c) {
|
|
79
|
+
if (c != null)
|
|
80
|
+
this.children.push(c);
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Live DOM error host (client create / schedule).
|
|
86
|
+
* @param {string} name
|
|
87
|
+
* @param {string} [via]
|
|
88
|
+
* @returns {HTMLElement}
|
|
89
|
+
*/
|
|
90
|
+
export function createUnknownComponentElement(name, via = 'client') {
|
|
91
|
+
noteUnknownComponent(name, via);
|
|
92
|
+
const host = document.createElement('div');
|
|
93
|
+
host.setAttribute('data-vmz-error', UNKNOWN_COMPONENT_ERROR);
|
|
94
|
+
host.setAttribute('data-vmz-component', String(name || ''));
|
|
95
|
+
if (isDevSurface()) {
|
|
96
|
+
host.textContent = `Unknown component <${name} />`;
|
|
97
|
+
}
|
|
98
|
+
return host;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Mark an existing island host as unknown (resume / EventEntry).
|
|
102
|
+
* @param {HTMLElement} el
|
|
103
|
+
* @param {string} name
|
|
104
|
+
* @param {string} [via]
|
|
105
|
+
*/
|
|
106
|
+
export function markUnknownComponentHost(el, name, via = 'resume') {
|
|
107
|
+
if (!el)
|
|
108
|
+
return;
|
|
109
|
+
noteUnknownComponent(name, via);
|
|
110
|
+
el.setAttribute('data-vmz-error', UNKNOWN_COMPONENT_ERROR);
|
|
111
|
+
el.setAttribute('data-vmz-component', String(name || ''));
|
|
112
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vmz/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "VMZ production runtime core — DOM / SSR / HTTP / WriteBarrier (no compiler)",
|
|
6
6
|
"exports": {
|
|
@@ -58,12 +58,12 @@
|
|
|
58
58
|
"linkedom": "^0.18.13"
|
|
59
59
|
},
|
|
60
60
|
"optionalDependencies": {
|
|
61
|
-
"@vmz/vmz-win32-x64": "0.1.
|
|
62
|
-
"@vmz/vmz-win32-arm64": "0.1.
|
|
63
|
-
"@vmz/vmz-darwin-x64": "0.1.
|
|
64
|
-
"@vmz/vmz-darwin-arm64": "0.1.
|
|
65
|
-
"@vmz/vmz-linux-x64": "0.1.
|
|
66
|
-
"@vmz/vmz-linux-arm64": "0.1.
|
|
61
|
+
"@vmz/vmz-win32-x64": "0.1.21",
|
|
62
|
+
"@vmz/vmz-win32-arm64": "0.1.21",
|
|
63
|
+
"@vmz/vmz-darwin-x64": "0.1.21",
|
|
64
|
+
"@vmz/vmz-darwin-arm64": "0.1.21",
|
|
65
|
+
"@vmz/vmz-linux-x64": "0.1.21",
|
|
66
|
+
"@vmz/vmz-linux-arm64": "0.1.21"
|
|
67
67
|
},
|
|
68
68
|
"publishConfig": {
|
|
69
69
|
"access": "public"
|