@vmz/core 0.2.5 → 0.2.7

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 (77) hide show
  1. package/dist/browser/client-nav.d.ts +5 -55
  2. package/dist/browser/client-nav.js +5 -769
  3. package/dist/browser/diagnostics/precision-trace.d.ts +47 -0
  4. package/dist/browser/diagnostics/precision-trace.js +86 -0
  5. package/dist/browser/dom/attributes.d.ts +5 -0
  6. package/dist/browser/dom/attributes.js +102 -0
  7. package/dist/browser/dom/component.d.ts +11 -0
  8. package/dist/browser/dom/component.js +255 -0
  9. package/dist/browser/dom/direct-api.d.ts +66 -0
  10. package/dist/browser/dom/direct-api.js +446 -0
  11. package/dist/browser/dom/lifecycle.d.ts +9 -0
  12. package/dist/browser/dom/lifecycle.js +161 -0
  13. package/dist/browser/dom/registry.d.ts +5 -0
  14. package/dist/browser/dom/registry.js +16 -0
  15. package/dist/browser/dom-core.d.ts +51 -249
  16. package/dist/browser/dom-core.js +51 -2521
  17. package/dist/browser/navigation/client-navigation.d.ts +44 -0
  18. package/dist/browser/navigation/client-navigation.js +277 -0
  19. package/dist/browser/navigation/extract-html.d.ts +1 -0
  20. package/dist/browser/navigation/extract-html.js +5 -0
  21. package/dist/browser/navigation/layout-retain.d.ts +3 -0
  22. package/dist/browser/navigation/layout-retain.js +34 -0
  23. package/dist/browser/navigation/locale-transition.d.ts +24 -0
  24. package/dist/browser/navigation/locale-transition.js +323 -0
  25. package/dist/browser/navigation/scroll-focus.d.ts +14 -0
  26. package/dist/browser/navigation/scroll-focus.js +87 -0
  27. package/dist/browser/reactivity/patch-scheduler.d.ts +12 -0
  28. package/dist/browser/reactivity/patch-scheduler.js +720 -0
  29. package/dist/browser/reactivity/write-barrier.d.ts +16 -0
  30. package/dist/browser/reactivity/write-barrier.js +546 -0
  31. package/dist/browser/resume/adopt.d.ts +1 -0
  32. package/dist/browser/resume/adopt.js +168 -0
  33. package/dist/browser/resume/hydrate.d.ts +4 -0
  34. package/dist/browser/resume/hydrate.js +107 -0
  35. package/dist/browser/resume/resume.d.ts +3 -0
  36. package/dist/browser/resume/resume.js +102 -0
  37. package/dist/faces/dom.browser.d.ts +2 -1
  38. package/dist/faces/dom.browser.js +2 -1
  39. package/dist/host/{deployment-registry.d.ts → deployment/deployment-registry.d.ts} +1 -1
  40. package/dist/host/{deployment-registry.js → deployment/deployment-registry.js} +1 -1
  41. package/dist/host/list-client-components.d.ts +2 -2
  42. package/dist/host/list-client-components.js +4 -4
  43. package/dist/host/{render-host.d.ts → render/render-host.d.ts} +2 -2
  44. package/dist/host/{render-host.js → render/render-host.js} +1 -1
  45. package/dist/host/{route-layout-chain.js → render/route-layout-chain.js} +1 -1
  46. package/dist/host/serve/bootstrap.d.ts +1 -0
  47. package/dist/host/serve/bootstrap.js +25 -0
  48. package/dist/host/serve/constants.d.ts +6 -0
  49. package/dist/host/serve/constants.js +6 -0
  50. package/dist/host/serve/hmr-dev.d.ts +34 -0
  51. package/dist/host/serve/hmr-dev.js +294 -0
  52. package/dist/host/serve/http.d.ts +1 -0
  53. package/dist/host/serve/http.js +124 -0
  54. package/dist/host/serve/locale-theme.d.ts +19 -0
  55. package/dist/host/serve/locale-theme.js +169 -0
  56. package/dist/host/serve/page-catalog.d.ts +14 -0
  57. package/dist/host/serve/page-catalog.js +105 -0
  58. package/dist/host/serve/page-render.d.ts +17 -0
  59. package/dist/host/serve/page-render.js +419 -0
  60. package/dist/host/serve/paths.d.ts +3 -0
  61. package/dist/host/serve/paths.js +74 -0
  62. package/dist/host/serve/route-catalog.d.ts +6 -0
  63. package/dist/host/serve/route-catalog.js +108 -0
  64. package/dist/host/serve/state.d.ts +30 -0
  65. package/dist/host/serve/state.js +36 -0
  66. package/dist/host/serve-host.d.ts +0 -17
  67. package/dist/host/serve-host.mjs +4 -1420
  68. package/dist/ssr/document.d.ts +2 -0
  69. package/dist/ssr/document.js +71 -0
  70. package/dist/ssr/dom-ssr.d.ts +10 -47
  71. package/dist/ssr/dom-ssr.js +10 -1284
  72. package/dist/ssr/render.d.ts +2 -0
  73. package/dist/ssr/render.js +78 -0
  74. package/dist/ssr/serialize.d.ts +3 -0
  75. package/dist/ssr/serialize.js +678 -0
  76. package/package.json +11 -11
  77. /package/dist/host/{route-layout-chain.d.ts → render/route-layout-chain.d.ts} +0 -0
