@vertz/ui 0.2.0 → 0.2.2

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 (36) hide show
  1. package/README.md +339 -857
  2. package/dist/css/public.d.ts +24 -27
  3. package/dist/css/public.js +5 -1
  4. package/dist/form/public.d.ts +94 -38
  5. package/dist/form/public.js +5 -3
  6. package/dist/index.d.ts +754 -167
  7. package/dist/index.js +606 -84
  8. package/dist/internals.d.ts +192 -23
  9. package/dist/internals.js +151 -102
  10. package/dist/jsx-runtime/index.d.ts +44 -17
  11. package/dist/jsx-runtime/index.js +26 -7
  12. package/dist/query/public.d.ts +73 -7
  13. package/dist/query/public.js +12 -4
  14. package/dist/router/public.d.ts +199 -26
  15. package/dist/router/public.js +22 -7
  16. package/dist/shared/chunk-0xcmwgdb.js +288 -0
  17. package/dist/shared/{chunk-j8vzvne3.js → chunk-9e92w0wt.js} +4 -1
  18. package/dist/shared/chunk-g4rch80a.js +33 -0
  19. package/dist/shared/chunk-hh0dhmb4.js +528 -0
  20. package/dist/shared/{chunk-pgymxpn1.js → chunk-hrd0mft1.js} +136 -34
  21. package/dist/shared/chunk-jrtrk5z4.js +125 -0
  22. package/dist/shared/chunk-ka5ked7n.js +188 -0
  23. package/dist/shared/chunk-n91rwj2r.js +483 -0
  24. package/dist/shared/chunk-prj7nm08.js +67 -0
  25. package/dist/shared/chunk-q6cpe5k7.js +230 -0
  26. package/dist/shared/{chunk-f1ynwam4.js → chunk-qacth5ah.js} +162 -36
  27. package/dist/shared/chunk-ryb49346.js +374 -0
  28. package/dist/shared/chunk-v3yyf79g.js +48 -0
  29. package/dist/test/index.d.ts +67 -6
  30. package/dist/test/index.js +4 -3
  31. package/package.json +14 -9
  32. package/dist/shared/chunk-bp3v6s9j.js +0 -62
  33. package/dist/shared/chunk-d8h2eh8d.js +0 -141
  34. package/dist/shared/chunk-tsdpgmks.js +0 -98
  35. package/dist/shared/chunk-xd9d7q5p.js +0 -115
  36. package/dist/shared/chunk-zbbvx05f.js +0 -202
@@ -1,11 +1,76 @@
1
1
  // src/component/context.ts
2
2
  var currentScope = null;
3
+ function isSignalLike(value) {
4
+ return value != null && typeof value === "object" && "peek" in value && typeof value.peek === "function";
5
+ }
6
+ function wrapSignalProps(value) {
7
+ if (value == null || typeof value !== "object" || Array.isArray(value)) {
8
+ return value;
9
+ }
10
+ const source = value;
11
+ const keys = Object.keys(source);
12
+ let hasSignal = false;
13
+ for (const key of keys) {
14
+ if (isSignalLike(source[key])) {
15
+ hasSignal = true;
16
+ break;
17
+ }
18
+ }
19
+ if (!hasSignal)
20
+ return value;
21
+ const wrapped = {};
22
+ for (const key of keys) {
23
+ const propValue = source[key];
24
+ if (isSignalLike(propValue)) {
25
+ Object.defineProperty(wrapped, key, {
26
+ get() {
27
+ return propValue.value;
28
+ },
29
+ enumerable: true,
30
+ configurable: true
31
+ });
32
+ } else {
33
+ wrapped[key] = propValue;
34
+ }
35
+ }
36
+ return wrapped;
37
+ }
3
38
  function asKey(ctx) {
4
39
  return ctx;
5
40
  }