@@ -0,0 +1,323 @@
1
+ export function applyLocaleRealization(doc, root) {
2
+ if (!root || !doc?.documentElement)
3
+ return null;
4
+ const locale = root.getAttribute('data-vmz-locale');
5
+ const dir = root.getAttribute('data-vmz-dir');
6
+ if (locale) {
7
+ doc.documentElement.setAttribute('data-locale', locale);
8
+ doc.documentElement.lang = locale;
9
+ }
10
+ if (dir)
11
+ doc.documentElement.dir = dir;
12
+ return locale;
13
+ }
14
+ export function createLocaleTransition({ document: doc, window: win, location: loc, transitionTo }) {
15
+ let localeTransitionGeneration = 0;
16
+ function readLocaleRouting() {
17
+ const raw = doc.documentElement?.getAttribute('data-vmz-locale-routing');
18
+ if (!raw)
19
+ return null;
20
+ try {
21
+ return JSON.parse(raw);
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ function readLocaleHrefTable() {
28
+ const raw = doc.documentElement?.getAttribute('data-vmz-locale-hrefs');
29
+ if (!raw)
30
+ return null;
31
+ try {
32
+ const table = JSON.parse(raw);
33
+ return table && typeof table === 'object' ? table : null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ function lookupFrozenLocaleHref(routeId, localeId) {
40
+ if (!routeId || !localeId)
41
+ return null;
42
+ const table = readLocaleHrefTable();
43
+ const href = table?.[routeId]?.[localeId];
44
+ return typeof href === 'string' && href && !/\[[^\]]+\]/.test(href) && !/\/:[^/]+/.test(href) ? href : null;
45
+ }
46
+ function resolveRouteIdFromHrefTable(pathname, localeId) {
47
+ const table = readLocaleHrefTable();
48
+ if (!table || !localeId)
49
+ return null;
50
+ const norm = pathname.length > 1 && pathname.endsWith('/') ? pathname.slice(0, -1) : pathname || '/';
51
+ for (const [routeId, byLocale] of Object.entries(table)) {
52
+ const href = byLocale?.[localeId];
53
+ if (typeof href !== 'string')
54
+ continue;
55
+ const h = href.length > 1 && href.endsWith('/') ? href.slice(0, -1) : href;
56
+ if (h === norm)
57
+ return routeId;
58
+ }
59
+ return null;
60
+ }
61
+ function realizePathForLocale(href, localeId, routing) {
62
+ let pathname = href;
63
+ let search = '';
64
+ let hash = '';
65
+ const hashIdx = pathname.indexOf('#');
66
+ if (hashIdx >= 0) {
67
+ hash = pathname.slice(hashIdx);
68
+ pathname = pathname.slice(0, hashIdx);
69
+ }
70
+ const qIdx = pathname.indexOf('?');
71
+ if (qIdx >= 0) {
72
+ search = pathname.slice(qIdx);
73
+ pathname = pathname.slice(0, qIdx);
74
+ }
75
+ if (!pathname)
76
+ pathname = '/';
77
+ const fromLocale = doc.documentElement?.getAttribute('data-locale') || null;
78
+ const routeId = doc.documentElement?.getAttribute('data-vmz-route') ||
79
+ doc.querySelector?.('[data-vmz-app][data-vmz-route]')?.getAttribute?.('data-vmz-route') ||
80
+ resolveRouteIdFromHrefTable(pathname, fromLocale);
81
+ const frozen = lookupFrozenLocaleHref(routeId, localeId);
82
+ if (frozen)
83
+ return `${frozen}${search}${hash}`;
84
+ const supported = Array.isArray(routing.locales) ? routing.locales : [];
85
+ const parts = pathname.split('/').filter(Boolean);
86
+ let rest = pathname;
87
+ if (parts.length && supported.includes(parts[0])) {
88
+ const r = parts.slice(1);
89
+ rest = r.length ? `/${r.join('/')}` : '/';
90
+ }
91
+ if (rest.length > 1 && rest.endsWith('/'))
92
+ rest = rest.slice(0, -1);
93
+ if (!rest.startsWith('/'))
94
+ rest = `/${rest}`;
95
+ const strategy = routing.strategy || 'prefix';
96
+ const defaultPrefix = routing.defaultPrefix || 'include';
97
+ const defaultLocale = routing.defaultLocale;
98
+ if (strategy === 'none' || strategy === 'domain')
99
+ return `${rest}${search}${hash}`;
100
+ if (defaultPrefix === 'omit' && localeId === defaultLocale)
101
+ return `${rest}${search}${hash}`;
102
+ const pathOut = rest === '/' ? `/${localeId}` : `/${localeId}${rest}`;
103
+ return `${pathOut}${search}${hash}`;
104
+ }
105
+ function localizeClickHref(href, routeId) {
106
+ if (!doc?.documentElement)
107
+ return href;
108
+ const locale = doc.documentElement.getAttribute('data-locale');
109
+ if (!locale)
110
+ return href;
111
+ const frozen = lookupFrozenLocaleHref(routeId, locale);
112
+ if (frozen) {
113
+ let search = '';
114
+ let hash = '';
115
+ const hashIdx = href.indexOf('#');
116
+ let pathPart = href;
117
+ if (hashIdx >= 0) {
118
+ hash = pathPart.slice(hashIdx);
119
+ pathPart = pathPart.slice(0, hashIdx);
120
+ }
121
+ const qIdx = pathPart.indexOf('?');
122
+ if (qIdx >= 0) {
123
+ search = pathPart.slice(qIdx);
124
+ }
125
+ return `${frozen}${search}${hash}`;
126
+ }
127
+ const raw = doc.documentElement.getAttribute('data-vmz-locale-routing');
128
+ if (!raw)
129
+ return href;
130
+ let routing;
131
+ try {
132
+ routing = JSON.parse(raw);
133
+ }
134
+ catch {
135
+ return href;
136
+ }
137
+ const supported = Array.isArray(routing.locales) ? routing.locales : [];
138
+ const defaultLocale = routing.defaultLocale;
139
+ let pathname = href;
140
+ let search = '';
141
+ let hash = '';
142
+ const hashIdx = pathname.indexOf('#');
143
+ if (hashIdx >= 0) {
144
+ hash = pathname.slice(hashIdx);
145
+ pathname = pathname.slice(0, hashIdx);
146
+ }
147
+ const qIdx = pathname.indexOf('?');
148
+ if (qIdx >= 0) {
149
+ search = pathname.slice(qIdx);
150
+ pathname = pathname.slice(0, qIdx);
151
+ }
152
+ if (!pathname)
153
+ pathname = '/';
154
+ const parts = pathname.split('/').filter(Boolean);
155
+ if (parts.length && supported.includes(parts[0])) {
156
+ return `${pathname}${search}${hash}`;
157
+ }
158
+ let rest = pathname;
159
+ if (rest.length > 1 && rest.endsWith('/'))
160
+ rest = rest.slice(0, -1);
161
+ if (!rest.startsWith('/'))
162
+ rest = `/${rest}`;
163
+ const strategy = routing.strategy || 'prefix';
164
+ const defaultPrefix = routing.defaultPrefix || 'include';
165
+ if (strategy === 'none' || strategy === 'domain')
166
+ return `${rest}${search}${hash}`;
167
+ if (defaultPrefix === 'omit' && locale === defaultLocale)
168
+ return `${rest}${search}${hash}`;
169
+ const pathOut = rest === '/' ? `/${locale}` : `/${locale}${rest}`;
170
+ return `${pathOut}${search}${hash}`;
171
+ }
172
+ function transitionLocaleNone(toLocale, fromLocale, opts = {}) {
173
+ const STORE_KEY = 'vmz.locale';
174
+ try {
175
+ try {
176
+ localStorage.setItem(STORE_KEY, toLocale);
177
+ }
178
+ catch {
179
+ /* private mode */
180
+ }
181
+ try {
182
+ doc.cookie = `${STORE_KEY}=${encodeURIComponent(toLocale)}; path=/; max-age=31536000; SameSite=Lax`;
183
+ }
184
+ catch {
185
+ /* ignore */
186
+ }
187
+ if (doc.documentElement) {
188
+ doc.documentElement.setAttribute('data-locale', toLocale);
189
+ doc.documentElement.setAttribute('lang', toLocale);
190
+ }
191
+ if (win)
192
+ win.__vmzLocaleIdHint = toLocale;
193
+ }
194
+ catch (err) {
195
+ const out = {
196
+ status: 'rolled_back',
197
+ fromLocale,
198
+ toLocale,
199
+ reason: 'persist_failed',
200
+ detail: err && err.message ? String(err.message) : String(err),
201
+ };
202
+ if (win)
203
+ win.__vmzLastLocaleTransition = out;
204
+ return out;
205
+ }
206
+ const out = {
207
+ status: 'committed',
208
+ fromLocale,
209
+ toLocale,
210
+ reason: 'ok',
211
+ strategy: 'none',
212
+ href: loc.pathname + loc.search,
213
+ reload: opts.reload !== false,
214
+ };
215
+ if (win)
216
+ win.__vmzLastLocaleTransition = out;
217
+ if (opts.reload !== false && loc && typeof loc.reload === 'function') {
218
+ loc.reload();
219
+ }
220
+ return out;
221
+ }
222
+ async function transitionLocale(toLocale, opts = {}) {
223
+ const fromLocale = doc.documentElement?.getAttribute('data-locale') || null;
224
+ const routing = readLocaleRouting();
225
+ if (!routing) {
226
+ const out = {
227
+ status: 'rejected',
228
+ fromLocale,
229
+ toLocale,
230
+ reason: 'missing_routing',
231
+ };
232
+ if (win)
233
+ win.__vmzLastLocaleTransition = out;
234
+ return out;
235
+ }
236
+ const supported = Array.isArray(routing.locales) ? routing.locales : [];
237
+ if (!supported.includes(toLocale)) {
238
+ const out = {
239
+ status: 'rejected',
240
+ fromLocale,
241
+ toLocale,
242
+ reason: 'unsupported',
243
+ };
244
+ if (win)
245
+ win.__vmzLastLocaleTransition = out;
246
+ return out;
247
+ }
248
+ if (toLocale === fromLocale) {
249
+ const out = {
250
+ status: 'committed',
251
+ fromLocale,
252
+ toLocale,
253
+ reason: 'noop',
254
+ href: loc.pathname + loc.search,
255
+ };
256
+ if (win)
257
+ win.__vmzLastLocaleTransition = out;
258
+ return out;
259
+ }
260
+ const strategy = routing.strategy || 'prefix';
261
+ if (strategy === 'none') {
262
+ return transitionLocaleNone(toLocale, fromLocale, opts);
263
+ }
264
+ const gen = ++localeTransitionGeneration;
265
+ const targetHref = realizePathForLocale(loc.pathname + loc.search + loc.hash, toLocale, routing);
266
+ const result = await transitionTo(targetHref, { replace: opts.replace !== false, softFail: true });
267
+ if (gen !== localeTransitionGeneration) {
268
+ const out = {
269
+ status: 'cancelled',
270
+ fromLocale,
271
+ toLocale,
272
+ reason: 'stale_generation',
273
+ href: targetHref,
274
+ generation: gen,
275
+ };
276
+ if (win)
277
+ win.__vmzLastLocaleTransition = out;
278
+ return out;
279
+ }
280
+ if (!result?.ok) {
281
+ const still = doc.documentElement?.getAttribute('data-locale');
282
+ const out = {
283
+ status: 'rolled_back',
284
+ fromLocale,
285
+ toLocale,
286
+ reason: result?.reason || 'nav_failed',
287
+ href: targetHref,
288
+ retainedLocale: still,
289
+ generation: gen,
290
+ };
291
+ if (win)
292
+ win.__vmzLastLocaleTransition = out;
293
+ return out;
294
+ }
295
+ const committed = doc.documentElement?.getAttribute('data-locale');
296
+ if (committed !== toLocale) {
297
+ const out = {
298
+ status: 'failed',
299
+ fromLocale,
300
+ toLocale,
301
+ reason: 'partial',
302
+ href: targetHref,
303
+ committedLocale: committed,
304
+ generation: gen,
305
+ };
306
+ if (win)
307
+ win.__vmzLastLocaleTransition = out;
308
+ return out;
309
+ }
310
+ const out = {
311
+ status: 'committed',
312
+ fromLocale,
313
+ toLocale,
314
+ reason: 'ok',
315
+ href: targetHref,
316
+ generation: gen,
317
+ };
318
+ if (win)
319
+ win.__vmzLastLocaleTransition = out;
320
+ return out;
321
+ }
322
+ return { transitionLocale, localizeClickHref };
323
+ }
@@ -0,0 +1,14 @@
1
+ export type ScrollFocusEnv = {
2
+ document: Document;
3
+ window: Window;
4
+ location: Location;
5
+ };
6
+ export declare function createScrollFocus({ document: doc, window: win, location: loc }: ScrollFocusEnv): {
7
+ saveScroll: () => void;
8
+ restoreScroll: (target: URL, fromPop: boolean) => Promise<{
9
+ mode: string;
10
+ x: number;
11
+ y: number;
12
+ }>;
13
+ restoreFocus: (root: HTMLElement | null, target: URL) => string;
14
+ };
@@ -0,0 +1,87 @@
1
+ export function createScrollFocus({ document: doc, window: win, location: loc }) {
2
+ const scrollPositions = new Map();
3
+ function navKey(pathname, search) {
4
+ return `${pathname || '/'}${search || ''}`;
5
+ }
6
+ function saveScroll() {
7
+ scrollPositions.set(navKey(loc.pathname, loc.search), {
8
+ x: win.scrollX || 0,
9
+ y: win.scrollY || 0,
10
+ });
11
+ }
12
+ async function restoreScroll(target, fromPop) {
13
+ const frame = () => new Promise((resolve) => {
14
+ if (typeof win.requestAnimationFrame === 'function')
15
+ win.requestAnimationFrame(() => resolve());
16
+ else
17
+ setTimeout(resolve, 0);
18
+ });
19
+ if (fromPop) {
20
+ const saved = scrollPositions.get(navKey(target.pathname, target.search));
21
+ if (saved) {
22
+ const apply = () => {
23
+ try {
24
+ win.scrollTo(saved.x, saved.y);
25
+ }
26
+ catch {
27
+ /* ignore */
28
+ }
29
+ };
30
+ for (let i = 0; i < 12; i++) {
31
+ apply();
32
+ const y = win.scrollY || 0;
33
+ if (Math.abs(y - saved.y) <= 2)
34
+ break;
35
+ const docEl = doc.documentElement || doc.body;
36
+ const maxY = Math.max(0, (docEl?.scrollHeight || 0) - (win.innerHeight || 0));
37
+ if (maxY + 2 < saved.y) {
38
+ await frame();
39
+ continue;
40
+ }
41
+ await frame();
42
+ }
43
+ apply();
44
+ return { mode: 'restored', x: saved.x, y: win.scrollY || saved.y };
45
+ }
46
+ }
47
+ if (target.hash) {
48
+ const id = decodeURIComponent(target.hash.slice(1));
49
+ const el = id ? doc.getElementById(id) : null;
50
+ if (el && typeof el.scrollIntoView === 'function') {
51
+ el.scrollIntoView();
52
+ return { mode: 'hash', x: win.scrollX || 0, y: win.scrollY || 0 };
53
+ }
54
+ }
55
+ win.scrollTo(0, 0);
56
+ return { mode: 'top', x: 0, y: 0 };
57
+ }
58
+ function restoreFocus(root, target) {
59
+ if (!root || !doc)
60
+ return null;
61
+ let el = null;
62
+ if (target.hash) {
63
+ const id = decodeURIComponent(target.hash.slice(1));
64
+ el = id ? doc.getElementById(id) : null;
65
+ }
66
+ if (!el)
67
+ el = root.querySelector('[data-vmz-focus]');
68
+ if (!el)
69
+ el = root.querySelector('main, h1, [role="main"]');
70
+ if (!el)
71
+ el = root;
72
+ if (el === doc.body)
73
+ return null;
74
+ const focusable = el;
75
+ if (!focusable.hasAttribute('tabindex') && focusable.tabIndex < 0) {
76
+ focusable.setAttribute('tabindex', '-1');
77
+ }
78
+ try {
79
+ focusable.focus({ preventScroll: true });
80
+ }
81
+ catch {
82
+ /* ignore */
83
+ }
84
+ return focusable.getAttribute('data-vmz-focus') || focusable.tagName?.toLowerCase() || null;
85
+ }
86
+ return { saveScroll, restoreScroll, restoreFocus };
87
+ }
@@ -0,0 +1,12 @@
1
+ export declare function runPatch(inst: any, fn: any, depKey?: any, bindingId?: any): any;
2
+ export declare function scheduleRefresh(inst: any, notice: any): void;
3
+ export declare function inferHandlerMethod(handler: any): any;
4
+ export declare function methodAllowsSyncEventFlush(inst: any, methodName: any): boolean;
5
+ export declare function runDomEventHandler(inst: any, methodHint: any, fn: any): any;
6
+ export declare function beginEventFlush(inst: any): void;
7
+ export declare function endEventFlush(inst: any): void;
8
+ export declare function promoteLeafDirtyToTrie(inst: any): void;
9
+ export declare function flushPending(inst: any): any;
10
+ export declare function registerBind(inst: any, deps: any, fn: any, bindingId?: any): void;
11
+ export declare function unregisterBind(inst: any, deps: any, fn: any, bindingId?: any): void;
12
+ export declare function hasMeaningfulChild(el: any): boolean;