6
- function createContext(defaultValue) {
41
+ var REGISTRY_KEY = "__VERTZ_CTX_REG__";
42
+ var contextRegistry = globalThis[REGISTRY_KEY] ?? (() => {
43
+ const m = new Map;
44
+ globalThis[REGISTRY_KEY] = m;
45
+ return m;
46
+ })();
47
+ function createContext(defaultValue, __stableId) {
48
+ if (__stableId) {
49
+ const existing = contextRegistry.get(__stableId);
50
+ if (existing)
51
+ return existing;
52
+ }
7
53
  const ctx = {
8
- Provider(value, fn) {
54
+ Provider(valueOrProps, fn) {
55
+ if (fn !== undefined) {
56
+ const value2 = wrapSignalProps(valueOrProps);
57
+ const parentScope2 = currentScope;
58
+ const scope2 = parentScope2 ? new Map(parentScope2) : new Map;
59
+ scope2.set(asKey(ctx), value2);
60
+ ctx._stack.push(value2);
61
+ const prevScope2 = currentScope;
62
+ currentScope = scope2;
63
+ try {
64
+ fn();
65
+ } finally {
66
+ ctx._stack.pop();
67
+ currentScope = prevScope2;
68
+ }
69
+ return;
70
+ }
71
+ const props = valueOrProps;
72
+ const { value: rawValue, children } = props;
73
+ const value = wrapSignalProps(rawValue);
9
74
  const parentScope = currentScope;
10
75
  const scope = parentScope ? new Map(parentScope) : new Map;
11
76
  scope.set(asKey(ctx), value);
@@ -13,7 +78,11 @@ function createContext(defaultValue) {
13
78
  const prevScope = currentScope;
14
79
  currentScope = scope;
15
80
  try {
16
- fn();
81
+ const result = typeof children === "function" ? children() : children;
82
+ if (typeof process !== "undefined" && true && Array.isArray(result)) {
83
+ throw new Error("Context.Provider JSX children must have a single root element. " + "Wrap multiple children in a fragment: <><Child1 /><Child2 /></>");
84
+ }
85
+ return result;
17
86
  } finally {
18
87
  ctx._stack.pop();
19
88
  currentScope = prevScope;
@@ -22,6 +91,9 @@ function createContext(defaultValue) {
22
91
  _default: defaultValue,
23
92
  _stack: []
24
93
  };
94
+ if (__stableId) {
95
+ contextRegistry.set(__stableId, ctx);
96
+ }
25
97
  return ctx;
26
98
  }
27
99
  function useContext(ctx) {
@@ -46,7 +118,7 @@ function setContextScope(scope) {
46
118
  // src/runtime/disposal.ts
47
119
  class DisposalScopeError extends Error {
48
120
  constructor() {
49
- super("onCleanup() must be called within a disposal scope (e.g., inside effect(), watch(), onMount(), or a pushScope()/popScope() block). " + "Called outside a scope, the cleanup callback would be silently discarded.");
121
+ super("onCleanup() must be called within a disposal scope (e.g., inside domEffect(), lifecycleEffect(), onMount(), or a pushScope()/popScope() block). " + "Called outside a scope, the cleanup callback would be silently discarded.");
50
122
  this.name = "DisposalScopeError";
51
123
  }
52
124
  }
@@ -79,6 +151,35 @@ function runCleanups(cleanups) {
79
151
  cleanups.length = 0;
80
152
  }
81
153
 
154
+ // src/runtime/tracking.ts
155
+ var currentSubscriber = null;
156
+ var readValueCallback = null;
157
+ function getSubscriber() {
158
+ return currentSubscriber;
159
+ }
160
+ function setSubscriber(sub) {
161
+ const prev = currentSubscriber;
162
+ currentSubscriber = sub;
163
+ return prev;
164
+ }
165
+ function getReadValueCallback() {
166
+ return readValueCallback;
167
+ }
168
+ function setReadValueCallback(cb) {
169
+ const prev = readValueCallback;
170
+ readValueCallback = cb;
171
+ return prev;
172
+ }
173
+ function untrack(fn) {
174
+ const prev = currentSubscriber;
175
+ currentSubscriber = null;
176
+ try {
177
+ return fn();
178
+ } finally {
179
+ currentSubscriber = prev;
180
+ }
181
+ }
182
+
82
183
  // src/runtime/scheduler.ts
83
184
  var batchDepth = 0;
84
185
  var pendingEffects = new Map;
@@ -114,36 +215,18 @@ function batch(fn) {
114
215
  }
115
216
  }
116
217
 
117
- // src/runtime/tracking.ts
118
- var currentSubscriber = null;
119
- var readValueCallback = null;
120
- function getSubscriber() {
121
- return currentSubscriber;
122
- }
123
- function setSubscriber(sub) {
124
- const prev = currentSubscriber;
125
- currentSubscriber = sub;
126
- return prev;
218
+ // src/runtime/signal.ts
219
+ function isSSR() {
220
+ const check = typeof globalThis !== "undefined" && globalThis.__VERTZ_IS_SSR__;
221
+ return typeof check === "function" ? check() : false;
127
222
  }
128
- function getReadValueCallback() {
129
- return readValueCallback;
223
+ var signalCollectorStack = [];
224
+ function startSignalCollection() {
225
+ signalCollectorStack.push([]);
130
226
  }
131
- function setReadValueCallback(cb) {
132
- const prev = readValueCallback;
133
- readValueCallback = cb;
134
- return prev;
135
- }
136
- function untrack(fn) {
137
- const prev = currentSubscriber;
138
- currentSubscriber = null;
139
- try {
140
- return fn();
141
- } finally {
142
- currentSubscriber = prev;
143
- }
227
+ function stopSignalCollection() {
228
+ return signalCollectorStack.pop() ?? [];
144
229
  }
145
-
146
- // src/runtime/signal.ts
147
230
  var nextId = 0;
148
231
 
149
232
  class SignalImpl {
@@ -185,7 +268,12 @@ class SignalImpl {
185
268
  }
186
269
  }
187
270
  function signal(initial) {
188
- return new SignalImpl(initial);
271
+ const s = new SignalImpl(initial);
272
+ const collector = signalCollectorStack[signalCollectorStack.length - 1];
273
+ if (collector) {
274
+ collector.push(s);
275
+ }
276
+ return s;
189
277
  }
190
278
  class ComputedImpl {
191
279
  _id;
@@ -297,7 +385,21 @@ class EffectImpl {
297
385
  this._contextScope = null;
298
386
  }
299
387
  }
300
- function effect(fn) {
388
+ function domEffect(fn) {
389
+ if (isSSR()) {
390
+ fn();
391
+ return () => {};
392
+ }
393
+ const eff = new EffectImpl(fn);
394
+ eff._run();
395
+ const dispose = () => eff._dispose();
396
+ _tryOnCleanup(dispose);
397
+ return dispose;
398
+ }
399
+ function lifecycleEffect(fn) {
400
+ if (isSSR()) {
401
+ return () => {};
402
+ }
301
403
  const eff = new EffectImpl(fn);
302
404
  eff._run();
303
405
  const dispose = () => eff._dispose();
@@ -305,4 +407,4 @@ function effect(fn) {
305
407
  return dispose;
306
408
  }
307
409
 
308
- export { createContext, useContext, DisposalScopeError, onCleanup, _tryOnCleanup, pushScope, popScope, runCleanups, batch, setReadValueCallback, untrack, signal, computed, effect };
410
+ export { createContext, useContext, getContextScope, setContextScope, DisposalScopeError, onCleanup, _tryOnCleanup, pushScope, popScope, runCleanups, setReadValueCallback, untrack, batch, startSignalCollection, stopSignalCollection, signal, computed, domEffect, lifecycleEffect };
@@ -0,0 +1,125 @@
1
+ // src/router/server-nav.ts
2
+ function parseSSE(buffer) {
3
+ const events = [];
4
+ const blocks = buffer.split(`
5
+
6
+ `);
7
+ const remaining = blocks.pop() ?? "";
8
+ for (const block of blocks) {
9
+ if (block.trim() === "")
10
+ continue;
11
+ let type = "";
12
+ let data = "";
13
+ for (const line of block.split(`
14
+ `)) {
15
+ if (line.startsWith("event: ")) {
16
+ type = line.slice(7).trim();
17
+ } else if (line.startsWith("data: ")) {
18
+ data = line.slice(6);
19
+ }
20
+ }
21
+ if (type) {
22
+ events.push({ type, data });
23
+ }
24
+ }
25
+ return { events, remaining };
26
+ }
27
+ function ensureSSRDataBus() {
28
+ const g = globalThis;
29
+ g.__VERTZ_SSR_DATA__ = [];
30
+ g.__VERTZ_SSR_PUSH__ = (key, data) => {
31
+ g.__VERTZ_SSR_DATA__.push({ key, data });
32
+ document.dispatchEvent(new CustomEvent("vertz:ssr-data", { detail: { key, data } }));
33
+ };
34
+ }
35
+ function pushNavData(key, data) {
36
+ const push = globalThis.__VERTZ_SSR_PUSH__;
37
+ if (typeof push === "function") {
38
+ push(key, data);
39
+ }
40
+ }
41
+ function isNavPrefetchActive() {
42
+ return globalThis.__VERTZ_NAV_PREFETCH_ACTIVE__ === true;
43
+ }
44
+ function setNavPrefetchActive(active) {
45
+ globalThis.__VERTZ_NAV_PREFETCH_ACTIVE__ = active;
46
+ }
47
+ function dispatchPrefetchDone() {
48
+ setNavPrefetchActive(false);
49
+ document.dispatchEvent(new CustomEvent("vertz:nav-prefetch-done"));
50
+ }
51
+ var prefetchGen = 0;
52
+ function prefetchNavData(url, options) {
53
+ const controller = new AbortController;
54
+ const timeout = options?.timeout ?? 5000;
55
+ const gen = ++prefetchGen;
56
+ ensureSSRDataBus();
57
+ setNavPrefetchActive(true);
58
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
59
+ let resolveFirstEvent = null;
60
+ const firstEvent = new Promise((r) => {
61
+ resolveFirstEvent = r;
62
+ });
63
+ function onFirstEvent() {
64
+ if (resolveFirstEvent) {
65
+ resolveFirstEvent();
66
+ resolveFirstEvent = null;
67
+ }
68
+ }
69
+ function finishIfCurrent() {
70
+ if (gen === prefetchGen) {
71
+ dispatchPrefetchDone();
72
+ }
73
+ }
74
+ const done = fetch(url, {
75
+ headers: { "X-Vertz-Nav": "1" },
76
+ signal: controller.signal
77
+ }).then(async (response) => {
78
+ if (!response.body) {
79
+ onFirstEvent();
80
+ finishIfCurrent();
81
+ return;
82
+ }
83
+ const reader = response.body.getReader();
84
+ const decoder = new TextDecoder;
85
+ let buffer = "";
86
+ while (true) {
87
+ const { done: streamDone, value } = await reader.read();
88
+ if (streamDone)
89
+ break;
90
+ buffer += decoder.decode(value, { stream: true });
91
+ const parsed = parseSSE(buffer);
92
+ buffer = parsed.remaining;
93
+ for (const event of parsed.events) {
94
+ onFirstEvent();
95
+ if (event.type === "data") {
96
+ try {
97
+ const { key, data } = JSON.parse(event.data);
98
+ pushNavData(key, data);
99
+ } catch {}
100
+ } else if (event.type === "done") {
101
+ finishIfCurrent();
102
+ clearTimeout(timeoutId);
103
+ return;
104
+ }
105
+ }
106
+ }
107
+ onFirstEvent();
108
+ finishIfCurrent();
109
+ }).catch(() => {
110
+ onFirstEvent();
111
+ finishIfCurrent();
112
+ }).finally(() => {
113
+ clearTimeout(timeoutId);
114
+ });
115
+ return {
116
+ abort: () => {
117
+ controller.abort();
118
+ clearTimeout(timeoutId);
119
+ },
120
+ done,
121
+ firstEvent
122
+ };
123
+ }
124
+
125
+ export { isNavPrefetchActive, prefetchNavData };
@@ -0,0 +1,188 @@
1
+ import {
2
+ executeLoaders,
3
+ matchRoute
4
+ } from "./chunk-9e92w0wt.js";
5
+ import {
6
+ prefetchNavData
7
+ } from "./chunk-jrtrk5z4.js";
8
+ import {
9
+ signal
10
+ } from "./chunk-hrd0mft1.js";
11
+
12
+ // src/router/navigate.ts
13
+ var DEFAULT_NAV_THRESHOLD_MS = 500;
14
+ function createRouter(routes, initialUrl, options) {
15
+ const isSSR = typeof window === "undefined" || typeof globalThis.__SSR_URL__ !== "undefined";
16
+ let url;
17
+ if (initialUrl) {
18
+ url = initialUrl;
19
+ } else if (isSSR) {
20
+ url = globalThis.__SSR_URL__ || "/";
21
+ } else {
22
+ url = window.location.pathname + window.location.search;
23
+ }
24
+ const initialMatch = matchRoute(routes, url);
25
+ function normalizeUrl(rawUrl) {
26
+ const qIdx = rawUrl.indexOf("?");
27
+ if (qIdx === -1)
28
+ return rawUrl;
29
+ const pathname = rawUrl.slice(0, qIdx);
30
+ const params = new URLSearchParams(rawUrl.slice(qIdx + 1));
31
+ params.sort();
32
+ const sorted = params.toString();
33
+ return sorted ? `${pathname}?${sorted}` : pathname;
34
+ }
35
+ const visitedUrls = new Set;
36
+ if (initialMatch)
37
+ visitedUrls.add(normalizeUrl(url));
38
+ const current = signal(initialMatch);
39
+ const loaderData = signal([]);
40
+ const loaderError = signal(null);
41
+ const searchParams = signal(initialMatch?.search ?? {});
42
+ let navigationGen = 0;
43
+ let navigateGen = 0;
44
+ let currentAbort = null;
45
+ const serverNavEnabled = !!options?.serverNav;
46
+ const serverNavTimeout = typeof options?.serverNav === "object" ? options.serverNav.timeout : undefined;
47
+ const prefetchFn = options?._prefetchNavData ?? (serverNavEnabled ? prefetchNavData : null);
48
+ let activePrefetch = null;
49
+ let activePrefetchUrl = null;
50
+ function startPrefetch(navUrl) {
51
+ if (!serverNavEnabled || !prefetchFn)
52
+ return null;
53
+ const normalized = normalizeUrl(navUrl);
54
+ if (activePrefetch && activePrefetchUrl === normalized) {
55
+ return activePrefetch;
56
+ }
57
+ if (activePrefetch) {
58
+ activePrefetch.abort();
59
+ }
60
+ const prefetchOpts = {};
61
+ if (serverNavTimeout !== undefined) {
62
+ prefetchOpts.timeout = serverNavTimeout;
63
+ }
64
+ activePrefetch = prefetchFn(navUrl, prefetchOpts);
65
+ activePrefetchUrl = normalized;
66
+ return activePrefetch;
67
+ }
68
+ async function awaitPrefetch(handle) {
69
+ const target = handle?.firstEvent ?? handle?.done;
70
+ if (!target)
71
+ return;
72
+ await Promise.race([target, new Promise((r) => setTimeout(r, DEFAULT_NAV_THRESHOLD_MS))]);
73
+ }
74
+ if (isSSR) {
75
+ const g = globalThis;
76
+ const prev = g.__VERTZ_SSR_SYNC_ROUTER__;
77
+ g.__VERTZ_SSR_SYNC_ROUTER__ = (ssrUrl) => {
78
+ if (typeof prev === "function")
79
+ prev(ssrUrl);
80
+ const match = matchRoute(routes, ssrUrl);
81
+ current.value = match;
82
+ searchParams.value = match?.search ?? {};
83
+ };
84
+ }
85
+ if (initialMatch) {
86
+ const gen = ++navigationGen;
87
+ const abort = new AbortController;
88
+ currentAbort = abort;
89
+ runLoaders(initialMatch, gen, abort.signal).catch(() => {});
90
+ }
91
+ async function runLoaders(match, gen, abortSignal) {
92
+ try {
93
+ loaderError.value = null;
94
+ const results = await executeLoaders(match.matched, match.params, abortSignal);
95
+ if (gen === navigationGen) {
96
+ loaderData.value = results;
97
+ }
98
+ } catch (err) {
99
+ if (gen === navigationGen) {
100
+ loaderError.value = err instanceof Error ? err : new Error(String(err));
101
+ }
102
+ }
103
+ }
104
+ async function applyNavigation(url2) {
105
+ if (currentAbort) {
106
+ currentAbort.abort();
107
+ }
108
+ const gen = ++navigationGen;
109
+ const abort = new AbortController;
110
+ currentAbort = abort;
111
+ const match = matchRoute(routes, url2);
112
+ current.value = match;
113
+ if (match) {
114
+ visitedUrls.add(normalizeUrl(url2));
115
+ searchParams.value = match.search;
116
+ await runLoaders(match, gen, abort.signal);
117
+ } else {
118
+ searchParams.value = {};
119
+ if (gen === navigationGen) {
120
+ loaderData.value = [];
121
+ loaderError.value = null;
122
+ }
123
+ }
124
+ }
125
+ async function navigate(navUrl, navOptions) {
126
+ const gen = ++navigateGen;
127
+ const handle = startPrefetch(navUrl);
128
+ if (!isSSR) {
129
+ if (navOptions?.replace) {
130
+ window.history.replaceState(null, "", navUrl);
131
+ } else {
132
+ window.history.pushState(null, "", navUrl);
133
+ }
134
+ }
135
+ const isCachedNav = visitedUrls.has(normalizeUrl(navUrl));
136
+ if (!isCachedNav && (handle?.firstEvent || handle?.done)) {
137
+ await awaitPrefetch(handle);
138
+ }
139
+ if (gen !== navigateGen)
140
+ return;
141
+ await applyNavigation(navUrl);
142
+ }
143
+ async function revalidate() {
144
+ const match = current.value;
145
+ if (match) {
146
+ if (currentAbort) {
147
+ currentAbort.abort();
148
+ }
149
+ const gen = ++navigationGen;
150
+ const abort = new AbortController;
151
+ currentAbort = abort;
152
+ await runLoaders(match, gen, abort.signal);
153
+ }
154
+ }
155
+ let onPopState = null;
156
+ if (!isSSR) {
157
+ onPopState = () => {
158
+ const popUrl = window.location.pathname + window.location.search;
159
+ startPrefetch(popUrl);
160
+ applyNavigation(popUrl).catch(() => {});
161
+ };
162
+ window.addEventListener("popstate", onPopState);
163
+ }
164
+ function dispose() {
165
+ if (onPopState) {
166
+ window.removeEventListener("popstate", onPopState);
167
+ }
168
+ if (currentAbort) {
169
+ currentAbort.abort();
170
+ }
171
+ if (activePrefetch) {
172
+ activePrefetch.abort();
173
+ activePrefetch = null;
174
+ activePrefetchUrl = null;
175
+ }
176
+ }
177
+ return {
178
+ current,
179
+ dispose,
180
+ loaderData,
181
+ loaderError,
182
+ navigate,
183
+ revalidate,
184
+ searchParams
185
+ };
186
+ }
187
+
188
+ export { createRouter };