@epoch32/visage 0.0.0-stage → 0.0.0

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 (138) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +110 -2
  3. package/dist/bundle.dev.js +4875 -0
  4. package/dist/index.js +9633 -0
  5. package/dist/src/api/index.js +4002 -0
  6. package/dist/src/charts/index.js +2717 -0
  7. package/dist/src/devtools/index.js +4677 -0
  8. package/dist/src/dom/index.js +1550 -0
  9. package/dist/src/form/index.js +1415 -0
  10. package/dist/src/index.js +11826 -0
  11. package/dist/src/jsx-runtime/index.js +1630 -0
  12. package/dist/src/query/index.js +2422 -0
  13. package/dist/src/router/index.js +1856 -0
  14. package/dist/src/rpc/index.js +3484 -0
  15. package/dist/src/server/index.js +1173 -0
  16. package/dist/src/signals/index.js +1077 -0
  17. package/dist/src/style/index.js +2340 -0
  18. package/dist/src/template/index.js +1149 -0
  19. package/dist/src/ui/index.js +4155 -0
  20. package/dist/src/virtual/index.js +1955 -0
  21. package/dist/src/vite/index.js +984 -0
  22. package/dist/vite/index.js +707 -0
  23. package/package.json +140 -4
  24. package/src/api/client.ts +371 -0
  25. package/src/api/file-router.ts +183 -0
  26. package/src/api/handler.ts +326 -0
  27. package/src/api/index.ts +71 -0
  28. package/src/api/middleware.ts +54 -0
  29. package/src/api/pragma.ts +155 -0
  30. package/src/api/procedure.ts +172 -0
  31. package/src/api/types.ts +249 -0
  32. package/src/charts/Area.tsx +111 -0
  33. package/src/charts/Axis.tsx +126 -0
  34. package/src/charts/Bar.tsx +86 -0
  35. package/src/charts/CartesianGrid.tsx +72 -0
  36. package/src/charts/Chart.tsx +269 -0
  37. package/src/charts/Cursor.tsx +42 -0
  38. package/src/charts/Legend.tsx +56 -0
  39. package/src/charts/Line.tsx +106 -0
  40. package/src/charts/Pie.tsx +88 -0
  41. package/src/charts/Tooltip.tsx +127 -0
  42. package/src/charts/context.ts +30 -0
  43. package/src/charts/index.ts +14 -0
  44. package/src/charts/path.ts +155 -0
  45. package/src/charts/scale.ts +133 -0
  46. package/src/charts/types.ts +50 -0
  47. package/src/devtools/DomTab.tsx +134 -0
  48. package/src/devtools/GraphInspector.tsx +196 -0
  49. package/src/devtools/GraphTab.tsx +315 -0
  50. package/src/devtools/QueryTab.tsx +200 -0
  51. package/src/devtools/RpcTab.tsx +190 -0
  52. package/src/devtools/SignalsTab.tsx +129 -0
  53. package/src/devtools/component.tsx +243 -0
  54. package/src/devtools/highlighter.ts +134 -0
  55. package/src/devtools/hub.ts +175 -0
  56. package/src/devtools/index.ts +20 -0
  57. package/src/devtools/styles.ts +313 -0
  58. package/src/devtools/types.ts +45 -0
  59. package/src/dom/async.ts +232 -0
  60. package/src/dom/control-flow.ts +353 -0
  61. package/src/dom/index.ts +32 -0
  62. package/src/dom/lazy.ts +82 -0
  63. package/src/dom/render.ts +286 -0
  64. package/src/dom/resource.ts +120 -0
  65. package/src/form/form.ts +218 -0
  66. package/src/form/index.ts +17 -0
  67. package/src/form/schema.ts +299 -0
  68. package/src/index.ts +413 -0
  69. package/src/jsx-dev-runtime/index.ts +1 -0
  70. package/src/jsx-runtime/index.ts +112 -0
  71. package/src/jsx-runtime/jsx.d.ts +278 -0
  72. package/src/query/create-mutation.ts +64 -0
  73. package/src/query/create-query.ts +426 -0
  74. package/src/query/focus-manager.ts +68 -0
  75. package/src/query/index.ts +63 -0
  76. package/src/query/mutation-cache.ts +138 -0
  77. package/src/query/online-manager.ts +67 -0
  78. package/src/query/query-cache.ts +369 -0
  79. package/src/query/query-client.ts +248 -0
  80. package/src/query/types.ts +221 -0
  81. package/src/query/utils.ts +132 -0
  82. package/src/router/index.ts +19 -0
  83. package/src/router/router.tsx +352 -0
  84. package/src/rpc/client.ts +317 -0
  85. package/src/rpc/error.ts +70 -0
  86. package/src/rpc/index.ts +52 -0
  87. package/src/rpc/procedure.ts +88 -0
  88. package/src/rpc/router.ts +105 -0
  89. package/src/rpc/server.ts +511 -0
  90. package/src/rpc/types.ts +328 -0
  91. package/src/server/hydrate.ts +21 -0
  92. package/src/server/index.ts +10 -0
  93. package/src/server/render-to-stream.ts +31 -0
  94. package/src/server/render-to-string.ts +125 -0
  95. package/src/signals/computed.ts +217 -0
  96. package/src/signals/context.ts +89 -0
  97. package/src/signals/effect.ts +161 -0
  98. package/src/signals/index.ts +57 -0
  99. package/src/signals/scope.ts +132 -0
  100. package/src/signals/signal.ts +203 -0
  101. package/src/signals/store.ts +163 -0
  102. package/src/signals/system.ts +124 -0
  103. package/src/signals/types.ts +64 -0
  104. package/src/style/component.tsx +122 -0
  105. package/src/style/create-style.ts +229 -0
  106. package/src/style/cx.ts +75 -0
  107. package/src/style/hash.ts +19 -0
  108. package/src/style/index.ts +8 -0
  109. package/src/style/layout.tsx +406 -0
  110. package/src/style/manager.ts +87 -0
  111. package/src/style/parser.ts +257 -0
  112. package/src/style/scale.ts +237 -0
  113. package/src/template/index.ts +4 -0
  114. package/src/template/template.ts +126 -0
  115. package/src/ui/accordion.tsx +286 -0
  116. package/src/ui/command-dialog.tsx +49 -0
  117. package/src/ui/command.tsx +400 -0
  118. package/src/ui/data-table.tsx +322 -0
  119. package/src/ui/dialog.tsx +362 -0
  120. package/src/ui/dropdown-menu.tsx +381 -0
  121. package/src/ui/icon.tsx +69 -0
  122. package/src/ui/index.ts +138 -0
  123. package/src/ui/layout.tsx +13 -0
  124. package/src/ui/popover.tsx +249 -0
  125. package/src/ui/switch.tsx +114 -0
  126. package/src/ui/tabs.tsx +297 -0
  127. package/src/ui/toast.tsx +280 -0
  128. package/src/ui/tooltip.tsx +262 -0
  129. package/src/ui/utils.ts +110 -0
  130. package/src/virtual/index.ts +12 -0
  131. package/src/virtual/virtual-list.tsx +185 -0
  132. package/src/virtual/virtualizer.ts +274 -0
  133. package/src/vite/hmr.ts +38 -0
  134. package/src/vite/index.ts +3 -0
  135. package/src/vite/lucide.ts +124 -0
  136. package/src/vite/plugin.ts +102 -0
  137. package/src/vite/rpc-middleware.ts +82 -0
  138. package/src/vite/types.ts +65 -0
@@ -0,0 +1,4155 @@
1
+ // src/signals/types.ts
2
+ var SubscriberState;
3
+ ((SubscriberState) => {
4
+ SubscriberState[SubscriberState["CLEAN"] = 0] = "CLEAN";
5
+ SubscriberState[SubscriberState["CHECK_DIRTY"] = 1] = "CHECK_DIRTY";
6
+ SubscriberState[SubscriberState["DIRTY"] = 2] = "DIRTY";
7
+ SubscriberState[SubscriberState["DISPOSED"] = 3] = "DISPOSED";
8
+ })(SubscriberState ||= {});
9
+ var SIGNAL_BRAND = Symbol("visage.signal");
10
+ var COMPUTED_BRAND = Symbol("visage.computed");
11
+ function isSignal(value) {
12
+ return typeof value === "function" && ((SIGNAL_BRAND in value) || (COMPUTED_BRAND in value));
13
+ }
14
+
15
+ // src/signals/system.ts
16
+ var currentSubscriber = null;
17
+ var currentScope = null;
18
+ var batchDepth = 0;
19
+ var pendingEffects = new Set;
20
+ var warnedCyclicSubscribers = new WeakSet;
21
+ var isFlushing = false;
22
+ function setCurrentSubscriber(sub) {
23
+ currentSubscriber = sub;
24
+ }
25
+ function setCurrentScope(scope) {
26
+ currentScope = scope;
27
+ }
28
+ function getCurrentScope() {
29
+ return currentScope;
30
+ }
31
+ function addPendingEffect(eff) {
32
+ pendingEffects.add(eff);
33
+ }
34
+ function removePendingEffect(eff) {
35
+ pendingEffects.delete(eff);
36
+ }
37
+ var MAX_FLUSH_COUNT = 100;
38
+ function flushEffects() {
39
+ if (isFlushing || batchDepth > 0)
40
+ return;
41
+ isFlushing = true;
42
+ let iterations = 0;
43
+ try {
44
+ while (pendingEffects.size > 0) {
45
+ if (++iterations > MAX_FLUSH_COUNT) {
46
+ pendingEffects.clear();
47
+ throw new Error(`[Visage Reactivity] Maximum update depth exceeded (${MAX_FLUSH_COUNT} cycles). ` + `An effect continuously triggered state mutations (infinite loop detected). ` + `Ensure effects that modify signals do not unconditionally depend on them, or use untrack() to read state.`);
48
+ }
49
+ const effectsToRun = Array.from(pendingEffects);
50
+ pendingEffects.clear();
51
+ for (const eff of effectsToRun) {
52
+ if (eff.state === 2 /* DIRTY */ || eff.state === 1 /* CHECK_DIRTY */) {
53
+ eff.run();
54
+ }
55
+ }
56
+ }
57
+ } finally {
58
+ isFlushing = false;
59
+ }
60
+ }
61
+ function batch(fn) {
62
+ batchDepth++;
63
+ try {
64
+ return fn();
65
+ } finally {
66
+ batchDepth--;
67
+ if (batchDepth === 0) {
68
+ flushEffects();
69
+ }
70
+ }
71
+ }
72
+ function untrack(fn) {
73
+ const prev = currentSubscriber;
74
+ currentSubscriber = null;
75
+ try {
76
+ return fn();
77
+ } finally {
78
+ currentSubscriber = prev;
79
+ }
80
+ }
81
+
82
+ // src/signals/computed.ts
83
+ class Computed {
84
+ [COMPUTED_BRAND] = true;
85
+ _fn;
86
+ _value;
87
+ _subscribers = new Set;
88
+ sources = new Set;
89
+ sourceVersions = new Map;
90
+ state = 2 /* DIRTY */;
91
+ scope;
92
+ version = 0;
93
+ constructor(fn) {
94
+ this._fn = fn;
95
+ this.scope = currentScope;
96
+ if (currentScope) {
97
+ currentScope.addSubscriber(this);
98
+ }
99
+ }
100
+ get() {
101
+ if (this.state === 3 /* DISPOSED */) {
102
+ return this._fn();
103
+ }
104
+ if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
105
+ this._subscribers.add(currentSubscriber);
106
+ currentSubscriber.sources.add(this);
107
+ currentSubscriber.sourceVersions.set(this, this.version);
108
+ }
109
+ if (this.state === 2 /* DIRTY */ || this.state === 1 /* CHECK_DIRTY */) {
110
+ this.updateIfNecessary();
111
+ }
112
+ return this._value;
113
+ }
114
+ get value() {
115
+ return this.get();
116
+ }
117
+ removeSubscriber(sub) {
118
+ this._subscribers.delete(sub);
119
+ }
120
+ markDirty(targetState = 1 /* CHECK_DIRTY */) {
121
+ if (this.state >= targetState || this.state === 3 /* DISPOSED */) {
122
+ return;
123
+ }
124
+ this.state = targetState;
125
+ for (const sub of this._subscribers) {
126
+ sub.markDirty(1 /* CHECK_DIRTY */);
127
+ }
128
+ }
129
+ updateIfNecessary() {
130
+ if (this.state === 2 /* DIRTY */) {
131
+ const prev = this._value;
132
+ this.recompute();
133
+ return !Object.is(prev, this._value);
134
+ }
135
+ if (this.state === 1 /* CHECK_DIRTY */) {
136
+ let anyChanged = false;
137
+ for (const source of this.sources) {
138
+ if (source instanceof Computed) {
139
+ source.updateIfNecessary();
140
+ }
141
+ const lastVersion = this.sourceVersions.get(source);
142
+ if (lastVersion !== undefined && lastVersion !== source.version) {
143
+ anyChanged = true;
144
+ }
145
+ }
146
+ if (anyChanged) {
147
+ const prev = this._value;
148
+ this.recompute();
149
+ return !Object.is(prev, this._value);
150
+ }
151
+ this.state = 0 /* CLEAN */;
152
+ return false;
153
+ }
154
+ return false;
155
+ }
156
+ recompute() {
157
+ this.cleanupSources();
158
+ const prevSubscriber = currentSubscriber;
159
+ setCurrentSubscriber(this);
160
+ const prevScope = currentScope;
161
+ setCurrentScope(this.scope);
162
+ try {
163
+ const next = this._fn();
164
+ if (!Object.is(this._value, next)) {
165
+ this._value = next;
166
+ this.version++;
167
+ }
168
+ this.state = 0 /* CLEAN */;
169
+ } finally {
170
+ setCurrentSubscriber(prevSubscriber);
171
+ setCurrentScope(prevScope);
172
+ }
173
+ }
174
+ cleanupSources() {
175
+ for (const source of this.sources) {
176
+ source.removeSubscriber(this);
177
+ }
178
+ this.sources.clear();
179
+ this.sourceVersions.clear();
180
+ }
181
+ dispose() {
182
+ if (this.state === 3 /* DISPOSED */)
183
+ return;
184
+ this.state = 3 /* DISPOSED */;
185
+ this.cleanupSources();
186
+ this._subscribers.clear();
187
+ }
188
+ }
189
+ function computed(fn, options) {
190
+ const isInternal = options?.internal ?? false;
191
+ const customName = options?.name;
192
+ const c = new Computed(fn);
193
+ const accessor = () => c.get();
194
+ Object.defineProperties(accessor, {
195
+ [COMPUTED_BRAND]: { value: true },
196
+ get: { value: () => c.get() },
197
+ value: { get: () => c.get() }
198
+ });
199
+ if (!isInternal && typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
200
+ const devtools = window.__VISAGE_DEVTOOLS__;
201
+ const sigId = devtools.registerSignal({
202
+ name: customName,
203
+ type: "computed",
204
+ getValue: () => c.get(),
205
+ version: () => c.version,
206
+ subscribersCount: () => c._subscribers?.size ?? 0,
207
+ dependencies: () => Array.from(c.sources ?? []).map((src) => src._devId).filter(Boolean),
208
+ dependents: () => Array.from(c._subscribers ?? []).map((sub) => sub._devId).filter(Boolean)
209
+ });
210
+ c._devId = sigId;
211
+ if (currentScope) {
212
+ currentScope.addCleanup(() => {
213
+ devtools.unregisterSignal(sigId);
214
+ });
215
+ }
216
+ }
217
+ return accessor;
218
+ }
219
+ var createMemo = computed;
220
+ // src/style/cx.ts
221
+ function hasReactiveClass(val) {
222
+ if (typeof val === "function")
223
+ return true;
224
+ if (Array.isArray(val)) {
225
+ for (let i = 0;i < val.length; i++) {
226
+ if (hasReactiveClass(val[i]))
227
+ return true;
228
+ }
229
+ return false;
230
+ }
231
+ if (typeof val === "object" && val !== null) {
232
+ for (const k in val) {
233
+ if (typeof val[k] === "function")
234
+ return true;
235
+ }
236
+ }
237
+ return false;
238
+ }
239
+ function normalizeClass(val) {
240
+ if (!val)
241
+ return "";
242
+ if (typeof val === "function")
243
+ return normalizeClass(val());
244
+ if (typeof val === "string")
245
+ return val.trim();
246
+ if (typeof val === "number")
247
+ return String(val);
248
+ if (Array.isArray(val)) {
249
+ let res = "";
250
+ for (let i = 0;i < val.length; i++) {
251
+ const item = typeof val[i] === "function" ? val[i]() : val[i];
252
+ const itemStr = normalizeClass(item);
253
+ if (itemStr) {
254
+ res = res ? `${res} ${itemStr}` : itemStr;
255
+ }
256
+ }
257
+ return res;
258
+ }
259
+ if (typeof val === "object") {
260
+ let res = "";
261
+ for (const key in val) {
262
+ const condition = typeof val[key] === "function" ? val[key]() : val[key];
263
+ if (condition) {
264
+ res = res ? `${res} ${key}` : key;
265
+ }
266
+ }
267
+ return res;
268
+ }
269
+ return "";
270
+ }
271
+ function cx(...args) {
272
+ return normalizeClass(args);
273
+ }
274
+
275
+ // src/style/scale.ts
276
+ var UNITLESS_PROPERTIES = new Set([
277
+ "animationIterationCount",
278
+ "aspectRatio",
279
+ "borderImageSlice",
280
+ "columnCount",
281
+ "columns",
282
+ "flex",
283
+ "flexGrow",
284
+ "flexShrink",
285
+ "flexOrder",
286
+ "fontWeight",
287
+ "lineHeight",
288
+ "opacity",
289
+ "order",
290
+ "orphans",
291
+ "scale",
292
+ "tabSize",
293
+ "widows",
294
+ "zIndex",
295
+ "zoom",
296
+ "fillOpacity",
297
+ "strokeOpacity"
298
+ ]);
299
+ var DIMENSION_KEYWORDS = {
300
+ screen: "100dvh",
301
+ "screen-h": "100dvh",
302
+ "screen-w": "100dvw",
303
+ full: "100%",
304
+ half: "50%",
305
+ third: "33.333333%",
306
+ "two-thirds": "66.666667%",
307
+ quarter: "25%",
308
+ "three-quarters": "75%",
309
+ auto: "auto",
310
+ min: "min-content",
311
+ max: "max-content",
312
+ fit: "fit-content"
313
+ };
314
+ function space(val) {
315
+ if (val === undefined || val === null || val === "")
316
+ return "";
317
+ if (typeof val === "number") {
318
+ if (val === 0)
319
+ return "0px";
320
+ return `${val * 4}px`;
321
+ }
322
+ const str = String(val).trim();
323
+ if (str in DIMENSION_KEYWORDS) {
324
+ return DIMENSION_KEYWORDS[str];
325
+ }
326
+ return str;
327
+ }
328
+ function resolveDimension(val) {
329
+ if (val === undefined || val === null || val === "")
330
+ return "";
331
+ if (typeof val === "number") {
332
+ if (val === 0)
333
+ return "0px";
334
+ if (val > 48)
335
+ return `${val}px`;
336
+ return `${val * 4}px`;
337
+ }
338
+ const str = String(val).trim();
339
+ if (str in DIMENSION_KEYWORDS) {
340
+ return DIMENSION_KEYWORDS[str];
341
+ }
342
+ return str;
343
+ }
344
+ function px(val) {
345
+ return `${val}px`;
346
+ }
347
+ function rem(val) {
348
+ return `${val}rem`;
349
+ }
350
+ function em(val) {
351
+ return `${val}em`;
352
+ }
353
+ function fluid(minPx, maxPx, options) {
354
+ const minVw = options?.minVw ?? 375;
355
+ const maxVw = options?.maxVw ?? 1280;
356
+ const slope = (maxPx - minPx) / (maxVw - minVw);
357
+ const yIntercept = -minVw * slope + minPx;
358
+ const slopeVw = slope * 100;
359
+ const preferred = `${yIntercept.toFixed(2)}px + ${slopeVw.toFixed(2)}vw`;
360
+ const min = Math.min(minPx, maxPx);
361
+ const max = Math.max(minPx, maxPx);
362
+ return `clamp(${min}px, ${preferred}, ${max}px)`;
363
+ }
364
+ var SHADOW_PRESETS = {
365
+ none: "none",
366
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)",
367
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
368
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
369
+ xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)",
370
+ soft: "0 8px 30px rgba(0, 0, 0, 0.06)",
371
+ glow: "0 0 24px rgba(168, 85, 247, 0.35)",
372
+ inner: "inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)"
373
+ };
374
+ function shadow(variant) {
375
+ if (variant in SHADOW_PRESETS) {
376
+ return SHADOW_PRESETS[variant];
377
+ }
378
+ return variant;
379
+ }
380
+ var RADIUS_PRESETS = {
381
+ none: "0px",
382
+ sm: "4px",
383
+ md: "8px",
384
+ lg: "12px",
385
+ xl: "16px",
386
+ "2xl": "20px",
387
+ "3xl": "24px",
388
+ full: "9999px"
389
+ };
390
+ function radius(variant) {
391
+ if (typeof variant === "number") {
392
+ return `${variant}px`;
393
+ }
394
+ if (variant in RADIUS_PRESETS) {
395
+ return RADIUS_PRESETS[variant];
396
+ }
397
+ return String(variant);
398
+ }
399
+ function glass(options = {}) {
400
+ const blurVal = typeof options.blur === "number" ? `${options.blur}px` : options.blur ?? "20px";
401
+ const tintVal = options.tint ?? "rgba(255, 255, 255, 0.65)";
402
+ const borderVal = options.border ?? "1px solid rgba(255, 255, 255, 0.75)";
403
+ return {
404
+ backdropFilter: `blur(${blurVal})`,
405
+ WebkitBackdropFilter: `blur(${blurVal})`,
406
+ backgroundColor: tintVal,
407
+ border: borderVal
408
+ };
409
+ }
410
+ function formatStyleProp(prop, val) {
411
+ if (val === null || val === undefined || val === "")
412
+ return "";
413
+ if (typeof val === "number") {
414
+ if (val === 0 || UNITLESS_PROPERTIES.has(prop)) {
415
+ return String(val);
416
+ }
417
+ return `${val}px`;
418
+ }
419
+ const str = String(val).trim();
420
+ if (str in DIMENSION_KEYWORDS) {
421
+ const lowerProp = prop.toLowerCase();
422
+ if (str === "screen") {
423
+ if (lowerProp.includes("width"))
424
+ return "100dvw";
425
+ return "100dvh";
426
+ }
427
+ return DIMENSION_KEYWORDS[str];
428
+ }
429
+ return str;
430
+ }
431
+
432
+ // src/dom/render.ts
433
+ function isReactive(value) {
434
+ return isSignal(value) || typeof value === "function";
435
+ }
436
+ function resolveValue(val) {
437
+ if (typeof val === "function") {
438
+ return val();
439
+ }
440
+ return val;
441
+ }
442
+ function render(fn, container) {
443
+ return createRoot((dispose) => {
444
+ container.textContent = "";
445
+ const node = insertChild(container, fn());
446
+ onCleanup(() => {
447
+ if (node && node instanceof Node && node.parentNode === container) {
448
+ container.removeChild(node);
449
+ }
450
+ });
451
+ return dispose;
452
+ });
453
+ }
454
+ function setAttribute(el, key, value) {
455
+ if (key.startsWith("on") && typeof value === "function") {
456
+ const eventName = key.startsWith("onCapture") ? key.slice(9).toLowerCase() : key.slice(2).toLowerCase();
457
+ const useCapture = key.startsWith("onCapture");
458
+ el.addEventListener(eventName, value, useCapture);
459
+ onCleanup(() => {
460
+ el.removeEventListener(eventName, value, useCapture);
461
+ });
462
+ return;
463
+ }
464
+ if (key === "ref" && typeof value === "function") {
465
+ value(el);
466
+ return;
467
+ }
468
+ if (key === "class" || key === "className") {
469
+ if (hasReactiveClass(value)) {
470
+ effect(() => {
471
+ const cls = normalizeClass(value);
472
+ if (cls)
473
+ el.setAttribute("class", cls);
474
+ else
475
+ el.removeAttribute("class");
476
+ });
477
+ } else {
478
+ const cls = normalizeClass(value);
479
+ if (cls)
480
+ el.setAttribute("class", cls);
481
+ else
482
+ el.removeAttribute("class");
483
+ }
484
+ return;
485
+ }
486
+ if (isReactive(value)) {
487
+ effect(() => {
488
+ const resolved = resolveValue(value);
489
+ applyProp(el, key, resolved);
490
+ });
491
+ } else {
492
+ applyProp(el, key, value);
493
+ }
494
+ }
495
+ function setStyleProperty(el, prop, val) {
496
+ const formatted = formatStyleProp(prop, val);
497
+ if (prop.startsWith("--") || prop.includes("-")) {
498
+ if (formatted === "") {
499
+ el.style.removeProperty(prop);
500
+ } else {
501
+ el.style.setProperty(prop, formatted);
502
+ }
503
+ } else {
504
+ el.style[prop] = formatted;
505
+ }
506
+ }
507
+ function applyProp(el, key, value) {
508
+ if (value === null || value === undefined || value === false && !key.startsWith("aria-") && !key.startsWith("data-")) {
509
+ if (key === "className" || key === "class") {
510
+ el.removeAttribute("class");
511
+ } else if (key === "style" && typeof value === "string") {
512
+ el.removeAttribute("style");
513
+ } else if (key in el && !(el instanceof SVGElement)) {
514
+ try {
515
+ el[key] = typeof el[key] === "boolean" ? false : "";
516
+ } catch {
517
+ el.removeAttribute(key);
518
+ }
519
+ } else {
520
+ el.removeAttribute(key);
521
+ }
522
+ return;
523
+ }
524
+ if (key === "className" || key === "class") {
525
+ const cls = normalizeClass(value);
526
+ if (cls) {
527
+ el.setAttribute("class", cls);
528
+ } else {
529
+ el.removeAttribute("class");
530
+ }
531
+ } else if (key === "style") {
532
+ if (typeof value === "string") {
533
+ el.setAttribute("style", value);
534
+ } else if (typeof value === "object" && value !== null) {
535
+ for (const styleKey in value) {
536
+ const styleVal = value[styleKey];
537
+ if (isReactive(styleVal)) {
538
+ effect(() => {
539
+ setStyleProperty(el, styleKey, resolveValue(styleVal));
540
+ });
541
+ } else {
542
+ setStyleProperty(el, styleKey, styleVal);
543
+ }
544
+ }
545
+ }
546
+ } else if (key === "dangerouslySetInnerHTML" && value && typeof value.__html === "string") {
547
+ el.innerHTML = value.__html;
548
+ } else if (key in el && !(el instanceof SVGElement) && key !== "list" && key !== "form") {
549
+ try {
550
+ el[key] = value;
551
+ } catch {
552
+ el.setAttribute(key, String(value));
553
+ }
554
+ } else {
555
+ if (key.startsWith("aria-") || key.startsWith("data-")) {
556
+ el.setAttribute(key, String(value));
557
+ } else if (value === true) {
558
+ el.setAttribute(key, "");
559
+ } else {
560
+ el.setAttribute(key, String(value));
561
+ }
562
+ }
563
+ }
564
+ function insertChild(parent, child, before = null) {
565
+ if (child === null || child === undefined || child === false || child === true) {
566
+ return null;
567
+ }
568
+ if (child instanceof Node) {
569
+ parent.insertBefore(child, before);
570
+ return child;
571
+ }
572
+ if (Array.isArray(child)) {
573
+ const fragment = document.createDocumentFragment();
574
+ for (const item of child) {
575
+ insertChild(fragment, item);
576
+ }
577
+ parent.insertBefore(fragment, before);
578
+ return fragment;
579
+ }
580
+ if (isReactive(child)) {
581
+ const marker = document.createTextNode("");
582
+ parent.insertBefore(marker, before);
583
+ let childScope = null;
584
+ let currentNodes = [];
585
+ effect(() => {
586
+ const resolved = resolveValue(child);
587
+ if ((typeof resolved === "string" || typeof resolved === "number") && currentNodes.length === 1 && currentNodes[0].nodeType === Node.TEXT_NODE) {
588
+ currentNodes[0].data = String(resolved);
589
+ return;
590
+ }
591
+ if (childScope) {
592
+ childScope.dispose();
593
+ }
594
+ childScope = new Scope(getActiveScope());
595
+ runInScope(childScope, () => {
596
+ for (const node of currentNodes) {
597
+ if (node.parentNode) {
598
+ node.parentNode.removeChild(node);
599
+ }
600
+ }
601
+ currentNodes = [];
602
+ if (resolved === null || resolved === undefined || resolved === false) {
603
+ return;
604
+ }
605
+ const frag = document.createDocumentFragment();
606
+ if (typeof resolved === "string" || typeof resolved === "number" || typeof resolved === "boolean") {
607
+ frag.appendChild(document.createTextNode(String(resolved)));
608
+ } else {
609
+ insertChild(frag, resolved);
610
+ }
611
+ currentNodes = Array.from(frag.childNodes);
612
+ if (marker.parentNode) {
613
+ marker.parentNode.insertBefore(frag, marker);
614
+ }
615
+ });
616
+ });
617
+ onCleanup(() => {
618
+ if (childScope) {
619
+ childScope.dispose();
620
+ }
621
+ for (const node of currentNodes) {
622
+ if (node.parentNode) {
623
+ node.parentNode.removeChild(node);
624
+ }
625
+ }
626
+ if (marker.parentNode) {
627
+ marker.parentNode.removeChild(marker);
628
+ }
629
+ });
630
+ return marker;
631
+ }
632
+ const textNode = document.createTextNode(String(child));
633
+ parent.insertBefore(textNode, before);
634
+ return textNode;
635
+ }
636
+
637
+ // src/signals/scope.ts
638
+ class Scope {
639
+ subscribers = new Set;
640
+ cleanups = [];
641
+ parent = null;
642
+ isDisposed = false;
643
+ context;
644
+ constructor(parent = currentScope) {
645
+ this.parent = parent;
646
+ if (parent && !parent.isDisposed) {
647
+ parent.cleanups.push(() => this.dispose());
648
+ if (parent.context) {
649
+ this.context = new Map(parent.context);
650
+ }
651
+ }
652
+ }
653
+ addSubscriber(sub) {
654
+ if (this.isDisposed)
655
+ return;
656
+ this.subscribers.add(sub);
657
+ }
658
+ addCleanup(fn) {
659
+ if (this.isDisposed) {
660
+ fn();
661
+ return;
662
+ }
663
+ this.cleanups.push(fn);
664
+ }
665
+ dispose() {
666
+ if (this.isDisposed)
667
+ return;
668
+ this.isDisposed = true;
669
+ for (const sub of this.subscribers) {
670
+ sub.dispose();
671
+ }
672
+ this.subscribers.clear();
673
+ for (let i = this.cleanups.length - 1;i >= 0; i--) {
674
+ try {
675
+ this.cleanups[i]();
676
+ } catch (err) {
677
+ console.error("Error during cleanup:", err);
678
+ }
679
+ }
680
+ this.cleanups = [];
681
+ }
682
+ }
683
+ function onCleanup(fn) {
684
+ if (currentSubscriber && "addCleanup" in currentSubscriber) {
685
+ currentSubscriber.addCleanup(fn);
686
+ } else if (currentScope) {
687
+ currentScope.addCleanup(fn);
688
+ }
689
+ }
690
+ function createRoot(fn) {
691
+ const prevScope = currentScope;
692
+ const scope = new Scope(null);
693
+ setCurrentScope(scope);
694
+ try {
695
+ return fn(() => scope.dispose());
696
+ } finally {
697
+ setCurrentScope(prevScope);
698
+ }
699
+ }
700
+ function runInScope(scope, fn) {
701
+ const prevScope = currentScope;
702
+ setCurrentScope(scope);
703
+ try {
704
+ return fn();
705
+ } finally {
706
+ setCurrentScope(prevScope);
707
+ }
708
+ }
709
+ function getActiveScope() {
710
+ return getCurrentScope();
711
+ }
712
+
713
+ // src/signals/context.ts
714
+ function createContext(defaultValue) {
715
+ const id = Symbol("visage.context");
716
+ const context = {
717
+ id,
718
+ defaultValue,
719
+ Provider: (props) => {
720
+ const parentScope = getActiveScope();
721
+ const scope = new Scope(parentScope);
722
+ if (!scope.context) {
723
+ scope.context = new Map(parentScope?.context);
724
+ }
725
+ scope.context.set(id, props.value);
726
+ return runInScope(scope, () => {
727
+ const content = typeof props.children === "function" ? untrack(() => props.children()) : props.children;
728
+ if (typeof document !== "undefined") {
729
+ const frag = document.createDocumentFragment();
730
+ insertChild(frag, content);
731
+ return frag;
732
+ }
733
+ return content;
734
+ });
735
+ }
736
+ };
737
+ return context;
738
+ }
739
+ function useContext(context) {
740
+ let scope = getActiveScope();
741
+ while (scope) {
742
+ if (scope.context?.has(context.id)) {
743
+ return scope.context.get(context.id);
744
+ }
745
+ scope = scope.parent;
746
+ }
747
+ return context.defaultValue;
748
+ }
749
+ // src/signals/effect.ts
750
+ class Effect {
751
+ _fn;
752
+ sources = new Set;
753
+ sourceVersions = new Map;
754
+ cleanups = [];
755
+ state = 2 /* DIRTY */;
756
+ scope;
757
+ constructor(fn) {
758
+ this._fn = fn;
759
+ this.scope = currentScope;
760
+ if (currentScope) {
761
+ currentScope.addSubscriber(this);
762
+ }
763
+ this.run();
764
+ }
765
+ addCleanup(fn) {
766
+ this.cleanups.push(fn);
767
+ }
768
+ runCleanups() {
769
+ for (let i = this.cleanups.length - 1;i >= 0; i--) {
770
+ try {
771
+ this.cleanups[i]();
772
+ } catch (e) {
773
+ console.error("Error in effect cleanup:", e);
774
+ }
775
+ }
776
+ this.cleanups = [];
777
+ }
778
+ markDirty(targetState = 2 /* DIRTY */) {
779
+ if (this.state >= targetState || this.state === 3 /* DISPOSED */) {
780
+ return;
781
+ }
782
+ this.state = targetState;
783
+ addPendingEffect(this);
784
+ if (batchDepth === 0) {
785
+ flushEffects();
786
+ }
787
+ }
788
+ run() {
789
+ if (this.state === 3 /* DISPOSED */)
790
+ return;
791
+ if (this.state === 1 /* CHECK_DIRTY */) {
792
+ let isDirty = false;
793
+ for (const source of this.sources) {
794
+ if (source instanceof Computed) {
795
+ source.updateIfNecessary();
796
+ }
797
+ const lastVersion = this.sourceVersions.get(source);
798
+ if (lastVersion !== undefined && lastVersion !== source.version) {
799
+ isDirty = true;
800
+ }
801
+ }
802
+ if (!isDirty) {
803
+ this.state = 0 /* CLEAN */;
804
+ return;
805
+ }
806
+ }
807
+ this.runCleanups();
808
+ this.cleanupSources();
809
+ const prevSubscriber = currentSubscriber;
810
+ setCurrentSubscriber(this);
811
+ const prevScope = currentScope;
812
+ setCurrentScope(this.scope);
813
+ try {
814
+ this.state = 0 /* CLEAN */;
815
+ const res = this._fn();
816
+ if (typeof res === "function") {
817
+ this.cleanups.push(res);
818
+ }
819
+ } finally {
820
+ setCurrentSubscriber(prevSubscriber);
821
+ setCurrentScope(prevScope);
822
+ }
823
+ }
824
+ cleanupSources() {
825
+ for (const source of this.sources) {
826
+ source.removeSubscriber(this);
827
+ }
828
+ this.sources.clear();
829
+ this.sourceVersions.clear();
830
+ }
831
+ dispose() {
832
+ if (this.state === 3 /* DISPOSED */)
833
+ return;
834
+ this.state = 3 /* DISPOSED */;
835
+ this.runCleanups();
836
+ this.cleanupSources();
837
+ removePendingEffect(this);
838
+ }
839
+ }
840
+ function effect(fn) {
841
+ const eff = new Effect(fn);
842
+ return () => eff.dispose();
843
+ }
844
+ var createEffect = effect;
845
+ // src/signals/signal.ts
846
+ class Signal {
847
+ [SIGNAL_BRAND] = true;
848
+ _value;
849
+ _subscribers = new Set;
850
+ _equals;
851
+ version = 0;
852
+ constructor(initialValue, equals) {
853
+ this._value = initialValue;
854
+ this._equals = equals ?? Object.is;
855
+ }
856
+ get() {
857
+ if (currentSubscriber !== null && currentSubscriber.state !== 3 /* DISPOSED */) {
858
+ this._subscribers.add(currentSubscriber);
859
+ currentSubscriber.sources.add(this);
860
+ currentSubscriber.sourceVersions.set(this, this.version);
861
+ }
862
+ return this._value;
863
+ }
864
+ set(newValue) {
865
+ if (this._equals(this._value, newValue)) {
866
+ return;
867
+ }
868
+ if (currentSubscriber !== null && this._subscribers.has(currentSubscriber)) {
869
+ if (!warnedCyclicSubscribers.has(currentSubscriber)) {
870
+ warnedCyclicSubscribers.add(currentSubscriber);
871
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
872
+ console.warn(`[Visage Reactivity] Cyclic update detected: An active subscriber modified a signal that it depends on. ` + `To read a signal inside an effect/computed without creating a circular dependency, wrap the read in untrack():
873
+ ` + ` untrack(() => signal())`);
874
+ }
875
+ }
876
+ }
877
+ this._value = newValue;
878
+ this.version++;
879
+ batch(() => {
880
+ this.notify();
881
+ });
882
+ }
883
+ update(fn) {
884
+ this.set(fn(this._value));
885
+ }
886
+ get value() {
887
+ return this.get();
888
+ }
889
+ set value(val) {
890
+ this.set(val);
891
+ }
892
+ removeSubscriber(sub) {
893
+ this._subscribers.delete(sub);
894
+ }
895
+ notify() {
896
+ if (this._subscribers.size === 0)
897
+ return;
898
+ const subs = Array.from(this._subscribers);
899
+ for (const sub of subs) {
900
+ sub.markDirty(2 /* DIRTY */);
901
+ }
902
+ }
903
+ }
904
+ function signal(initialValue, optionsOrEquals) {
905
+ const equals = typeof optionsOrEquals === "function" ? optionsOrEquals : optionsOrEquals?.equals;
906
+ const isInternal = typeof optionsOrEquals === "object" ? optionsOrEquals?.internal : false;
907
+ const customName = typeof optionsOrEquals === "object" ? optionsOrEquals?.name : undefined;
908
+ const s = new Signal(initialValue, equals);
909
+ const accessor = (...args) => {
910
+ if (args.length === 0) {
911
+ return s.get();
912
+ }
913
+ s.set(args[0]);
914
+ return args[0];
915
+ };
916
+ Object.defineProperties(accessor, {
917
+ [SIGNAL_BRAND]: { value: true },
918
+ get: { value: () => s.get() },
919
+ set: { value: (v) => s.set(v) },
920
+ update: { value: (fn) => s.update(fn) },
921
+ value: {
922
+ get: () => s.get(),
923
+ set: (v) => s.set(v)
924
+ }
925
+ });
926
+ if (!isInternal && typeof window !== "undefined" && window.__VISAGE_DEVTOOLS__) {
927
+ const devtools = window.__VISAGE_DEVTOOLS__;
928
+ const sigId = devtools.registerSignal({
929
+ name: customName,
930
+ type: "signal",
931
+ getValue: () => s.get(),
932
+ version: () => s.version,
933
+ subscribersCount: () => s._subscribers?.size ?? 0,
934
+ dependents: () => Array.from(s._subscribers ?? []).map((sub) => sub._devId).filter(Boolean)
935
+ });
936
+ s._devId = sigId;
937
+ if (currentScope) {
938
+ currentScope.addCleanup(() => {
939
+ devtools.unregisterSignal(sigId);
940
+ });
941
+ }
942
+ }
943
+ return accessor;
944
+ }
945
+ function createSignal(initialValue, optionsOrEquals) {
946
+ const s = signal(initialValue, optionsOrEquals);
947
+ const setter = (value) => {
948
+ if (typeof value === "function") {
949
+ s.update(value);
950
+ } else {
951
+ s.set(value);
952
+ }
953
+ };
954
+ return [s, setter];
955
+ }
956
+ // src/signals/store.ts
957
+ var STORE_RAW = Symbol("visage.store.raw");
958
+ var STORE_SIGNALS = Symbol("visage.store.signals");
959
+ var STORE_PROXY = Symbol("visage.store.proxy");
960
+ function isObject(val) {
961
+ return typeof val === "object" && val !== null && (typeof Node === "undefined" || !(val instanceof Node)) && !isSignal(val);
962
+ }
963
+ function getOrCreatePropertySignal(target, prop) {
964
+ let signalsMap = target[STORE_SIGNALS];
965
+ if (!signalsMap) {
966
+ signalsMap = new Map;
967
+ Object.defineProperty(target, STORE_SIGNALS, {
968
+ value: signalsMap,
969
+ enumerable: false,
970
+ writable: true
971
+ });
972
+ }
973
+ let sig = signalsMap.get(prop);
974
+ if (!sig) {
975
+ sig = new Signal(target[prop]);
976
+ signalsMap.set(prop, sig);
977
+ }
978
+ return sig;
979
+ }
980
+ function createStoreProxy(target) {
981
+ if (!isObject(target))
982
+ return target;
983
+ if (target[STORE_PROXY])
984
+ return target[STORE_PROXY];
985
+ const proxy = new Proxy(target, {
986
+ get(target, prop, receiver) {
987
+ if (prop === STORE_RAW)
988
+ return target;
989
+ if (prop === STORE_PROXY)
990
+ return proxy;
991
+ if (typeof prop === "string" || typeof prop === "symbol") {
992
+ const sig = getOrCreatePropertySignal(target, prop);
993
+ sig.get();
994
+ }
995
+ const value = Reflect.get(target, prop, receiver);
996
+ if (isObject(value)) {
997
+ return createStoreProxy(value);
998
+ }
999
+ return value;
1000
+ },
1001
+ set(target, prop, value, receiver) {
1002
+ const prevValue = Reflect.get(target, prop, receiver);
1003
+ if (Object.is(prevValue, value)) {
1004
+ return true;
1005
+ }
1006
+ const success = Reflect.set(target, prop, value, receiver);
1007
+ if (success) {
1008
+ const sig = getOrCreatePropertySignal(target, prop);
1009
+ sig.set(value);
1010
+ if (Array.isArray(target) && prop !== "length") {
1011
+ const lenSig = getOrCreatePropertySignal(target, "length");
1012
+ lenSig.set(target.length);
1013
+ }
1014
+ }
1015
+ return success;
1016
+ },
1017
+ deleteProperty(target, prop) {
1018
+ const hadProp = Reflect.has(target, prop);
1019
+ const success = Reflect.deleteProperty(target, prop);
1020
+ if (hadProp && success) {
1021
+ const sig = getOrCreatePropertySignal(target, prop);
1022
+ sig.set(undefined);
1023
+ }
1024
+ return success;
1025
+ }
1026
+ });
1027
+ Object.defineProperty(target, STORE_PROXY, {
1028
+ value: proxy,
1029
+ enumerable: false,
1030
+ writable: true
1031
+ });
1032
+ return proxy;
1033
+ }
1034
+ function createStore(initialState) {
1035
+ if (!isObject(initialState)) {
1036
+ throw new Error("createStore requires an object or array as initial state");
1037
+ }
1038
+ return createStoreProxy(initialState);
1039
+ }
1040
+ function mutateStore(store, mutator) {
1041
+ batch(() => {
1042
+ mutator(store);
1043
+ });
1044
+ }
1045
+ function unwrapStore(store) {
1046
+ if (isObject(store) && store[STORE_RAW]) {
1047
+ return store[STORE_RAW];
1048
+ }
1049
+ return store;
1050
+ }
1051
+ // src/dom/control-flow.ts
1052
+ function Show(props) {
1053
+ if (typeof document === "undefined") {
1054
+ const condition = resolveValue(props.when);
1055
+ if (condition) {
1056
+ return typeof props.children === "function" && props.children.length > 0 ? props.children(() => resolveValue(props.when)) : typeof props.children === "function" ? props.children() : props.children;
1057
+ }
1058
+ return props.fallback ?? null;
1059
+ }
1060
+ const marker = document.createTextNode("");
1061
+ const initialFrag = document.createDocumentFragment();
1062
+ let currentScope = null;
1063
+ let currentContent = [];
1064
+ let isMounted = false;
1065
+ effect(() => {
1066
+ const condition = resolveValue(props.when);
1067
+ if (currentScope) {
1068
+ currentScope.dispose();
1069
+ currentScope = null;
1070
+ }
1071
+ for (const node of currentContent) {
1072
+ if (node.parentNode) {
1073
+ node.parentNode.removeChild(node);
1074
+ }
1075
+ }
1076
+ currentContent = [];
1077
+ const frag = document.createDocumentFragment();
1078
+ if (condition) {
1079
+ currentScope = new Scope(getActiveScope());
1080
+ untrack(() => {
1081
+ runInScope(currentScope, () => {
1082
+ const childRes = typeof props.children === "function" && props.children.length > 0 ? props.children(() => resolveValue(props.when)) : typeof props.children === "function" ? props.children() : props.children;
1083
+ insertChild(frag, childRes);
1084
+ });
1085
+ });
1086
+ } else if (props.fallback !== undefined) {
1087
+ currentScope = new Scope(getActiveScope());
1088
+ untrack(() => {
1089
+ runInScope(currentScope, () => {
1090
+ insertChild(frag, props.fallback);
1091
+ });
1092
+ });
1093
+ }
1094
+ currentContent = Array.from(frag.childNodes);
1095
+ if (marker.parentNode) {
1096
+ marker.parentNode.insertBefore(frag, marker);
1097
+ } else if (!isMounted) {
1098
+ initialFrag.appendChild(frag);
1099
+ }
1100
+ });
1101
+ isMounted = true;
1102
+ initialFrag.appendChild(marker);
1103
+ onCleanup(() => {
1104
+ if (currentScope) {
1105
+ currentScope.dispose();
1106
+ }
1107
+ });
1108
+ return initialFrag;
1109
+ }
1110
+ function For(props) {
1111
+ if (typeof document === "undefined") {
1112
+ const list = resolveValue(props.each) ?? [];
1113
+ if (list.length === 0) {
1114
+ return props.fallback ?? null;
1115
+ }
1116
+ return list.map((item, idx) => props.children(item, () => idx));
1117
+ }
1118
+ const marker = document.createTextNode("");
1119
+ const initialFrag = document.createDocumentFragment();
1120
+ let items = [];
1121
+ let fallbackScope = null;
1122
+ let fallbackNodes = [];
1123
+ let isMounted = false;
1124
+ effect(() => {
1125
+ const list = resolveValue(props.each) ?? [];
1126
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
1127
+ if (list.length === 0) {
1128
+ for (const rec of items) {
1129
+ rec.scope.dispose();
1130
+ for (const node of rec.nodes) {
1131
+ if (node.parentNode)
1132
+ node.parentNode.removeChild(node);
1133
+ }
1134
+ }
1135
+ items = [];
1136
+ if (props.fallback !== undefined && fallbackNodes.length === 0 && parent) {
1137
+ fallbackScope = new Scope(getActiveScope());
1138
+ untrack(() => {
1139
+ runInScope(fallbackScope, () => {
1140
+ const frag = document.createDocumentFragment();
1141
+ insertChild(frag, props.fallback);
1142
+ fallbackNodes = Array.from(frag.childNodes);
1143
+ if (marker.parentNode) {
1144
+ marker.parentNode.insertBefore(frag, marker);
1145
+ } else if (!isMounted) {
1146
+ initialFrag.appendChild(frag);
1147
+ }
1148
+ });
1149
+ });
1150
+ }
1151
+ return;
1152
+ }
1153
+ if (fallbackNodes.length > 0) {
1154
+ if (fallbackScope) {
1155
+ fallbackScope.dispose();
1156
+ fallbackScope = null;
1157
+ }
1158
+ for (const node of fallbackNodes) {
1159
+ if (node.parentNode)
1160
+ node.parentNode.removeChild(node);
1161
+ }
1162
+ fallbackNodes = [];
1163
+ }
1164
+ if (!parent)
1165
+ return;
1166
+ const newItems = [];
1167
+ const prevMap = new Map;
1168
+ for (const rec of items) {
1169
+ prevMap.set(rec.item, rec);
1170
+ }
1171
+ for (let i = 0;i < list.length; i++) {
1172
+ const item = list[i];
1173
+ const existing = prevMap.get(item);
1174
+ if (existing) {
1175
+ existing.indexSignal(i);
1176
+ newItems.push(existing);
1177
+ prevMap.delete(item);
1178
+ } else {
1179
+ let indexVal = i;
1180
+ const indexSubscribers = new Set;
1181
+ const indexSignal = (...args) => {
1182
+ if (args.length > 0 && args[0] !== undefined && args[0] !== indexVal) {
1183
+ indexVal = args[0];
1184
+ for (const sub of Array.from(indexSubscribers))
1185
+ sub();
1186
+ }
1187
+ return indexVal;
1188
+ };
1189
+ const itemScope = new Scope(getActiveScope());
1190
+ let itemNodes = [];
1191
+ untrack(() => {
1192
+ runInScope(itemScope, () => {
1193
+ const frag = document.createDocumentFragment();
1194
+ const child = props.children(item, indexSignal);
1195
+ insertChild(frag, child);
1196
+ itemNodes = Array.from(frag.childNodes);
1197
+ });
1198
+ });
1199
+ newItems.push({
1200
+ item,
1201
+ scope: itemScope,
1202
+ nodes: itemNodes,
1203
+ indexSignal
1204
+ });
1205
+ }
1206
+ }
1207
+ for (const [, removed] of prevMap) {
1208
+ removed.scope.dispose();
1209
+ for (const node of removed.nodes) {
1210
+ if (node.parentNode)
1211
+ node.parentNode.removeChild(node);
1212
+ }
1213
+ }
1214
+ if (marker.parentNode) {
1215
+ let currentMarker = marker;
1216
+ for (let i = newItems.length - 1;i >= 0; i--) {
1217
+ const rec = newItems[i];
1218
+ for (let j = rec.nodes.length - 1;j >= 0; j--) {
1219
+ const node = rec.nodes[j];
1220
+ if (node.nextSibling !== currentMarker) {
1221
+ marker.parentNode.insertBefore(node, currentMarker);
1222
+ }
1223
+ currentMarker = node;
1224
+ }
1225
+ }
1226
+ } else if (!isMounted) {
1227
+ for (const rec of newItems) {
1228
+ for (const node of rec.nodes) {
1229
+ initialFrag.appendChild(node);
1230
+ }
1231
+ }
1232
+ }
1233
+ items = newItems;
1234
+ });
1235
+ isMounted = true;
1236
+ initialFrag.appendChild(marker);
1237
+ onCleanup(() => {
1238
+ for (const rec of items) {
1239
+ rec.scope.dispose();
1240
+ }
1241
+ if (fallbackScope) {
1242
+ fallbackScope.dispose();
1243
+ }
1244
+ });
1245
+ return initialFrag;
1246
+ }
1247
+ function Portal(props) {
1248
+ if (typeof document === "undefined") {
1249
+ return null;
1250
+ }
1251
+ const marker = document.createTextNode("");
1252
+ let currentScope = null;
1253
+ let nodes = [];
1254
+ effect(() => {
1255
+ const target = props.mount ?? (typeof document !== "undefined" ? document.body : null);
1256
+ if (!target)
1257
+ return;
1258
+ if (currentScope) {
1259
+ currentScope.dispose();
1260
+ currentScope = null;
1261
+ }
1262
+ for (const node of nodes) {
1263
+ if (node.parentNode) {
1264
+ node.parentNode.removeChild(node);
1265
+ }
1266
+ }
1267
+ nodes = [];
1268
+ currentScope = new Scope(getActiveScope());
1269
+ untrack(() => {
1270
+ runInScope(currentScope, () => {
1271
+ const childRes = typeof props.children === "function" ? props.children() : props.children;
1272
+ const frag = document.createDocumentFragment();
1273
+ insertChild(frag, childRes);
1274
+ nodes = Array.from(frag.childNodes);
1275
+ target.appendChild(frag);
1276
+ });
1277
+ });
1278
+ });
1279
+ onCleanup(() => {
1280
+ if (currentScope) {
1281
+ currentScope.dispose();
1282
+ currentScope = null;
1283
+ }
1284
+ for (const node of nodes) {
1285
+ if (node.parentNode) {
1286
+ node.parentNode.removeChild(node);
1287
+ }
1288
+ }
1289
+ nodes = [];
1290
+ });
1291
+ return marker;
1292
+ }
1293
+
1294
+ // src/ui/utils.ts
1295
+ var idCounter = 0;
1296
+ function createId(prefix = "visage") {
1297
+ return `${prefix}-${++idCounter}`;
1298
+ }
1299
+ function createControllableSignal(options) {
1300
+ const isControlled = typeof options.value === "function";
1301
+ const internal = signal(options.defaultValue, { internal: true });
1302
+ const getter = computed(() => {
1303
+ if (isControlled) {
1304
+ const externalVal = options.value();
1305
+ if (externalVal !== undefined)
1306
+ return externalVal;
1307
+ }
1308
+ return internal();
1309
+ }, { internal: true });
1310
+ const setter = (next) => {
1311
+ const currentVal = getter();
1312
+ const nextVal = typeof next === "function" ? next(currentVal) : next;
1313
+ if (!isControlled) {
1314
+ internal.set(nextVal);
1315
+ }
1316
+ if (options.onChange && nextVal !== currentVal) {
1317
+ options.onChange(nextVal);
1318
+ }
1319
+ };
1320
+ return [getter, setter];
1321
+ }
1322
+ function trapFocus(container, event) {
1323
+ if (event.key !== "Tab")
1324
+ return;
1325
+ const focusables = container.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])');
1326
+ if (focusables.length === 0) {
1327
+ event.preventDefault();
1328
+ return;
1329
+ }
1330
+ const first = focusables[0];
1331
+ const last = focusables[focusables.length - 1];
1332
+ if (event.shiftKey) {
1333
+ if (document.activeElement === first) {
1334
+ last.focus();
1335
+ event.preventDefault();
1336
+ }
1337
+ } else {
1338
+ if (document.activeElement === last) {
1339
+ first.focus();
1340
+ event.preventDefault();
1341
+ }
1342
+ }
1343
+ }
1344
+ function onClickOutside(elements, handler) {
1345
+ const listener = (event) => {
1346
+ const target = event.target;
1347
+ if (!target)
1348
+ return;
1349
+ const list = Array.isArray(elements) ? elements : [elements];
1350
+ const isInside = list.some((el) => el?.contains(target));
1351
+ if (!isInside) {
1352
+ handler(event);
1353
+ }
1354
+ };
1355
+ if (typeof document !== "undefined") {
1356
+ document.addEventListener("mousedown", listener, true);
1357
+ document.addEventListener("touchstart", listener, true);
1358
+ }
1359
+ return () => {
1360
+ if (typeof document !== "undefined") {
1361
+ document.removeEventListener("mousedown", listener, true);
1362
+ document.removeEventListener("touchstart", listener, true);
1363
+ }
1364
+ };
1365
+ }
1366
+
1367
+ // src/dom/resource.ts
1368
+ var SuspenseContext = createContext(null);
1369
+ function createResource(sourceOrFetcher, maybeFetcher) {
1370
+ const isDirect = typeof maybeFetcher !== "function";
1371
+ const fetcher = isDirect ? sourceOrFetcher : maybeFetcher;
1372
+ const source = isDirect ? null : sourceOrFetcher;
1373
+ const data = signal(undefined);
1374
+ const loading = signal(true);
1375
+ const error = signal(null);
1376
+ let currentPromise = null;
1377
+ let requestId = 0;
1378
+ const load = async (arg) => {
1379
+ const currentReq = ++requestId;
1380
+ loading.set(true);
1381
+ error.set(null);
1382
+ const promise = isDirect ? fetcher() : fetcher(arg);
1383
+ currentPromise = promise;
1384
+ const suspense = useContext(SuspenseContext);
1385
+ if (suspense) {
1386
+ suspense.registerPromise(promise);
1387
+ }
1388
+ try {
1389
+ const res = await promise;
1390
+ if (currentReq === requestId) {
1391
+ data.set(res);
1392
+ loading.set(false);
1393
+ currentPromise = null;
1394
+ }
1395
+ return res;
1396
+ } catch (err) {
1397
+ if (currentReq === requestId) {
1398
+ error.set(err);
1399
+ loading.set(false);
1400
+ currentPromise = null;
1401
+ }
1402
+ throw err;
1403
+ }
1404
+ };
1405
+ if (source) {
1406
+ effect(() => {
1407
+ const sourceVal = resolveValue(source);
1408
+ if (sourceVal !== false && sourceVal !== null && sourceVal !== undefined) {
1409
+ load(sourceVal).catch(() => {});
1410
+ }
1411
+ });
1412
+ } else {
1413
+ load().catch(() => {});
1414
+ }
1415
+ const accessor = () => {
1416
+ if (loading() && currentPromise) {
1417
+ const suspense = useContext(SuspenseContext);
1418
+ if (suspense) {
1419
+ suspense.registerPromise(currentPromise);
1420
+ }
1421
+ }
1422
+ return data();
1423
+ };
1424
+ Object.defineProperties(accessor, {
1425
+ loading: { get: () => loading },
1426
+ error: { get: () => error },
1427
+ mutate: { value: (val) => data.set(val) },
1428
+ refetch: { value: () => source ? load(resolveValue(source)) : load() }
1429
+ });
1430
+ return accessor;
1431
+ }
1432
+
1433
+ // src/dom/lazy.ts
1434
+ function lazy(importer) {
1435
+ let loadedComponent = null;
1436
+ let loadingPromise = null;
1437
+ const preload = () => {
1438
+ if (loadedComponent) {
1439
+ return Promise.resolve(loadedComponent);
1440
+ }
1441
+ if (!loadingPromise) {
1442
+ loadingPromise = importer().then((mod) => {
1443
+ const comp = mod && typeof mod === "object" && "default" in mod ? mod.default : mod;
1444
+ loadedComponent = comp;
1445
+ return comp;
1446
+ }).catch((err) => {
1447
+ loadingPromise = null;
1448
+ throw err;
1449
+ });
1450
+ }
1451
+ return loadingPromise;
1452
+ };
1453
+ const LazyWrapper = (props) => {
1454
+ if (loadedComponent) {
1455
+ return loadedComponent(props);
1456
+ }
1457
+ const promise = preload();
1458
+ const suspense = useContext(SuspenseContext);
1459
+ if (suspense) {
1460
+ suspense.registerPromise(promise);
1461
+ }
1462
+ const res = createResource(() => promise);
1463
+ return () => {
1464
+ const Comp = res();
1465
+ return Comp ? Comp(props) : null;
1466
+ };
1467
+ };
1468
+ LazyWrapper.preload = preload;
1469
+ return LazyWrapper;
1470
+ }
1471
+ // src/dom/async.ts
1472
+ function Suspense(props) {
1473
+ if (typeof document === "undefined") {
1474
+ return typeof props.children === "function" ? props.children() : props.children;
1475
+ }
1476
+ const marker = document.createTextNode("");
1477
+ const initialFrag = document.createDocumentFragment();
1478
+ const pendingCount = signal(0);
1479
+ let currentScope = null;
1480
+ let currentNodes = [];
1481
+ let isMounted = false;
1482
+ const suspenseValue = {
1483
+ registerPromise(p) {
1484
+ pendingCount.update((c) => c + 1);
1485
+ p.finally(() => {
1486
+ pendingCount.update((c) => Math.max(0, c - 1));
1487
+ });
1488
+ }
1489
+ };
1490
+ const renderContent = (content) => {
1491
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
1492
+ if (!parent)
1493
+ return;
1494
+ for (const n of currentNodes) {
1495
+ if (n.parentNode)
1496
+ n.parentNode.removeChild(n);
1497
+ }
1498
+ currentNodes = [];
1499
+ const frag = document.createDocumentFragment();
1500
+ insertChild(frag, content);
1501
+ currentNodes = Array.from(frag.childNodes);
1502
+ if (marker.parentNode) {
1503
+ marker.parentNode.insertBefore(frag, marker);
1504
+ } else if (!isMounted) {
1505
+ initialFrag.appendChild(frag);
1506
+ }
1507
+ };
1508
+ effect(() => {
1509
+ if (currentScope) {
1510
+ currentScope.dispose();
1511
+ currentScope = null;
1512
+ }
1513
+ currentScope = new Scope(getActiveScope());
1514
+ runInScope(currentScope, () => {
1515
+ let threwPromise = null;
1516
+ let rendered = null;
1517
+ try {
1518
+ const SuspenseProvider = SuspenseContext.Provider;
1519
+ rendered = SuspenseProvider({
1520
+ value: suspenseValue,
1521
+ children: props.children
1522
+ });
1523
+ } catch (err) {
1524
+ if (err && typeof err.then === "function") {
1525
+ threwPromise = err;
1526
+ suspenseValue.registerPromise(err);
1527
+ } else {
1528
+ throw err;
1529
+ }
1530
+ }
1531
+ if (pendingCount() > 0 || threwPromise) {
1532
+ renderContent(props.fallback);
1533
+ } else {
1534
+ renderContent(rendered);
1535
+ }
1536
+ });
1537
+ });
1538
+ isMounted = true;
1539
+ initialFrag.appendChild(marker);
1540
+ onCleanup(() => {
1541
+ if (currentScope)
1542
+ currentScope.dispose();
1543
+ });
1544
+ return initialFrag;
1545
+ }
1546
+ function ErrorBoundary(props) {
1547
+ if (typeof document === "undefined") {
1548
+ try {
1549
+ return typeof props.children === "function" ? props.children() : props.children;
1550
+ } catch (err) {
1551
+ return typeof props.fallback === "function" ? props.fallback(err, () => {}) : props.fallback;
1552
+ }
1553
+ }
1554
+ const marker = document.createTextNode("");
1555
+ const initialFrag = document.createDocumentFragment();
1556
+ const currentError = signal(null);
1557
+ let currentScope = null;
1558
+ let currentNodes = [];
1559
+ let isMounted = false;
1560
+ const reset = () => {
1561
+ currentError.set(null);
1562
+ };
1563
+ const renderNodes = (child) => {
1564
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
1565
+ if (!parent)
1566
+ return;
1567
+ for (const n of currentNodes) {
1568
+ if (n.parentNode)
1569
+ n.parentNode.removeChild(n);
1570
+ }
1571
+ currentNodes = [];
1572
+ const frag = document.createDocumentFragment();
1573
+ insertChild(frag, child);
1574
+ currentNodes = Array.from(frag.childNodes);
1575
+ if (marker.parentNode) {
1576
+ marker.parentNode.insertBefore(frag, marker);
1577
+ } else if (!isMounted) {
1578
+ initialFrag.appendChild(frag);
1579
+ }
1580
+ };
1581
+ effect(() => {
1582
+ const err = currentError();
1583
+ if (currentScope) {
1584
+ currentScope.dispose();
1585
+ currentScope = null;
1586
+ }
1587
+ currentScope = new Scope(getActiveScope());
1588
+ runInScope(currentScope, () => {
1589
+ if (err !== null) {
1590
+ const fallbackNode = typeof props.fallback === "function" ? props.fallback(err, reset) : props.fallback;
1591
+ renderNodes(fallbackNode);
1592
+ } else {
1593
+ try {
1594
+ const content = typeof props.children === "function" ? props.children() : props.children;
1595
+ renderNodes(content);
1596
+ } catch (catchedErr) {
1597
+ currentError.set(catchedErr);
1598
+ }
1599
+ }
1600
+ });
1601
+ });
1602
+ isMounted = true;
1603
+ initialFrag.appendChild(marker);
1604
+ onCleanup(() => {
1605
+ if (currentScope)
1606
+ currentScope.dispose();
1607
+ });
1608
+ return initialFrag;
1609
+ }
1610
+ // src/jsx-runtime/index.ts
1611
+ var SVG_NS = "http://www.w3.org/2000/svg";
1612
+ var SVG_TAGS = new Set([
1613
+ "svg",
1614
+ "path",
1615
+ "circle",
1616
+ "rect",
1617
+ "g",
1618
+ "line",
1619
+ "polyline",
1620
+ "polygon",
1621
+ "text",
1622
+ "defs",
1623
+ "clipPath",
1624
+ "linearGradient",
1625
+ "radialGradient",
1626
+ "stop"
1627
+ ]);
1628
+ function Fragment(props) {
1629
+ if (typeof document === "undefined") {
1630
+ return props.children !== undefined ? props.children : [];
1631
+ }
1632
+ const fragment = document.createDocumentFragment();
1633
+ if (props.children !== undefined) {
1634
+ insertChild(fragment, props.children);
1635
+ }
1636
+ return fragment;
1637
+ }
1638
+ function jsx(type, props = {}, key) {
1639
+ if (typeof type === "function") {
1640
+ return type(props, key);
1641
+ }
1642
+ if (typeof type === "string") {
1643
+ const { children, ...restProps } = props;
1644
+ if (typeof document === "undefined") {
1645
+ const attributes = new Map;
1646
+ for (const propName in restProps) {
1647
+ const val = restProps[propName];
1648
+ if (propName === "className" || propName === "class") {
1649
+ const resolved = typeof val === "function" ? val() : val;
1650
+ if (resolved)
1651
+ attributes.set("class", resolved);
1652
+ } else if (propName === "style") {
1653
+ const val = restProps[propName];
1654
+ const resolved = resolveValue(val);
1655
+ if (typeof resolved === "string") {
1656
+ attributes.set("style", resolved);
1657
+ } else if (typeof resolved === "object" && resolved !== null) {
1658
+ const styleStr = Object.entries(resolved).map(([k, v]) => {
1659
+ const finalVal = resolveValue(v);
1660
+ const formatted = formatStyleProp(k, finalVal);
1661
+ if (!formatted)
1662
+ return "";
1663
+ const kebab = k.startsWith("--") ? k : k.replace(/([A-Z])/g, "-$1").toLowerCase();
1664
+ return `${kebab}: ${formatted}`;
1665
+ }).filter(Boolean).join("; ");
1666
+ if (styleStr)
1667
+ attributes.set("style", styleStr);
1668
+ }
1669
+ } else if (!propName.startsWith("on")) {
1670
+ const resolved = typeof val === "function" ? val() : val;
1671
+ if (resolved === true) {
1672
+ attributes.set(propName, propName);
1673
+ } else if (resolved !== false && resolved !== null && resolved !== undefined) {
1674
+ attributes.set(propName, resolved);
1675
+ }
1676
+ }
1677
+ }
1678
+ const childNodes = children !== undefined ? Array.isArray(children) ? children : [children] : [];
1679
+ return {
1680
+ tagName: type,
1681
+ attributes,
1682
+ childNodes
1683
+ };
1684
+ }
1685
+ const isSvg = SVG_TAGS.has(type);
1686
+ const element = isSvg ? document.createElementNS(SVG_NS, type) : document.createElement(type);
1687
+ for (const propName in restProps) {
1688
+ setAttribute(element, propName, restProps[propName]);
1689
+ }
1690
+ if (children !== undefined) {
1691
+ insertChild(element, children);
1692
+ }
1693
+ return element;
1694
+ }
1695
+ return type;
1696
+ }
1697
+ var jsxs = jsx;
1698
+ var jsxDEV = jsx;
1699
+
1700
+ // src/ui/accordion.tsx
1701
+ var AccordionContext = createContext(null);
1702
+ function useAccordionContext() {
1703
+ return useContext(AccordionContext);
1704
+ }
1705
+ function AccordionRoot(props) {
1706
+ const isSingle = props.type === "single";
1707
+ const collapsible = props.collapsible ?? !isSingle;
1708
+ const [singleValue, setSingleValue] = createControllableSignal({
1709
+ value: isSingle ? props.value : undefined,
1710
+ defaultValue: isSingle ? props.defaultValue ?? "" : "",
1711
+ onChange: isSingle ? props.onValueChange : undefined
1712
+ });
1713
+ const [multiValue, setMultiValue] = createControllableSignal({
1714
+ value: !isSingle ? props.value : undefined,
1715
+ defaultValue: !isSingle ? props.defaultValue ?? [] : [],
1716
+ onChange: !isSingle ? props.onValueChange : undefined
1717
+ });
1718
+ const isExpanded = (val) => {
1719
+ if (isSingle) {
1720
+ return singleValue() === val;
1721
+ }
1722
+ return multiValue().includes(val);
1723
+ };
1724
+ const toggleItem = (val) => {
1725
+ if (isSingle) {
1726
+ if (singleValue() === val) {
1727
+ if (collapsible) {
1728
+ setSingleValue("");
1729
+ }
1730
+ } else {
1731
+ setSingleValue(val);
1732
+ }
1733
+ } else {
1734
+ const current = multiValue();
1735
+ if (current.includes(val)) {
1736
+ setMultiValue(current.filter((item) => item !== val));
1737
+ } else {
1738
+ setMultiValue([...current, val]);
1739
+ }
1740
+ }
1741
+ };
1742
+ const ctx = {
1743
+ isExpanded,
1744
+ toggleItem,
1745
+ type: props.type,
1746
+ collapsible
1747
+ };
1748
+ const {
1749
+ as: Tag = "div",
1750
+ items,
1751
+ itemClass,
1752
+ triggerClass,
1753
+ contentClass,
1754
+ children,
1755
+ class: className,
1756
+ style,
1757
+ ...rest
1758
+ } = props;
1759
+ return AccordionContext.Provider({
1760
+ value: ctx,
1761
+ children: () => /* @__PURE__ */ jsxs(Tag, {
1762
+ class: className,
1763
+ style,
1764
+ ...rest,
1765
+ children: [
1766
+ items ? items.map((item) => /* @__PURE__ */ jsx(AccordionItem, {
1767
+ value: item.value,
1768
+ disabled: item.disabled,
1769
+ class: itemClass,
1770
+ children: () => /* @__PURE__ */ jsxs(Fragment, {
1771
+ children: [
1772
+ /* @__PURE__ */ jsx(AccordionTrigger, {
1773
+ class: triggerClass,
1774
+ children: typeof item.trigger === "function" ? item.trigger() : item.trigger
1775
+ }),
1776
+ /* @__PURE__ */ jsx(AccordionContent, {
1777
+ class: contentClass,
1778
+ children: typeof item.content === "function" ? item.content() : item.content
1779
+ })
1780
+ ]
1781
+ })
1782
+ })) : null,
1783
+ typeof children === "function" ? children() : children
1784
+ ]
1785
+ })
1786
+ });
1787
+ }
1788
+ var AccordionItemContext = createContext(null);
1789
+ function useAccordionItemContext() {
1790
+ return useContext(AccordionItemContext);
1791
+ }
1792
+ function AccordionItem(props) {
1793
+ const itemId = createId("accordion-item");
1794
+ const ctx = {
1795
+ value: props.value,
1796
+ itemId
1797
+ };
1798
+ const accordion = useContext(AccordionContext);
1799
+ const isOpen = () => accordion ? accordion.isExpanded(props.value) : false;
1800
+ const { value, disabled, as: Tag = "div", children, class: className, style, ...rest } = props;
1801
+ return AccordionItemContext.Provider({
1802
+ value: ctx,
1803
+ children: () => /* @__PURE__ */ jsx(Tag, {
1804
+ "data-state": () => isOpen() ? "open" : "closed",
1805
+ "data-disabled": disabled,
1806
+ class: className,
1807
+ style,
1808
+ ...rest,
1809
+ children: typeof children === "function" ? children() : children
1810
+ })
1811
+ });
1812
+ }
1813
+ function AccordionTrigger(props) {
1814
+ const accordion = useContext(AccordionContext);
1815
+ const item = useContext(AccordionItemContext);
1816
+ const isOpen = () => accordion && item ? accordion.isExpanded(item.value) : false;
1817
+ const handleClick = (e) => {
1818
+ if (props.onClick)
1819
+ props.onClick(e);
1820
+ if (!e.defaultPrevented && accordion && item) {
1821
+ accordion.toggleItem(item.value);
1822
+ }
1823
+ };
1824
+ const { as: Tag = "button", children, onClick, class: className, style, ...rest } = props;
1825
+ return /* @__PURE__ */ jsx(Tag, {
1826
+ id: item ? `${item.itemId}-trigger` : undefined,
1827
+ type: Tag === "button" ? "button" : undefined,
1828
+ "aria-expanded": isOpen,
1829
+ "aria-controls": item ? `${item.itemId}-content` : undefined,
1830
+ "data-state": () => isOpen() ? "open" : "closed",
1831
+ class: className,
1832
+ style,
1833
+ onClick: handleClick,
1834
+ ...rest,
1835
+ children
1836
+ });
1837
+ }
1838
+ function AccordionContent(props) {
1839
+ const accordion = useContext(AccordionContext);
1840
+ const item = useContext(AccordionItemContext);
1841
+ const isOpen = () => accordion && item ? accordion.isExpanded(item.value) : false;
1842
+ const { forceMount, as: Tag = "div", children, class: className, style, ...rest } = props;
1843
+ if (forceMount) {
1844
+ return /* @__PURE__ */ jsx(Tag, {
1845
+ id: item ? `${item.itemId}-content` : undefined,
1846
+ role: "region",
1847
+ "aria-labelledby": item ? `${item.itemId}-trigger` : undefined,
1848
+ "data-state": () => isOpen() ? "open" : "closed",
1849
+ hidden: () => !isOpen(),
1850
+ class: className,
1851
+ style,
1852
+ ...rest,
1853
+ children
1854
+ });
1855
+ }
1856
+ return /* @__PURE__ */ jsx(Show, {
1857
+ when: isOpen,
1858
+ children: /* @__PURE__ */ jsx(Tag, {
1859
+ id: item ? `${item.itemId}-content` : undefined,
1860
+ role: "region",
1861
+ "aria-labelledby": item ? `${item.itemId}-trigger` : undefined,
1862
+ "data-state": "open",
1863
+ class: className,
1864
+ style,
1865
+ ...rest,
1866
+ children
1867
+ })
1868
+ });
1869
+ }
1870
+ var Accordion = Object.assign(AccordionRoot, {
1871
+ Root: AccordionRoot,
1872
+ Item: AccordionItem,
1873
+ Trigger: AccordionTrigger,
1874
+ Content: AccordionContent
1875
+ });
1876
+ // src/ui/command-dialog.tsx
1877
+ function CommandDialog(props) {
1878
+ const [open, setOpen] = createControllableSignal({
1879
+ value: props.open,
1880
+ defaultValue: props.defaultOpen ?? false,
1881
+ onChange: props.onOpenChange
1882
+ });
1883
+ const { overlayClass, contentClass, style, ...rest } = props;
1884
+ return /* @__PURE__ */ jsx(Portal, {
1885
+ children: /* @__PURE__ */ jsx("div", {
1886
+ style: () => ({
1887
+ display: open() ? "flex" : "none",
1888
+ position: "fixed",
1889
+ inset: 0,
1890
+ background: "rgba(0, 0, 0, 0.6)",
1891
+ backdropFilter: "blur(4px)",
1892
+ alignItems: "flex-start",
1893
+ justifyContent: "center",
1894
+ paddingTop: "15vh",
1895
+ zIndex: 9999
1896
+ }),
1897
+ class: overlayClass,
1898
+ onClick: (e) => {
1899
+ if (e.target === e.currentTarget)
1900
+ setOpen(false);
1901
+ },
1902
+ children: /* @__PURE__ */ jsx("div", {
1903
+ style: { width: "100%", maxWidth: "560px" },
1904
+ class: contentClass,
1905
+ children: /* @__PURE__ */ jsx(CommandRoot, {
1906
+ ...rest
1907
+ })
1908
+ })
1909
+ })
1910
+ });
1911
+ }
1912
+
1913
+ // src/ui/command.tsx
1914
+ var CommandContext = createContext(null);
1915
+ function useCommandContext() {
1916
+ return useContext(CommandContext);
1917
+ }
1918
+ function CommandRoot(props) {
1919
+ const [search, setSearch] = createControllableSignal({
1920
+ value: props.search,
1921
+ defaultValue: "",
1922
+ onChange: props.onSearchChange
1923
+ });
1924
+ const [activeValue, setActiveValue] = createControllableSignal({
1925
+ value: props.value,
1926
+ defaultValue: props.defaultValue ?? "",
1927
+ onChange: props.onValueChange
1928
+ });
1929
+ const commandId = createId("command");
1930
+ const filterMatches = (text, keywords) => {
1931
+ const q = search().toLowerCase().trim();
1932
+ if (!q)
1933
+ return true;
1934
+ if (text.toLowerCase().includes(q))
1935
+ return true;
1936
+ if (keywords?.some((k) => k.toLowerCase().includes(q)))
1937
+ return true;
1938
+ return false;
1939
+ };
1940
+ const ctx = {
1941
+ search,
1942
+ setSearch,
1943
+ activeValue,
1944
+ setActiveValue,
1945
+ filterMatches,
1946
+ commandId
1947
+ };
1948
+ const {
1949
+ as: Tag = "div",
1950
+ placeholder = "Type a command or search...",
1951
+ groups,
1952
+ items,
1953
+ emptyText = "No results found.",
1954
+ class: className,
1955
+ style,
1956
+ inputClass,
1957
+ listClass,
1958
+ itemClass,
1959
+ children,
1960
+ ...rest
1961
+ } = props;
1962
+ if (groups || items) {
1963
+ return CommandContext.Provider({
1964
+ value: ctx,
1965
+ children: () => /* @__PURE__ */ jsxs(Tag, {
1966
+ class: className,
1967
+ style: { display: "flex", flexDirection: "column", overflow: "hidden", ...style },
1968
+ ...rest,
1969
+ children: [
1970
+ /* @__PURE__ */ jsx(CommandInput, {
1971
+ placeholder,
1972
+ class: inputClass
1973
+ }),
1974
+ /* @__PURE__ */ jsxs(CommandList, {
1975
+ class: listClass,
1976
+ children: [
1977
+ /* @__PURE__ */ jsx(CommandEmpty, {
1978
+ children: emptyText
1979
+ }),
1980
+ groups?.map((grp) => /* @__PURE__ */ jsx(CommandGroup, {
1981
+ heading: grp.heading,
1982
+ children: grp.items.map((item) => /* @__PURE__ */ jsxs(CommandItem, {
1983
+ value: item.value,
1984
+ shortcut: item.shortcut,
1985
+ disabled: item.disabled,
1986
+ onSelect: item.onSelect,
1987
+ keywords: item.keywords,
1988
+ class: item.class ?? itemClass,
1989
+ children: [
1990
+ item.icon ? /* @__PURE__ */ jsx("span", {
1991
+ style: { display: "inline-flex", alignItems: "center", marginRight: "8px" },
1992
+ children: typeof item.icon === "function" ? item.icon() : item.icon
1993
+ }) : null,
1994
+ typeof item.label === "function" ? item.label() : item.label
1995
+ ]
1996
+ }))
1997
+ })),
1998
+ items?.map((item) => /* @__PURE__ */ jsxs(CommandItem, {
1999
+ value: item.value,
2000
+ shortcut: item.shortcut,
2001
+ disabled: item.disabled,
2002
+ onSelect: item.onSelect,
2003
+ keywords: item.keywords,
2004
+ class: item.class ?? itemClass,
2005
+ children: [
2006
+ item.icon ? /* @__PURE__ */ jsx("span", {
2007
+ style: { display: "inline-flex", alignItems: "center", marginRight: "8px" },
2008
+ children: typeof item.icon === "function" ? item.icon() : item.icon
2009
+ }) : null,
2010
+ typeof item.label === "function" ? item.label() : item.label
2011
+ ]
2012
+ })),
2013
+ typeof children === "function" ? children() : children
2014
+ ]
2015
+ })
2016
+ ]
2017
+ })
2018
+ });
2019
+ }
2020
+ return CommandContext.Provider({
2021
+ value: ctx,
2022
+ children: () => /* @__PURE__ */ jsx(Tag, {
2023
+ class: className,
2024
+ style,
2025
+ ...rest,
2026
+ children: typeof children === "function" ? children() : children
2027
+ })
2028
+ });
2029
+ }
2030
+ function CommandInput(props) {
2031
+ const ctx = useContext(CommandContext);
2032
+ const handleKeyDown = (e) => {
2033
+ const list = e.currentTarget.closest('[role="combobox"], [data-command-root], div')?.querySelector('[role="listbox"]');
2034
+ if (!list)
2035
+ return;
2036
+ const items = Array.from(list.querySelectorAll('[role="option"]:not([aria-disabled="true"]):not([style*="display: none"])'));
2037
+ if (items.length === 0)
2038
+ return;
2039
+ const currentActive = items.find((el) => el.getAttribute("aria-selected") === "true") ?? items[0];
2040
+ const index = currentActive ? items.indexOf(currentActive) : 0;
2041
+ if (e.key === "ArrowDown") {
2042
+ e.preventDefault();
2043
+ const nextIndex = (index + 1) % items.length;
2044
+ const nextItem = items[nextIndex];
2045
+ if (nextItem && ctx) {
2046
+ ctx.setActiveValue(nextItem.getAttribute("data-value") ?? "");
2047
+ nextItem.scrollIntoView({ block: "nearest" });
2048
+ }
2049
+ } else if (e.key === "ArrowUp") {
2050
+ e.preventDefault();
2051
+ const prevIndex = (index - 1 + items.length) % items.length;
2052
+ const prevItem = items[prevIndex];
2053
+ if (prevItem && ctx) {
2054
+ ctx.setActiveValue(prevItem.getAttribute("data-value") ?? "");
2055
+ prevItem.scrollIntoView({ block: "nearest" });
2056
+ }
2057
+ } else if (e.key === "Enter" && currentActive) {
2058
+ e.preventDefault();
2059
+ currentActive.click();
2060
+ }
2061
+ };
2062
+ const { placeholder = "Type a command...", class: className, style, ...rest } = props;
2063
+ return /* @__PURE__ */ jsx("input", {
2064
+ type: "text",
2065
+ role: "searchbox",
2066
+ placeholder,
2067
+ value: () => ctx?.search() ?? "",
2068
+ onInput: (e) => ctx?.setSearch(e.target.value),
2069
+ onKeyDown: handleKeyDown,
2070
+ class: className,
2071
+ style,
2072
+ ...rest
2073
+ });
2074
+ }
2075
+ function CommandList(props) {
2076
+ const { as: Tag = "div", children, class: className, style, ...rest } = props;
2077
+ return /* @__PURE__ */ jsx(Tag, {
2078
+ role: "listbox",
2079
+ class: className,
2080
+ style: { overflowY: "auto", ...style },
2081
+ ...rest,
2082
+ children
2083
+ });
2084
+ }
2085
+ function CommandEmpty(props) {
2086
+ const ctx = useContext(CommandContext);
2087
+ const { as: Tag = "div", children, class: className, style, ...rest } = props;
2088
+ return /* @__PURE__ */ jsx(Tag, {
2089
+ class: className,
2090
+ style: () => ({
2091
+ display: ctx && ctx.search().trim().length > 0 ? undefined : "none",
2092
+ textAlign: "center",
2093
+ padding: "16px",
2094
+ color: "#94a3b8",
2095
+ ...style
2096
+ }),
2097
+ ...rest,
2098
+ children
2099
+ });
2100
+ }
2101
+ function CommandGroup(props) {
2102
+ const { heading, as: Tag = "div", children, class: className, style, ...rest } = props;
2103
+ return /* @__PURE__ */ jsxs(Tag, {
2104
+ role: "group",
2105
+ class: className,
2106
+ style,
2107
+ ...rest,
2108
+ children: [
2109
+ heading ? /* @__PURE__ */ jsx("div", {
2110
+ style: {
2111
+ fontSize: "11px",
2112
+ fontWeight: 700,
2113
+ textTransform: "uppercase",
2114
+ letterSpacing: "0.05em",
2115
+ color: "#64748b",
2116
+ padding: "6px 10px"
2117
+ },
2118
+ children: heading
2119
+ }) : null,
2120
+ children
2121
+ ]
2122
+ });
2123
+ }
2124
+ function CommandItem(props) {
2125
+ const ctx = useContext(CommandContext);
2126
+ const itemValue = props.value ?? (typeof props.children === "string" ? props.children : createId("item"));
2127
+ const isVisible = () => {
2128
+ if (!ctx)
2129
+ return true;
2130
+ const text = typeof props.children === "string" ? props.children : itemValue;
2131
+ return ctx.filterMatches(text, props.keywords);
2132
+ };
2133
+ const isSelected = () => ctx ? ctx.activeValue() === itemValue : false;
2134
+ const handleClick = () => {
2135
+ if (props.disabled)
2136
+ return;
2137
+ if (props.onSelect)
2138
+ props.onSelect();
2139
+ };
2140
+ const { as: Tag = "div", shortcut, disabled, children, class: className, style, ...rest } = props;
2141
+ return /* @__PURE__ */ jsxs(Tag, {
2142
+ role: "option",
2143
+ "data-value": itemValue,
2144
+ "aria-selected": isSelected,
2145
+ "aria-disabled": disabled,
2146
+ class: className,
2147
+ style: () => ({
2148
+ display: isVisible() ? "flex" : "none",
2149
+ alignItems: "center",
2150
+ justifyContent: "space-between",
2151
+ cursor: disabled ? "not-allowed" : "pointer",
2152
+ ...style
2153
+ }),
2154
+ onClick: handleClick,
2155
+ ...rest,
2156
+ children: [
2157
+ /* @__PURE__ */ jsx("div", {
2158
+ style: { display: "flex", alignItems: "center" },
2159
+ children
2160
+ }),
2161
+ shortcut ? /* @__PURE__ */ jsx("span", {
2162
+ style: {
2163
+ fontSize: "11px",
2164
+ color: "#64748b",
2165
+ background: "#1e293b",
2166
+ padding: "2px 6px",
2167
+ borderRadius: "4px"
2168
+ },
2169
+ children: shortcut
2170
+ }) : null
2171
+ ]
2172
+ });
2173
+ }
2174
+ var Command = Object.assign(CommandRoot, {
2175
+ Root: CommandRoot,
2176
+ Dialog: CommandDialog,
2177
+ Input: CommandInput,
2178
+ List: CommandList,
2179
+ Empty: CommandEmpty,
2180
+ Group: CommandGroup,
2181
+ Item: CommandItem
2182
+ });
2183
+ // src/ui/data-table.tsx
2184
+ function DataTable(props) {
2185
+ const [sortState, setSortState] = createControllableSignal({
2186
+ value: props.sort,
2187
+ defaultValue: { column: "", direction: null },
2188
+ onChange: props.onSortChange
2189
+ });
2190
+ const [selectedKeys, setSelectedKeys] = createControllableSignal({
2191
+ value: props.selectedKeys,
2192
+ defaultValue: [],
2193
+ onChange: props.onSelectionChange
2194
+ });
2195
+ const [currentPage, setCurrentPage] = createSignal(0, { internal: true });
2196
+ const pageSize = props.pageSize ?? 10;
2197
+ const selectionMode = props.selection ?? "none";
2198
+ const getRowId = (row, index) => {
2199
+ if (props.getRowId)
2200
+ return props.getRowId(row, index);
2201
+ if (row && typeof row === "object" && "id" in row)
2202
+ return String(row.id);
2203
+ return String(index);
2204
+ };
2205
+ const filteredData = () => {
2206
+ const raw = typeof props.data === "function" ? props.data() : props.data;
2207
+ if (!raw)
2208
+ return [];
2209
+ const filterQuery = props.filter ? (typeof props.filter === "function" ? props.filter() : props.filter)?.toLowerCase().trim() : "";
2210
+ if (!filterQuery)
2211
+ return raw;
2212
+ return raw.filter((row) => Object.values(row).some((val) => String(val).toLowerCase().includes(filterQuery)));
2213
+ };
2214
+ const sortedData = () => {
2215
+ const list = [...filteredData()];
2216
+ const currentSort = sortState();
2217
+ if (!currentSort.column || !currentSort.direction)
2218
+ return list;
2219
+ return list.sort((a, b) => {
2220
+ const aVal = a[currentSort.column];
2221
+ const bVal = b[currentSort.column];
2222
+ if (aVal === bVal)
2223
+ return 0;
2224
+ if (aVal === null || aVal === undefined)
2225
+ return 1;
2226
+ if (bVal === null || bVal === undefined)
2227
+ return -1;
2228
+ const comp = aVal < bVal ? -1 : 1;
2229
+ return currentSort.direction === "asc" ? comp : -comp;
2230
+ });
2231
+ };
2232
+ const totalPages = () => Math.ceil(sortedData().length / pageSize) || 1;
2233
+ const paginatedData = () => {
2234
+ if (!props.pageSize)
2235
+ return sortedData();
2236
+ const start = currentPage() * pageSize;
2237
+ return sortedData().slice(start, start + pageSize);
2238
+ };
2239
+ const handleSort = (colId) => {
2240
+ const current = sortState();
2241
+ if (current.column !== colId) {
2242
+ setSortState({ column: colId, direction: "asc" });
2243
+ } else if (current.direction === "asc") {
2244
+ setSortState({ column: colId, direction: "desc" });
2245
+ } else {
2246
+ setSortState({ column: "", direction: null });
2247
+ }
2248
+ };
2249
+ const handleSelectRow = (key, e) => {
2250
+ e.stopPropagation();
2251
+ if (selectionMode === "single") {
2252
+ setSelectedKeys(selectedKeys().includes(key) ? [] : [key]);
2253
+ } else if (selectionMode === "multi") {
2254
+ const current = selectedKeys();
2255
+ if (current.includes(key)) {
2256
+ setSelectedKeys(current.filter((k) => k !== key));
2257
+ } else {
2258
+ setSelectedKeys([...current, key]);
2259
+ }
2260
+ }
2261
+ };
2262
+ const handleSelectAll = () => {
2263
+ if (selectionMode !== "multi")
2264
+ return;
2265
+ const allCurrentKeys = paginatedData().map((row, i) => getRowId(row, i));
2266
+ const allSelected = allCurrentKeys.every((k) => selectedKeys().includes(k));
2267
+ if (allSelected) {
2268
+ setSelectedKeys(selectedKeys().filter((k) => !allCurrentKeys.includes(k)));
2269
+ } else {
2270
+ setSelectedKeys(Array.from(new Set([...selectedKeys(), ...allCurrentKeys])));
2271
+ }
2272
+ };
2273
+ const {
2274
+ class: className,
2275
+ style,
2276
+ tableClass,
2277
+ headerClass,
2278
+ rowClass,
2279
+ cellClass,
2280
+ paginationClass,
2281
+ emptyText = "No data available",
2282
+ ...rest
2283
+ } = props;
2284
+ return /* @__PURE__ */ jsxs("div", {
2285
+ class: className,
2286
+ style: { display: "flex", flexDirection: "column", width: "100%", ...style },
2287
+ ...rest,
2288
+ children: [
2289
+ /* @__PURE__ */ jsx("div", {
2290
+ style: { overflowX: "auto", width: "100%" },
2291
+ children: /* @__PURE__ */ jsxs("table", {
2292
+ class: tableClass,
2293
+ style: { width: "100%", borderCollapse: "collapse" },
2294
+ children: [
2295
+ /* @__PURE__ */ jsx("thead", {
2296
+ class: headerClass,
2297
+ children: /* @__PURE__ */ jsxs("tr", {
2298
+ children: [
2299
+ selectionMode === "multi" ? /* @__PURE__ */ jsx("th", {
2300
+ style: { width: "40px", padding: "8px" },
2301
+ children: /* @__PURE__ */ jsx("input", {
2302
+ type: "checkbox",
2303
+ checked: () => {
2304
+ const keys = paginatedData().map((row, i) => getRowId(row, i));
2305
+ return keys.length > 0 && keys.every((k) => selectedKeys().includes(k));
2306
+ },
2307
+ onChange: handleSelectAll
2308
+ })
2309
+ }) : null,
2310
+ props.columns.map((col) => {
2311
+ const isSorted = () => sortState().column === col.id;
2312
+ const sortDir = () => isSorted() ? sortState().direction : null;
2313
+ return /* @__PURE__ */ jsx("th", {
2314
+ style: {
2315
+ width: col.width,
2316
+ textAlign: col.align ?? "left",
2317
+ cursor: col.sortable ? "pointer" : "default",
2318
+ userSelect: col.sortable ? "none" : "auto",
2319
+ padding: "10px 12px"
2320
+ },
2321
+ onClick: () => {
2322
+ if (col.sortable)
2323
+ handleSort(col.id);
2324
+ },
2325
+ children: /* @__PURE__ */ jsxs("div", {
2326
+ style: { display: "inline-flex", alignItems: "center", gap: "6px" },
2327
+ children: [
2328
+ /* @__PURE__ */ jsx("span", {
2329
+ children: typeof col.header === "function" ? col.header() : col.header
2330
+ }),
2331
+ col.sortable ? /* @__PURE__ */ jsx("span", {
2332
+ style: { fontSize: "10px", color: isSorted() ? "#38bdf8" : "#64748b" },
2333
+ children: () => sortDir() === "asc" ? "▲" : sortDir() === "desc" ? "▼" : "⇅"
2334
+ }) : null
2335
+ ]
2336
+ })
2337
+ });
2338
+ })
2339
+ ]
2340
+ })
2341
+ }),
2342
+ /* @__PURE__ */ jsx("tbody", {
2343
+ children: /* @__PURE__ */ jsx(For, {
2344
+ each: paginatedData,
2345
+ fallback: /* @__PURE__ */ jsx("tr", {
2346
+ children: /* @__PURE__ */ jsx("td", {
2347
+ colSpan: props.columns.length + (selectionMode === "multi" ? 1 : 0),
2348
+ style: { textAlign: "center", padding: "24px", color: "#64748b" },
2349
+ children: emptyText
2350
+ })
2351
+ }),
2352
+ children: (row, idx) => {
2353
+ const key = () => getRowId(row, idx());
2354
+ const isSelected = () => selectedKeys().includes(key());
2355
+ return /* @__PURE__ */ jsxs("tr", {
2356
+ class: rowClass,
2357
+ style: { cursor: props.onRowClick ? "pointer" : "default" },
2358
+ "data-selected": isSelected,
2359
+ onClick: () => {
2360
+ if (props.onRowClick)
2361
+ props.onRowClick(row, idx());
2362
+ },
2363
+ children: [
2364
+ selectionMode === "multi" ? /* @__PURE__ */ jsx("td", {
2365
+ style: { width: "40px", padding: "8px" },
2366
+ children: /* @__PURE__ */ jsx("input", {
2367
+ type: "checkbox",
2368
+ checked: isSelected,
2369
+ onClick: (e) => handleSelectRow(key(), e)
2370
+ })
2371
+ }) : null,
2372
+ props.columns.map((col) => {
2373
+ const content = col.cell ? col.cell(row, idx()) : col.accessorKey ? row[col.accessorKey] : row[col.id];
2374
+ return /* @__PURE__ */ jsx("td", {
2375
+ class: cellClass,
2376
+ style: {
2377
+ textAlign: col.align ?? "left",
2378
+ padding: "10px 12px"
2379
+ },
2380
+ children: typeof content === "function" ? content() : content
2381
+ });
2382
+ })
2383
+ ]
2384
+ });
2385
+ }
2386
+ })
2387
+ })
2388
+ ]
2389
+ })
2390
+ }),
2391
+ props.pageSize ? /* @__PURE__ */ jsxs("div", {
2392
+ class: paginationClass,
2393
+ style: {
2394
+ display: "flex",
2395
+ alignItems: "center",
2396
+ justifyContent: "space-between",
2397
+ padding: "10px 12px",
2398
+ borderTop: "1px solid #1e293b",
2399
+ fontSize: "12px",
2400
+ color: "#94a3b8"
2401
+ },
2402
+ children: [
2403
+ /* @__PURE__ */ jsxs("div", {
2404
+ children: [
2405
+ "Showing ",
2406
+ /* @__PURE__ */ jsx("strong", {
2407
+ children: () => currentPage() * pageSize + 1
2408
+ }),
2409
+ " to",
2410
+ " ",
2411
+ /* @__PURE__ */ jsx("strong", {
2412
+ children: () => Math.min((currentPage() + 1) * pageSize, sortedData().length)
2413
+ }),
2414
+ " ",
2415
+ "of ",
2416
+ /* @__PURE__ */ jsx("strong", {
2417
+ children: () => sortedData().length
2418
+ }),
2419
+ " entries"
2420
+ ]
2421
+ }),
2422
+ /* @__PURE__ */ jsxs("div", {
2423
+ style: { display: "flex", gap: "6px", alignItems: "center" },
2424
+ children: [
2425
+ /* @__PURE__ */ jsx("button", {
2426
+ type: "button",
2427
+ disabled: () => currentPage() === 0,
2428
+ onClick: () => setCurrentPage((p) => Math.max(0, p - 1)),
2429
+ style: { padding: "4px 8px", cursor: "pointer" },
2430
+ children: "Previous"
2431
+ }),
2432
+ /* @__PURE__ */ jsxs("span", {
2433
+ children: [
2434
+ "Page ",
2435
+ /* @__PURE__ */ jsx("strong", {
2436
+ children: () => currentPage() + 1
2437
+ }),
2438
+ " of ",
2439
+ /* @__PURE__ */ jsx("strong", {
2440
+ children: totalPages
2441
+ })
2442
+ ]
2443
+ }),
2444
+ /* @__PURE__ */ jsx("button", {
2445
+ type: "button",
2446
+ disabled: () => currentPage() >= totalPages() - 1,
2447
+ onClick: () => setCurrentPage((p) => Math.min(totalPages() - 1, p + 1)),
2448
+ style: { padding: "4px 8px", cursor: "pointer" },
2449
+ children: "Next"
2450
+ })
2451
+ ]
2452
+ })
2453
+ ]
2454
+ }) : null
2455
+ ]
2456
+ });
2457
+ }
2458
+ // src/ui/dialog.tsx
2459
+ var DialogContext = createContext(null);
2460
+ function useDialogContext() {
2461
+ const ctx = useContext(DialogContext);
2462
+ return ctx;
2463
+ }
2464
+ function DialogRoot(props) {
2465
+ const [open, setOpen] = createControllableSignal({
2466
+ value: props.open,
2467
+ defaultValue: props.defaultOpen ?? false,
2468
+ onChange: props.onOpenChange
2469
+ });
2470
+ const titleId = createId("dialog-title");
2471
+ const descriptionId = createId("dialog-desc");
2472
+ const contentRef = { current: null };
2473
+ const ctx = {
2474
+ open,
2475
+ setOpen,
2476
+ titleId,
2477
+ descriptionId,
2478
+ contentRef
2479
+ };
2480
+ if (props.trigger !== undefined || props.title !== undefined || props.description !== undefined) {
2481
+ return DialogContext.Provider({
2482
+ value: ctx,
2483
+ children: () => /* @__PURE__ */ jsxs(Fragment, {
2484
+ children: [
2485
+ props.trigger ? /* @__PURE__ */ jsx(DialogTrigger, {
2486
+ as: "span",
2487
+ class: props.triggerClass,
2488
+ children: typeof props.trigger === "function" ? props.trigger() : props.trigger
2489
+ }) : null,
2490
+ /* @__PURE__ */ jsx(DialogOverlay, {
2491
+ class: props.overlayClass,
2492
+ portalled: props.portalled
2493
+ }),
2494
+ /* @__PURE__ */ jsxs(DialogContent, {
2495
+ portalled: props.portalled,
2496
+ class: props.contentClass,
2497
+ children: [
2498
+ props.title ? /* @__PURE__ */ jsx(DialogTitle, {
2499
+ class: props.titleClass,
2500
+ children: typeof props.title === "function" ? props.title() : props.title
2501
+ }) : null,
2502
+ props.description ? /* @__PURE__ */ jsx(DialogDescription, {
2503
+ class: props.descriptionClass,
2504
+ children: typeof props.description === "function" ? props.description() : props.description
2505
+ }) : null,
2506
+ typeof props.children === "function" ? props.children() : props.children,
2507
+ props.footer ? /* @__PURE__ */ jsx("div", {
2508
+ class: props.footerClass,
2509
+ children: typeof props.footer === "function" ? props.footer() : props.footer
2510
+ }) : null
2511
+ ]
2512
+ })
2513
+ ]
2514
+ })
2515
+ });
2516
+ }
2517
+ return DialogContext.Provider({
2518
+ value: ctx,
2519
+ children: props.children
2520
+ });
2521
+ }
2522
+ function DialogTrigger(props) {
2523
+ const ctx = useContext(DialogContext);
2524
+ const handleClick = (e) => {
2525
+ if (props.onClick)
2526
+ props.onClick(e);
2527
+ if (!e.defaultPrevented && ctx) {
2528
+ ctx.setOpen(true);
2529
+ }
2530
+ };
2531
+ const { as: Tag = "button", children, onClick, class: className, style, ...rest } = props;
2532
+ return /* @__PURE__ */ jsx(Tag, {
2533
+ type: Tag === "button" ? "button" : undefined,
2534
+ "aria-haspopup": "dialog",
2535
+ "aria-expanded": () => ctx?.open() ?? false,
2536
+ "data-state": () => ctx?.open() ? "open" : "closed",
2537
+ class: className,
2538
+ style,
2539
+ onClick: handleClick,
2540
+ ...rest,
2541
+ children
2542
+ });
2543
+ }
2544
+ function DialogPortal(props) {
2545
+ return /* @__PURE__ */ jsx(Portal, {
2546
+ mount: props.mount,
2547
+ children: props.children
2548
+ });
2549
+ }
2550
+ function DialogOverlay(props) {
2551
+ const ctx = useContext(DialogContext);
2552
+ const handleClick = (e) => {
2553
+ if (props.onClick)
2554
+ props.onClick(e);
2555
+ if (!e.defaultPrevented && ctx) {
2556
+ ctx.setOpen(false);
2557
+ }
2558
+ };
2559
+ const {
2560
+ as: Tag = "div",
2561
+ children,
2562
+ onClick,
2563
+ class: className,
2564
+ style,
2565
+ portalled = true,
2566
+ mount,
2567
+ ...rest
2568
+ } = props;
2569
+ const overlay = /* @__PURE__ */ jsx(Tag, {
2570
+ "data-state": () => ctx?.open() ? "open" : "closed",
2571
+ style: () => ({
2572
+ display: ctx?.open() ? undefined : "none",
2573
+ ...style
2574
+ }),
2575
+ class: className,
2576
+ onClick: handleClick,
2577
+ "aria-hidden": "true",
2578
+ ...rest,
2579
+ children
2580
+ });
2581
+ return portalled ? /* @__PURE__ */ jsx(Portal, {
2582
+ mount,
2583
+ children: overlay
2584
+ }) : overlay;
2585
+ }
2586
+ function DialogContent(props) {
2587
+ const ctx = useContext(DialogContext);
2588
+ const handleKeyDown = (e) => {
2589
+ if (props.onKeyDown)
2590
+ props.onKeyDown(e);
2591
+ if (e.defaultPrevented)
2592
+ return;
2593
+ if (e.key === "Escape") {
2594
+ ctx?.setOpen(false);
2595
+ e.stopPropagation();
2596
+ } else if (e.key === "Tab" && ctx?.contentRef.current) {
2597
+ trapFocus(ctx.contentRef.current, e);
2598
+ }
2599
+ };
2600
+ const handleClick = (e) => {
2601
+ if (props.onClick)
2602
+ props.onClick(e);
2603
+ if (e.defaultPrevented)
2604
+ return;
2605
+ const target = e.target;
2606
+ if (target?.closest("[data-dialog-close]")) {
2607
+ ctx?.setOpen(false);
2608
+ }
2609
+ };
2610
+ const {
2611
+ as: Tag = "div",
2612
+ children,
2613
+ onKeyDown,
2614
+ onClick: _onClick,
2615
+ class: className,
2616
+ style,
2617
+ portalled = true,
2618
+ mount,
2619
+ ...rest
2620
+ } = props;
2621
+ const content = /* @__PURE__ */ jsx(Tag, {
2622
+ ref: (el) => {
2623
+ if (ctx) {
2624
+ ctx.contentRef.current = el;
2625
+ if (el && ctx.open()) {
2626
+ const focusable = el.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
2627
+ if (focusable) {
2628
+ setTimeout(() => focusable.focus(), 0);
2629
+ }
2630
+ }
2631
+ }
2632
+ },
2633
+ role: "dialog",
2634
+ "aria-modal": "true",
2635
+ "aria-labelledby": ctx?.titleId,
2636
+ "aria-describedby": ctx?.descriptionId,
2637
+ "data-state": () => ctx?.open() ? "open" : "closed",
2638
+ style: () => ({
2639
+ display: ctx?.open() ? undefined : "none",
2640
+ ...style
2641
+ }),
2642
+ class: className,
2643
+ onKeyDown: handleKeyDown,
2644
+ onClick: handleClick,
2645
+ tabIndex: -1,
2646
+ ...rest,
2647
+ children
2648
+ });
2649
+ return portalled ? /* @__PURE__ */ jsx(Portal, {
2650
+ mount,
2651
+ children: content
2652
+ }) : content;
2653
+ }
2654
+ function DialogTitle(props) {
2655
+ const ctx = useContext(DialogContext);
2656
+ const { as: Tag = "h2", children, class: className, style, ...rest } = props;
2657
+ return /* @__PURE__ */ jsx(Tag, {
2658
+ id: ctx?.titleId,
2659
+ class: className,
2660
+ style,
2661
+ ...rest,
2662
+ children
2663
+ });
2664
+ }
2665
+ function DialogDescription(props) {
2666
+ const ctx = useContext(DialogContext);
2667
+ const { as: Tag = "p", children, class: className, style, ...rest } = props;
2668
+ return /* @__PURE__ */ jsx(Tag, {
2669
+ id: ctx?.descriptionId,
2670
+ class: className,
2671
+ style,
2672
+ ...rest,
2673
+ children
2674
+ });
2675
+ }
2676
+ function DialogClose(props) {
2677
+ const ctx = useContext(DialogContext);
2678
+ const handleClick = (e) => {
2679
+ if (props.onClick)
2680
+ props.onClick(e);
2681
+ if (!e.defaultPrevented && ctx) {
2682
+ ctx.setOpen(false);
2683
+ }
2684
+ };
2685
+ const { as: Tag = "button", children, onClick, class: className, style, ...rest } = props;
2686
+ return /* @__PURE__ */ jsx(Tag, {
2687
+ type: Tag === "button" ? "button" : undefined,
2688
+ "data-dialog-close": "",
2689
+ class: className,
2690
+ style,
2691
+ onClick: handleClick,
2692
+ ...rest,
2693
+ children
2694
+ });
2695
+ }
2696
+ var Dialog = Object.assign(DialogRoot, {
2697
+ Root: DialogRoot,
2698
+ Trigger: DialogTrigger,
2699
+ Portal: DialogPortal,
2700
+ Overlay: DialogOverlay,
2701
+ Content: DialogContent,
2702
+ Title: DialogTitle,
2703
+ Description: DialogDescription,
2704
+ Close: DialogClose
2705
+ });
2706
+ // src/ui/dropdown-menu.tsx
2707
+ var DropdownMenuContext = createContext(null);
2708
+ function useDropdownMenuContext() {
2709
+ return useContext(DropdownMenuContext);
2710
+ }
2711
+ function DropdownMenuRoot(props) {
2712
+ const [open, setOpen] = createControllableSignal({
2713
+ value: props.open,
2714
+ defaultValue: props.defaultOpen ?? false,
2715
+ onChange: props.onOpenChange
2716
+ });
2717
+ const triggerRef = { current: null };
2718
+ const contentRef = { current: null };
2719
+ const menuId = createId("dropdown-menu");
2720
+ const ctx = {
2721
+ open,
2722
+ setOpen,
2723
+ triggerRef,
2724
+ contentRef,
2725
+ menuId
2726
+ };
2727
+ if (props.trigger !== undefined || props.items !== undefined) {
2728
+ return DropdownMenuContext.Provider({
2729
+ value: ctx,
2730
+ children: () => /* @__PURE__ */ jsxs("div", {
2731
+ class: "visage-dropdown-root",
2732
+ style: { position: "relative", display: "inline-block" },
2733
+ children: [
2734
+ props.trigger ? /* @__PURE__ */ jsx(DropdownMenuTrigger, {
2735
+ as: "span",
2736
+ class: props.triggerClass,
2737
+ children: typeof props.trigger === "function" ? props.trigger() : props.trigger
2738
+ }) : null,
2739
+ /* @__PURE__ */ jsxs(DropdownMenuContent, {
2740
+ portalled: props.portalled ?? false,
2741
+ class: props.contentClass,
2742
+ children: [
2743
+ props.items ? props.items.map((item) => {
2744
+ if (item.separator) {
2745
+ return /* @__PURE__ */ jsx(DropdownMenuSeparator, {
2746
+ class: item.class ?? props.separatorClass
2747
+ });
2748
+ }
2749
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
2750
+ disabled: item.disabled,
2751
+ onSelect: item.onSelect,
2752
+ class: [props.itemClass, item.class, item.danger ? "danger" : ""].filter(Boolean).join(" "),
2753
+ children: [
2754
+ item.icon ? /* @__PURE__ */ jsx("span", {
2755
+ class: "dropdown-item-icon",
2756
+ style: {
2757
+ display: "inline-flex",
2758
+ alignItems: "center",
2759
+ marginRight: "8px"
2760
+ },
2761
+ children: typeof item.icon === "function" ? item.icon() : item.icon
2762
+ }) : null,
2763
+ typeof item.label === "function" ? item.label() : item.label
2764
+ ]
2765
+ });
2766
+ }) : null,
2767
+ typeof props.children === "function" ? props.children() : props.children
2768
+ ]
2769
+ })
2770
+ ]
2771
+ })
2772
+ });
2773
+ }
2774
+ return DropdownMenuContext.Provider({
2775
+ value: ctx,
2776
+ children: props.children
2777
+ });
2778
+ }
2779
+ function DropdownMenuTrigger(props) {
2780
+ const ctx = useContext(DropdownMenuContext);
2781
+ const handleClick = (e) => {
2782
+ if (props.onClick)
2783
+ props.onClick(e);
2784
+ if (!e.defaultPrevented && ctx) {
2785
+ ctx.setOpen(!ctx.open());
2786
+ }
2787
+ };
2788
+ const handleKeyDown = (e) => {
2789
+ if (props.onKeyDown)
2790
+ props.onKeyDown(e);
2791
+ if (e.defaultPrevented)
2792
+ return;
2793
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
2794
+ if (ctx) {
2795
+ ctx.setOpen(true);
2796
+ e.preventDefault();
2797
+ setTimeout(() => {
2798
+ const firstItem = ctx.contentRef.current?.querySelector('[role="menuitem"]:not([disabled])');
2799
+ firstItem?.focus();
2800
+ }, 0);
2801
+ }
2802
+ }
2803
+ };
2804
+ const {
2805
+ as: Tag = "button",
2806
+ children,
2807
+ onClick,
2808
+ onKeyDown,
2809
+ class: className,
2810
+ style,
2811
+ ...rest
2812
+ } = props;
2813
+ return /* @__PURE__ */ jsx(Tag, {
2814
+ ref: (el) => {
2815
+ if (ctx)
2816
+ ctx.triggerRef.current = el;
2817
+ },
2818
+ type: Tag === "button" ? "button" : undefined,
2819
+ "aria-haspopup": "menu",
2820
+ "aria-expanded": () => ctx?.open() ?? false,
2821
+ "aria-controls": ctx?.menuId,
2822
+ "data-state": () => ctx?.open() ? "open" : "closed",
2823
+ class: className,
2824
+ style,
2825
+ onClick: handleClick,
2826
+ onKeyDown: handleKeyDown,
2827
+ ...rest,
2828
+ children
2829
+ });
2830
+ }
2831
+ function DropdownMenuPortal(props) {
2832
+ return /* @__PURE__ */ jsx(Portal, {
2833
+ mount: props.mount,
2834
+ children: props.children
2835
+ });
2836
+ }
2837
+ function DropdownMenuContent(props) {
2838
+ const ctx = useContext(DropdownMenuContext);
2839
+ const handleKeyDown = (e) => {
2840
+ if (props.onKeyDown)
2841
+ props.onKeyDown(e);
2842
+ if (e.defaultPrevented)
2843
+ return;
2844
+ const el = ctx?.contentRef.current;
2845
+ if (!el)
2846
+ return;
2847
+ const items = Array.from(el.querySelectorAll('[role="menuitem"]:not([disabled])'));
2848
+ const active = document.activeElement;
2849
+ const index = active ? items.indexOf(active) : -1;
2850
+ if (e.key === "ArrowDown") {
2851
+ const nextIndex = index === items.length - 1 || index === -1 ? 0 : index + 1;
2852
+ items[nextIndex]?.focus();
2853
+ e.preventDefault();
2854
+ } else if (e.key === "ArrowUp") {
2855
+ const nextIndex = index <= 0 ? items.length - 1 : index - 1;
2856
+ items[nextIndex]?.focus();
2857
+ e.preventDefault();
2858
+ } else if (e.key === "Home") {
2859
+ items[0]?.focus();
2860
+ e.preventDefault();
2861
+ } else if (e.key === "End") {
2862
+ items[items.length - 1]?.focus();
2863
+ e.preventDefault();
2864
+ } else if (e.key === "Escape") {
2865
+ if (ctx) {
2866
+ ctx.setOpen(false);
2867
+ ctx.triggerRef.current?.focus();
2868
+ }
2869
+ e.preventDefault();
2870
+ } else if (e.key === "Tab") {
2871
+ if (ctx)
2872
+ ctx.setOpen(false);
2873
+ }
2874
+ };
2875
+ const {
2876
+ as: Tag = "div",
2877
+ children,
2878
+ onKeyDown,
2879
+ class: className,
2880
+ style,
2881
+ portalled = true,
2882
+ mount,
2883
+ ...rest
2884
+ } = props;
2885
+ const content = /* @__PURE__ */ jsx(Tag, {
2886
+ ref: (el) => {
2887
+ if (ctx) {
2888
+ ctx.contentRef.current = el;
2889
+ if (el) {
2890
+ const cleanup = onClickOutside([ctx.triggerRef.current, el], () => {
2891
+ if (ctx.open()) {
2892
+ ctx.setOpen(false);
2893
+ }
2894
+ });
2895
+ onCleanup(cleanup);
2896
+ }
2897
+ }
2898
+ },
2899
+ id: ctx?.menuId,
2900
+ role: "menu",
2901
+ "aria-orientation": "vertical",
2902
+ "data-state": () => ctx?.open() ? "open" : "closed",
2903
+ class: className,
2904
+ style: () => ({
2905
+ display: ctx?.open() ? undefined : "none",
2906
+ ...style
2907
+ }),
2908
+ onKeyDown: handleKeyDown,
2909
+ tabIndex: -1,
2910
+ ...rest,
2911
+ children
2912
+ });
2913
+ return portalled ? /* @__PURE__ */ jsx(Portal, {
2914
+ mount,
2915
+ children: content
2916
+ }) : content;
2917
+ }
2918
+ function DropdownMenuItem(props) {
2919
+ const ctx = useContext(DropdownMenuContext);
2920
+ const closeOnSelect = props.closeOnSelect ?? true;
2921
+ const handleSelect = (e) => {
2922
+ if (props.disabled)
2923
+ return;
2924
+ if (props.onSelect)
2925
+ props.onSelect(e);
2926
+ if (!e.defaultPrevented && closeOnSelect && ctx) {
2927
+ ctx.setOpen(false);
2928
+ ctx.triggerRef.current?.focus();
2929
+ }
2930
+ };
2931
+ const handleClick = (e) => {
2932
+ if (props.onClick)
2933
+ props.onClick(e);
2934
+ handleSelect(e);
2935
+ };
2936
+ const handleKeyDown = (e) => {
2937
+ if (props.onKeyDown)
2938
+ props.onKeyDown(e);
2939
+ if (e.key === "Enter" || e.key === " ") {
2940
+ e.preventDefault();
2941
+ handleSelect(e);
2942
+ }
2943
+ };
2944
+ const {
2945
+ disabled,
2946
+ closeOnSelect: _cos,
2947
+ as: Tag = "div",
2948
+ children,
2949
+ onClick,
2950
+ onKeyDown,
2951
+ onSelect: _os,
2952
+ class: className,
2953
+ style,
2954
+ ...rest
2955
+ } = props;
2956
+ return /* @__PURE__ */ jsx(Tag, {
2957
+ role: "menuitem",
2958
+ tabIndex: -1,
2959
+ "aria-disabled": disabled,
2960
+ class: className,
2961
+ style,
2962
+ onClick: handleClick,
2963
+ onKeyDown: handleKeyDown,
2964
+ ...rest,
2965
+ children
2966
+ });
2967
+ }
2968
+ function DropdownMenuSeparator(props) {
2969
+ const { as: Tag = "div", class: className, style, ...rest } = props;
2970
+ return /* @__PURE__ */ jsx(Tag, {
2971
+ role: "separator",
2972
+ "aria-orientation": "horizontal",
2973
+ class: className,
2974
+ style,
2975
+ ...rest
2976
+ });
2977
+ }
2978
+ var DropdownMenu = Object.assign(DropdownMenuRoot, {
2979
+ Root: DropdownMenuRoot,
2980
+ Trigger: DropdownMenuTrigger,
2981
+ Portal: DropdownMenuPortal,
2982
+ Content: DropdownMenuContent,
2983
+ Item: DropdownMenuItem,
2984
+ Separator: DropdownMenuSeparator
2985
+ });
2986
+ // src/ui/icon.tsx
2987
+ function createIcon(name, iconNode) {
2988
+ const IconComponent = function Icon(props = {}) {
2989
+ const size = () => typeof props.size === "function" ? props.size() : props.size ?? 24;
2990
+ const color = () => typeof props.color === "function" ? props.color() : props.color ?? "currentColor";
2991
+ const strokeWidth = () => typeof props.strokeWidth === "function" ? props.strokeWidth() : props.strokeWidth ?? 2;
2992
+ const {
2993
+ size: _s,
2994
+ color: _c,
2995
+ strokeWidth: _sw,
2996
+ class: className,
2997
+ style,
2998
+ children,
2999
+ ...rest
3000
+ } = props;
3001
+ return /* @__PURE__ */ jsxs("svg", {
3002
+ xmlns: "http://www.w3.org/2000/svg",
3003
+ width: size,
3004
+ height: size,
3005
+ viewBox: "0 0 24 24",
3006
+ fill: "none",
3007
+ stroke: color,
3008
+ "stroke-width": strokeWidth,
3009
+ "stroke-linecap": "round",
3010
+ "stroke-linejoin": "round",
3011
+ class: className,
3012
+ style,
3013
+ role: "img",
3014
+ "aria-label": props["aria-label"] ?? name,
3015
+ ...rest,
3016
+ children: [
3017
+ /* @__PURE__ */ jsx("title", {
3018
+ children: props.title ?? name
3019
+ }),
3020
+ iconNode.map(([Tag, attrs]) => /* @__PURE__ */ jsx(Tag, {
3021
+ ...attrs
3022
+ })),
3023
+ typeof children === "function" ? children() : children
3024
+ ]
3025
+ });
3026
+ };
3027
+ IconComponent.displayName = name;
3028
+ return IconComponent;
3029
+ }
3030
+ // src/style/layout.tsx
3031
+ var ALIGN_MAP = {
3032
+ start: "flex-start",
3033
+ center: "center",
3034
+ end: "flex-end",
3035
+ stretch: "stretch",
3036
+ baseline: "baseline"
3037
+ };
3038
+ var JUSTIFY_MAP = {
3039
+ start: "flex-start",
3040
+ center: "center",
3041
+ end: "flex-end",
3042
+ between: "space-between",
3043
+ around: "space-around",
3044
+ evenly: "space-evenly",
3045
+ stretch: "stretch"
3046
+ };
3047
+ function resolveBaseStyles(props) {
3048
+ const s = {
3049
+ boxSizing: "border-box"
3050
+ };
3051
+ if (props.gap !== undefined)
3052
+ s.gap = space(props.gap);
3053
+ if (props.p !== undefined)
3054
+ s.padding = space(props.p);
3055
+ if (props.px !== undefined) {
3056
+ s.paddingLeft = space(props.px);
3057
+ s.paddingRight = space(props.px);
3058
+ }
3059
+ if (props.py !== undefined) {
3060
+ s.paddingTop = space(props.py);
3061
+ s.paddingBottom = space(props.py);
3062
+ }
3063
+ if (props.pt !== undefined)
3064
+ s.paddingTop = space(props.pt);
3065
+ if (props.pb !== undefined)
3066
+ s.paddingBottom = space(props.pb);
3067
+ if (props.pl !== undefined)
3068
+ s.paddingLeft = space(props.pl);
3069
+ if (props.pr !== undefined)
3070
+ s.paddingRight = space(props.pr);
3071
+ if (props.m !== undefined)
3072
+ s.margin = space(props.m);
3073
+ if (props.mx !== undefined) {
3074
+ s.marginLeft = space(props.mx);
3075
+ s.marginRight = space(props.mx);
3076
+ }
3077
+ if (props.my !== undefined) {
3078
+ s.marginTop = space(props.my);
3079
+ s.marginBottom = space(props.my);
3080
+ }
3081
+ if (props.mt !== undefined)
3082
+ s.marginTop = space(props.mt);
3083
+ if (props.mb !== undefined)
3084
+ s.marginBottom = space(props.mb);
3085
+ if (props.ml !== undefined)
3086
+ s.marginLeft = space(props.ml);
3087
+ if (props.mr !== undefined)
3088
+ s.marginRight = space(props.mr);
3089
+ if (props.w !== undefined)
3090
+ s.width = resolveDimension(props.w);
3091
+ if (props.h !== undefined)
3092
+ s.height = resolveDimension(props.h);
3093
+ if (props.minW !== undefined)
3094
+ s.minWidth = resolveDimension(props.minW);
3095
+ if (props.maxW !== undefined)
3096
+ s.maxWidth = resolveDimension(props.maxW);
3097
+ if (props.minH !== undefined)
3098
+ s.minHeight = resolveDimension(props.minH);
3099
+ if (props.maxH !== undefined)
3100
+ s.maxHeight = resolveDimension(props.maxH);
3101
+ return s;
3102
+ }
3103
+ function mergeStyles(base, userStyle) {
3104
+ if (!userStyle)
3105
+ return base;
3106
+ if (typeof userStyle === "string") {
3107
+ const baseStr = Object.entries(base).map(([k, v]) => `${k.replace(/([A-Z])/g, "-$1").toLowerCase()}: ${v}`).join("; ");
3108
+ return `${baseStr}; ${userStyle}`;
3109
+ }
3110
+ if (typeof userStyle === "object") {
3111
+ return { ...base, ...userStyle };
3112
+ }
3113
+ return base;
3114
+ }
3115
+ function cleanProps(props, excludeKeys) {
3116
+ const result = {};
3117
+ for (const k in props) {
3118
+ if (!excludeKeys.has(k)) {
3119
+ result[k] = props[k];
3120
+ }
3121
+ }
3122
+ return result;
3123
+ }
3124
+ var COMMON_EXCLUDE = new Set([
3125
+ "as",
3126
+ "gap",
3127
+ "p",
3128
+ "px",
3129
+ "py",
3130
+ "pt",
3131
+ "pb",
3132
+ "pl",
3133
+ "pr",
3134
+ "m",
3135
+ "mx",
3136
+ "my",
3137
+ "mt",
3138
+ "mb",
3139
+ "ml",
3140
+ "mr",
3141
+ "w",
3142
+ "h",
3143
+ "minW",
3144
+ "maxW",
3145
+ "minH",
3146
+ "maxH"
3147
+ ]);
3148
+ var STACK_EXCLUDE = new Set([
3149
+ ...COMMON_EXCLUDE,
3150
+ "align",
3151
+ "justify",
3152
+ "direction",
3153
+ "reversed",
3154
+ "wrap",
3155
+ "inline"
3156
+ ]);
3157
+ function Stack(props) {
3158
+ const { as = "div", children, ...rest } = props;
3159
+ const layoutStyles = resolveBaseStyles(props);
3160
+ layoutStyles.display = props.inline ? "inline-flex" : "flex";
3161
+ layoutStyles.flexDirection = props.direction === "horizontal" ? props.reversed ? "row-reverse" : "row" : props.reversed ? "column-reverse" : "column";
3162
+ if (props.align && ALIGN_MAP[props.align]) {
3163
+ layoutStyles.alignItems = ALIGN_MAP[props.align];
3164
+ }
3165
+ if (props.justify && JUSTIFY_MAP[props.justify]) {
3166
+ layoutStyles.justifyContent = JUSTIFY_MAP[props.justify];
3167
+ }
3168
+ if (props.wrap) {
3169
+ layoutStyles.flexWrap = props.wrap === true ? "wrap" : props.wrap;
3170
+ }
3171
+ const domProps = cleanProps(rest, STACK_EXCLUDE);
3172
+ domProps.style = mergeStyles(layoutStyles, props.style);
3173
+ domProps.children = children;
3174
+ return jsx(as, domProps);
3175
+ }
3176
+ var ROW_EXCLUDE = new Set([...COMMON_EXCLUDE, "align", "justify", "reversed", "wrap", "inline"]);
3177
+ function Row(props) {
3178
+ const { as = "div", children, ...rest } = props;
3179
+ const layoutStyles = resolveBaseStyles(props);
3180
+ layoutStyles.display = props.inline ? "inline-flex" : "flex";
3181
+ layoutStyles.flexDirection = props.reversed ? "row-reverse" : "row";
3182
+ layoutStyles.alignItems = props.align ? ALIGN_MAP[props.align] ?? props.align : "center";
3183
+ if (props.justify && JUSTIFY_MAP[props.justify]) {
3184
+ layoutStyles.justifyContent = JUSTIFY_MAP[props.justify];
3185
+ }
3186
+ if (props.wrap) {
3187
+ layoutStyles.flexWrap = props.wrap === true ? "wrap" : props.wrap;
3188
+ }
3189
+ const domProps = cleanProps(rest, ROW_EXCLUDE);
3190
+ domProps.style = mergeStyles(layoutStyles, props.style);
3191
+ domProps.children = children;
3192
+ return jsx(as, domProps);
3193
+ }
3194
+ var CENTER_EXCLUDE = new Set([...COMMON_EXCLUDE, "inline"]);
3195
+ function Center(props) {
3196
+ const { as = "div", children, ...rest } = props;
3197
+ const layoutStyles = resolveBaseStyles(props);
3198
+ layoutStyles.display = props.inline ? "inline-flex" : "flex";
3199
+ layoutStyles.alignItems = "center";
3200
+ layoutStyles.justifyContent = "center";
3201
+ const domProps = cleanProps(rest, CENTER_EXCLUDE);
3202
+ domProps.style = mergeStyles(layoutStyles, props.style);
3203
+ domProps.children = children;
3204
+ return jsx(as, domProps);
3205
+ }
3206
+ var GRID_EXCLUDE = new Set([
3207
+ ...COMMON_EXCLUDE,
3208
+ "columns",
3209
+ "minChildWidth",
3210
+ "rows",
3211
+ "rowGap",
3212
+ "colGap",
3213
+ "align",
3214
+ "justify",
3215
+ "inline"
3216
+ ]);
3217
+ function Grid(props) {
3218
+ const { as = "div", children, ...rest } = props;
3219
+ const layoutStyles = resolveBaseStyles(props);
3220
+ layoutStyles.display = props.inline ? "inline-grid" : "grid";
3221
+ if (props.minChildWidth !== undefined) {
3222
+ const minW = resolveDimension(props.minChildWidth);
3223
+ layoutStyles.gridTemplateColumns = `repeat(auto-fit, minmax(min(100%, ${minW}), 1fr))`;
3224
+ } else if (props.columns !== undefined) {
3225
+ if (typeof props.columns === "number") {
3226
+ layoutStyles.gridTemplateColumns = `repeat(${props.columns}, minmax(0, 1fr))`;
3227
+ } else {
3228
+ layoutStyles.gridTemplateColumns = String(props.columns);
3229
+ }
3230
+ }
3231
+ if (props.rows !== undefined) {
3232
+ if (typeof props.rows === "number") {
3233
+ layoutStyles.gridTemplateRows = `repeat(${props.rows}, minmax(0, 1fr))`;
3234
+ } else {
3235
+ layoutStyles.gridTemplateRows = String(props.rows);
3236
+ }
3237
+ }
3238
+ if (props.rowGap !== undefined)
3239
+ layoutStyles.rowGap = space(props.rowGap);
3240
+ if (props.colGap !== undefined)
3241
+ layoutStyles.columnGap = space(props.colGap);
3242
+ if (props.align) {
3243
+ layoutStyles.alignItems = ALIGN_MAP[props.align] ?? props.align;
3244
+ }
3245
+ if (props.justify) {
3246
+ layoutStyles.justifyItems = props.justify;
3247
+ }
3248
+ const domProps = cleanProps(rest, GRID_EXCLUDE);
3249
+ domProps.style = mergeStyles(layoutStyles, props.style);
3250
+ domProps.children = children;
3251
+ return jsx(as, domProps);
3252
+ }
3253
+ var SPACER_EXCLUDE = new Set([...COMMON_EXCLUDE, "size", "x", "y", "flex"]);
3254
+ function Spacer(props) {
3255
+ const { as = "div", ...rest } = props;
3256
+ const layoutStyles = resolveBaseStyles(props);
3257
+ if (props.size !== undefined) {
3258
+ const s = space(props.size);
3259
+ layoutStyles.width = s;
3260
+ layoutStyles.height = s;
3261
+ layoutStyles.flexShrink = "0";
3262
+ } else if (props.x !== undefined || props.y !== undefined) {
3263
+ if (props.x !== undefined)
3264
+ layoutStyles.width = space(props.x);
3265
+ if (props.y !== undefined)
3266
+ layoutStyles.height = space(props.y);
3267
+ layoutStyles.flexShrink = "0";
3268
+ } else {
3269
+ layoutStyles.flex = typeof props.flex === "number" ? String(props.flex) : "1 1 0%";
3270
+ layoutStyles.alignSelf = "stretch";
3271
+ }
3272
+ const domProps = cleanProps(rest, SPACER_EXCLUDE);
3273
+ domProps.style = mergeStyles(layoutStyles, props.style);
3274
+ return jsx(as, domProps);
3275
+ }
3276
+ // src/ui/popover.tsx
3277
+ var PopoverContext = createContext(null);
3278
+ function usePopoverContext() {
3279
+ return useContext(PopoverContext);
3280
+ }
3281
+ function PopoverRoot(props) {
3282
+ const [open, setOpen] = createControllableSignal({
3283
+ value: props.open,
3284
+ defaultValue: props.defaultOpen ?? false,
3285
+ onChange: props.onOpenChange
3286
+ });
3287
+ const triggerRef = { current: null };
3288
+ const contentRef = { current: null };
3289
+ const contentId = createId("popover-content");
3290
+ const ctx = {
3291
+ open,
3292
+ setOpen,
3293
+ triggerRef,
3294
+ contentRef,
3295
+ contentId
3296
+ };
3297
+ if (props.trigger !== undefined || props.content !== undefined) {
3298
+ return PopoverContext.Provider({
3299
+ value: ctx,
3300
+ children: () => /* @__PURE__ */ jsxs(Fragment, {
3301
+ children: [
3302
+ props.trigger ? /* @__PURE__ */ jsx(PopoverTrigger, {
3303
+ as: "span",
3304
+ class: props.triggerClass,
3305
+ children: typeof props.trigger === "function" ? props.trigger() : props.trigger
3306
+ }) : null,
3307
+ /* @__PURE__ */ jsxs(PopoverContent, {
3308
+ portalled: props.portalled,
3309
+ class: props.contentClass,
3310
+ children: [
3311
+ typeof props.content === "function" ? props.content() : props.content,
3312
+ typeof props.children === "function" ? props.children() : props.children
3313
+ ]
3314
+ })
3315
+ ]
3316
+ })
3317
+ });
3318
+ }
3319
+ return PopoverContext.Provider({
3320
+ value: ctx,
3321
+ children: props.children
3322
+ });
3323
+ }
3324
+ function PopoverTrigger(props) {
3325
+ const ctx = useContext(PopoverContext);
3326
+ const handleClick = (e) => {
3327
+ if (props.onClick)
3328
+ props.onClick(e);
3329
+ if (!e.defaultPrevented && ctx) {
3330
+ ctx.setOpen(!ctx.open());
3331
+ }
3332
+ };
3333
+ const { as: Tag = "button", children, onClick, class: className, style, ...rest } = props;
3334
+ return /* @__PURE__ */ jsx(Tag, {
3335
+ ref: (el) => {
3336
+ if (ctx)
3337
+ ctx.triggerRef.current = el;
3338
+ },
3339
+ type: Tag === "button" ? "button" : undefined,
3340
+ "aria-haspopup": "dialog",
3341
+ "aria-expanded": () => ctx?.open() ?? false,
3342
+ "aria-controls": ctx?.contentId,
3343
+ "data-state": () => ctx?.open() ? "open" : "closed",
3344
+ class: className,
3345
+ style,
3346
+ onClick: handleClick,
3347
+ ...rest,
3348
+ children
3349
+ });
3350
+ }
3351
+ function PopoverPortal(props) {
3352
+ return /* @__PURE__ */ jsx(Portal, {
3353
+ mount: props.mount,
3354
+ children: props.children
3355
+ });
3356
+ }
3357
+ function PopoverContent(props) {
3358
+ const ctx = useContext(PopoverContext);
3359
+ const handleKeyDown = (e) => {
3360
+ if (props.onKeyDown)
3361
+ props.onKeyDown(e);
3362
+ if (e.defaultPrevented)
3363
+ return;
3364
+ if (e.key === "Escape" && ctx) {
3365
+ ctx.setOpen(false);
3366
+ ctx.triggerRef.current?.focus();
3367
+ e.stopPropagation();
3368
+ }
3369
+ };
3370
+ const handleClick = (e) => {
3371
+ if (props.onClick)
3372
+ props.onClick(e);
3373
+ if (e.defaultPrevented)
3374
+ return;
3375
+ const target = e.target;
3376
+ if (target?.closest("[data-popover-close]")) {
3377
+ ctx?.setOpen(false);
3378
+ }
3379
+ };
3380
+ const {
3381
+ as: Tag = "div",
3382
+ children,
3383
+ onKeyDown,
3384
+ onClick: _onClick,
3385
+ class: className,
3386
+ style,
3387
+ portalled = true,
3388
+ mount,
3389
+ ...rest
3390
+ } = props;
3391
+ const content = /* @__PURE__ */ jsx(Tag, {
3392
+ ref: (el) => {
3393
+ if (ctx) {
3394
+ ctx.contentRef.current = el;
3395
+ if (el) {
3396
+ const cleanup = onClickOutside([ctx.triggerRef.current, el], () => {
3397
+ if (ctx.open()) {
3398
+ ctx.setOpen(false);
3399
+ }
3400
+ });
3401
+ onCleanup(cleanup);
3402
+ }
3403
+ }
3404
+ },
3405
+ id: ctx?.contentId,
3406
+ role: "dialog",
3407
+ "data-state": () => ctx?.open() ? "open" : "closed",
3408
+ class: className,
3409
+ style: () => ({
3410
+ display: ctx?.open() ? undefined : "none",
3411
+ ...style
3412
+ }),
3413
+ onKeyDown: handleKeyDown,
3414
+ onClick: handleClick,
3415
+ tabIndex: -1,
3416
+ ...rest,
3417
+ children
3418
+ });
3419
+ return portalled ? /* @__PURE__ */ jsx(Portal, {
3420
+ mount,
3421
+ children: content
3422
+ }) : content;
3423
+ }
3424
+ function PopoverClose(props) {
3425
+ const ctx = useContext(PopoverContext);
3426
+ const handleClick = (e) => {
3427
+ if (props.onClick)
3428
+ props.onClick(e);
3429
+ if (!e.defaultPrevented && ctx) {
3430
+ ctx.setOpen(false);
3431
+ }
3432
+ };
3433
+ const { as: Tag = "button", children, onClick, class: className, style, ...rest } = props;
3434
+ return /* @__PURE__ */ jsx(Tag, {
3435
+ type: Tag === "button" ? "button" : undefined,
3436
+ "data-popover-close": "",
3437
+ class: className,
3438
+ style,
3439
+ onClick: handleClick,
3440
+ ...rest,
3441
+ children
3442
+ });
3443
+ }
3444
+ var Popover = Object.assign(PopoverRoot, {
3445
+ Root: PopoverRoot,
3446
+ Trigger: PopoverTrigger,
3447
+ Portal: PopoverPortal,
3448
+ Content: PopoverContent,
3449
+ Close: PopoverClose
3450
+ });
3451
+ // src/ui/switch.tsx
3452
+ function SwitchRoot(props) {
3453
+ const [checked, setChecked] = createControllableSignal({
3454
+ value: props.checked,
3455
+ defaultValue: props.defaultChecked ?? false,
3456
+ onChange: props.onCheckedChange
3457
+ });
3458
+ const toggle = () => {
3459
+ const isDisabled = typeof props.disabled === "function" ? props.disabled() : Boolean(props.disabled);
3460
+ if (isDisabled)
3461
+ return;
3462
+ setChecked(!checked());
3463
+ };
3464
+ const handleClick = (e) => {
3465
+ if (props.onClick)
3466
+ props.onClick(e);
3467
+ if (!e.defaultPrevented) {
3468
+ toggle();
3469
+ }
3470
+ };
3471
+ const handleKeyDown = (e) => {
3472
+ if (props.onKeyDown)
3473
+ props.onKeyDown(e);
3474
+ if (e.key === "Enter" || e.key === " ") {
3475
+ e.preventDefault();
3476
+ toggle();
3477
+ }
3478
+ };
3479
+ const {
3480
+ checked: _c,
3481
+ defaultChecked: _dc,
3482
+ onCheckedChange: _occ,
3483
+ disabled,
3484
+ required,
3485
+ name,
3486
+ value,
3487
+ thumbClass,
3488
+ thumbStyle,
3489
+ as: Tag = "button",
3490
+ children,
3491
+ onClick,
3492
+ onKeyDown,
3493
+ class: className,
3494
+ style,
3495
+ ...rest
3496
+ } = props;
3497
+ return /* @__PURE__ */ jsx(Tag, {
3498
+ type: Tag === "button" ? "button" : undefined,
3499
+ role: "switch",
3500
+ "aria-checked": checked,
3501
+ "data-state": () => checked() ? "checked" : "unchecked",
3502
+ disabled,
3503
+ class: className,
3504
+ style,
3505
+ onClick: handleClick,
3506
+ onKeyDown: handleKeyDown,
3507
+ ...rest,
3508
+ children: children !== undefined ? typeof children === "function" ? children() : children : /* @__PURE__ */ jsx(SwitchThumb, {
3509
+ class: thumbClass,
3510
+ style: thumbStyle
3511
+ })
3512
+ });
3513
+ }
3514
+ function SwitchThumb(props) {
3515
+ const { as: Tag = "span", class: className, style, ...rest } = props;
3516
+ return /* @__PURE__ */ jsx(Tag, {
3517
+ class: className,
3518
+ style,
3519
+ ...rest
3520
+ });
3521
+ }
3522
+ var Switch = Object.assign(SwitchRoot, {
3523
+ Root: SwitchRoot,
3524
+ Thumb: SwitchThumb
3525
+ });
3526
+ // src/ui/tabs.tsx
3527
+ var TabsContext = createContext(null);
3528
+ function useTabsContext() {
3529
+ return useContext(TabsContext);
3530
+ }
3531
+ function TabsRoot(props) {
3532
+ const [value, setValue] = createControllableSignal({
3533
+ value: props.value,
3534
+ defaultValue: props.defaultValue ?? (props.items && props.items.length > 0 ? props.items[0]?.value : ""),
3535
+ onChange: props.onValueChange
3536
+ });
3537
+ const baseId = createId("tabs");
3538
+ const orientation = props.orientation ?? "horizontal";
3539
+ const activationMode = props.activationMode ?? "automatic";
3540
+ const ctx = {
3541
+ value,
3542
+ setValue,
3543
+ orientation,
3544
+ activationMode,
3545
+ baseId
3546
+ };
3547
+ const {
3548
+ as: Tag = "div",
3549
+ value: _v,
3550
+ defaultValue: _dv,
3551
+ onValueChange: _ovc,
3552
+ orientation: _ori,
3553
+ activationMode: _am,
3554
+ items,
3555
+ listClass,
3556
+ triggerClass,
3557
+ contentClass,
3558
+ children,
3559
+ class: className,
3560
+ style,
3561
+ ...rest
3562
+ } = props;
3563
+ return TabsContext.Provider({
3564
+ value: ctx,
3565
+ children: () => /* @__PURE__ */ jsxs(Tag, {
3566
+ "data-orientation": orientation,
3567
+ class: className,
3568
+ style,
3569
+ ...rest,
3570
+ children: [
3571
+ items ? /* @__PURE__ */ jsxs(Fragment, {
3572
+ children: [
3573
+ /* @__PURE__ */ jsx(TabsList, {
3574
+ class: listClass,
3575
+ children: items.map((item) => /* @__PURE__ */ jsxs(TabsTrigger, {
3576
+ value: item.value,
3577
+ disabled: item.disabled,
3578
+ class: triggerClass,
3579
+ children: [
3580
+ item.icon ? /* @__PURE__ */ jsx("span", {
3581
+ class: "tab-icon",
3582
+ style: { display: "inline-flex", alignItems: "center" },
3583
+ children: typeof item.icon === "function" ? item.icon() : item.icon
3584
+ }) : null,
3585
+ typeof item.label === "function" ? item.label() : item.label
3586
+ ]
3587
+ }))
3588
+ }),
3589
+ items.map((item) => /* @__PURE__ */ jsx(TabsContent, {
3590
+ value: item.value,
3591
+ class: contentClass,
3592
+ children: typeof item.content === "function" ? item.content() : item.content
3593
+ }))
3594
+ ]
3595
+ }) : null,
3596
+ typeof children === "function" ? children() : children
3597
+ ]
3598
+ })
3599
+ });
3600
+ }
3601
+ function TabsList(props) {
3602
+ const ctx = useContext(TabsContext);
3603
+ const handleKeyDown = (e) => {
3604
+ if (props.onKeyDown)
3605
+ props.onKeyDown(e);
3606
+ if (e.defaultPrevented)
3607
+ return;
3608
+ const target = e.target;
3609
+ if (target?.getAttribute("role") !== "tab")
3610
+ return;
3611
+ const list = target.closest('[role="tablist"]');
3612
+ if (!list)
3613
+ return;
3614
+ const tabs = Array.from(list.querySelectorAll('[role="tab"]:not([disabled])'));
3615
+ const index = tabs.indexOf(target);
3616
+ if (index === -1)
3617
+ return;
3618
+ let nextIndex = index;
3619
+ const isHorizontal = (ctx?.orientation ?? "horizontal") === "horizontal";
3620
+ const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
3621
+ const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
3622
+ if (e.key === prevKey) {
3623
+ nextIndex = index === 0 ? tabs.length - 1 : index - 1;
3624
+ e.preventDefault();
3625
+ } else if (e.key === nextKey) {
3626
+ nextIndex = index === tabs.length - 1 ? 0 : index + 1;
3627
+ e.preventDefault();
3628
+ } else if (e.key === "Home") {
3629
+ nextIndex = 0;
3630
+ e.preventDefault();
3631
+ } else if (e.key === "End") {
3632
+ nextIndex = tabs.length - 1;
3633
+ e.preventDefault();
3634
+ }
3635
+ if (nextIndex !== index) {
3636
+ const nextTab = tabs[nextIndex];
3637
+ nextTab.focus();
3638
+ if (ctx?.activationMode === "automatic") {
3639
+ const val = nextTab.getAttribute("data-value");
3640
+ if (val)
3641
+ ctx.setValue(val);
3642
+ }
3643
+ }
3644
+ };
3645
+ const { as: Tag = "div", children, onKeyDown, class: className, style, ...rest } = props;
3646
+ return /* @__PURE__ */ jsx(Tag, {
3647
+ role: "tablist",
3648
+ "aria-orientation": ctx?.orientation ?? "horizontal",
3649
+ class: className,
3650
+ style,
3651
+ onKeyDown: handleKeyDown,
3652
+ ...rest,
3653
+ children
3654
+ });
3655
+ }
3656
+ function TabsTrigger(props) {
3657
+ const ctx = useContext(TabsContext);
3658
+ const isSelected = () => ctx ? ctx.value() === props.value : false;
3659
+ const handleClick = (e) => {
3660
+ if (props.onClick)
3661
+ props.onClick(e);
3662
+ if (!e.defaultPrevented && ctx) {
3663
+ ctx.setValue(props.value);
3664
+ }
3665
+ };
3666
+ const {
3667
+ value,
3668
+ disabled,
3669
+ as: Tag = "button",
3670
+ children,
3671
+ onClick,
3672
+ class: className,
3673
+ style,
3674
+ ...rest
3675
+ } = props;
3676
+ return /* @__PURE__ */ jsx(Tag, {
3677
+ id: ctx ? `${ctx.baseId}-trigger-${value}` : undefined,
3678
+ type: Tag === "button" ? "button" : undefined,
3679
+ role: "tab",
3680
+ "aria-selected": isSelected,
3681
+ "aria-controls": ctx ? `${ctx.baseId}-panel-${value}` : undefined,
3682
+ "data-state": () => isSelected() ? "active" : "inactive",
3683
+ "data-value": value,
3684
+ tabIndex: () => isSelected() ? 0 : -1,
3685
+ disabled,
3686
+ class: className,
3687
+ style,
3688
+ onClick: handleClick,
3689
+ ...rest,
3690
+ children
3691
+ });
3692
+ }
3693
+ function TabsContent(props) {
3694
+ const ctx = useContext(TabsContext);
3695
+ const isSelected = () => ctx ? ctx.value() === props.value : false;
3696
+ const { value, forceMount, as: Tag = "div", children, class: className, style, ...rest } = props;
3697
+ if (forceMount) {
3698
+ return /* @__PURE__ */ jsx(Tag, {
3699
+ id: ctx ? `${ctx.baseId}-panel-${value}` : undefined,
3700
+ role: "tabpanel",
3701
+ "aria-labelledby": ctx ? `${ctx.baseId}-trigger-${value}` : undefined,
3702
+ "data-state": () => isSelected() ? "active" : "inactive",
3703
+ hidden: () => !isSelected(),
3704
+ tabIndex: 0,
3705
+ class: className,
3706
+ style,
3707
+ ...rest,
3708
+ children
3709
+ });
3710
+ }
3711
+ return /* @__PURE__ */ jsx(Show, {
3712
+ when: isSelected,
3713
+ children: /* @__PURE__ */ jsx(Tag, {
3714
+ id: ctx ? `${ctx.baseId}-panel-${value}` : undefined,
3715
+ role: "tabpanel",
3716
+ "aria-labelledby": ctx ? `${ctx.baseId}-trigger-${value}` : undefined,
3717
+ "data-state": "active",
3718
+ tabIndex: 0,
3719
+ class: className,
3720
+ style,
3721
+ ...rest,
3722
+ children
3723
+ })
3724
+ });
3725
+ }
3726
+ var Tabs = Object.assign(TabsRoot, {
3727
+ Root: TabsRoot,
3728
+ List: TabsList,
3729
+ Trigger: TabsTrigger,
3730
+ Content: TabsContent
3731
+ });
3732
+ // src/ui/toast.tsx
3733
+ function createToastManager() {
3734
+ const toasts = signal([]);
3735
+ const dismiss = (id) => {
3736
+ const item = toasts().find((t) => t.id === id);
3737
+ if (item?.onDismiss)
3738
+ item.onDismiss();
3739
+ toasts.update((list) => list.filter((t) => t.id !== id));
3740
+ };
3741
+ const show = (options) => {
3742
+ const id = createId("toast");
3743
+ const normalized = typeof options === "string" ? { title: options } : options;
3744
+ const data = {
3745
+ id,
3746
+ title: normalized.title,
3747
+ description: normalized.description,
3748
+ variant: normalized.variant ?? "default",
3749
+ duration: normalized.duration ?? 5000,
3750
+ onDismiss: normalized.onDismiss
3751
+ };
3752
+ toasts.update((list) => [...list, data]);
3753
+ if (data.duration && data.duration > 0) {
3754
+ setTimeout(() => {
3755
+ dismiss(id);
3756
+ }, data.duration);
3757
+ }
3758
+ return id;
3759
+ };
3760
+ const success = (title, options) => show({ ...options, title, variant: "success" });
3761
+ const error = (title, options) => show({ ...options, title, variant: "error" });
3762
+ const warning = (title, options) => show({ ...options, title, variant: "warning" });
3763
+ const info = (title, options) => show({ ...options, title, variant: "info" });
3764
+ const clear = () => {
3765
+ toasts.set([]);
3766
+ };
3767
+ const fn = function toast(options) {
3768
+ return show(options);
3769
+ };
3770
+ fn.toasts = toasts;
3771
+ fn.show = show;
3772
+ fn.success = success;
3773
+ fn.error = error;
3774
+ fn.warning = warning;
3775
+ fn.info = info;
3776
+ fn.dismiss = dismiss;
3777
+ fn.clear = clear;
3778
+ return fn;
3779
+ }
3780
+ var defaultToastManager = createToastManager();
3781
+ var toast = defaultToastManager;
3782
+ var ToastContext = createContext(defaultToastManager);
3783
+ function useToast() {
3784
+ return useContext(ToastContext) ?? defaultToastManager;
3785
+ }
3786
+ function ToastProvider(props) {
3787
+ const manager = props.manager ?? defaultToastManager;
3788
+ return ToastContext.Provider({
3789
+ value: manager,
3790
+ children: props.children
3791
+ });
3792
+ }
3793
+ function ToastViewport(props) {
3794
+ const manager = useToast();
3795
+ const { as: Tag = "section", children, class: className, style, ...rest } = props;
3796
+ const defaultRender = (t) => /* @__PURE__ */ jsxs(Toast, {
3797
+ id: t.id,
3798
+ variant: t.variant,
3799
+ class: `visage-toast toast toast-${t.variant ?? "default"}`,
3800
+ onDismiss: () => manager.dismiss(t.id),
3801
+ children: [
3802
+ /* @__PURE__ */ jsxs("div", {
3803
+ class: "visage-toast-content",
3804
+ children: [
3805
+ t.title && /* @__PURE__ */ jsx(ToastTitle, {
3806
+ class: "visage-toast-title",
3807
+ children: t.title
3808
+ }),
3809
+ t.description && /* @__PURE__ */ jsx(ToastDescription, {
3810
+ class: "visage-toast-description",
3811
+ children: t.description
3812
+ })
3813
+ ]
3814
+ }),
3815
+ /* @__PURE__ */ jsx(ToastClose, {
3816
+ class: "visage-toast-close",
3817
+ onClick: () => manager.dismiss(t.id)
3818
+ })
3819
+ ]
3820
+ });
3821
+ const renderItem = children ?? defaultRender;
3822
+ return /* @__PURE__ */ jsx(Tag, {
3823
+ role: "region",
3824
+ "aria-label": "Notifications",
3825
+ class: className,
3826
+ style,
3827
+ tabIndex: -1,
3828
+ ...rest,
3829
+ children: /* @__PURE__ */ jsx(For, {
3830
+ each: manager.toasts,
3831
+ children: (t) => renderItem(t)
3832
+ })
3833
+ });
3834
+ }
3835
+ function ToastRoot(props) {
3836
+ const {
3837
+ id,
3838
+ variant = "default",
3839
+ onDismiss,
3840
+ as: Tag = "div",
3841
+ children,
3842
+ class: className,
3843
+ style,
3844
+ ...rest
3845
+ } = props;
3846
+ const role = variant === "error" ? "alert" : "status";
3847
+ const ariaLive = variant === "error" ? "assertive" : "polite";
3848
+ return /* @__PURE__ */ jsx(Tag, {
3849
+ id,
3850
+ role,
3851
+ "aria-live": ariaLive,
3852
+ "data-variant": variant,
3853
+ "data-state": "open",
3854
+ class: className,
3855
+ style,
3856
+ ...rest,
3857
+ children
3858
+ });
3859
+ }
3860
+ function ToastTitle(props) {
3861
+ const { as: Tag = "div", children, class: className, style, ...rest } = props;
3862
+ return /* @__PURE__ */ jsx(Tag, {
3863
+ class: className,
3864
+ style,
3865
+ ...rest,
3866
+ children
3867
+ });
3868
+ }
3869
+ function ToastDescription(props) {
3870
+ const { as: Tag = "div", children, class: className, style, ...rest } = props;
3871
+ return /* @__PURE__ */ jsx(Tag, {
3872
+ class: className,
3873
+ style,
3874
+ ...rest,
3875
+ children
3876
+ });
3877
+ }
3878
+ function ToastClose(props) {
3879
+ const { as: Tag = "button", children = "✕", onClick, class: className, style, ...rest } = props;
3880
+ return /* @__PURE__ */ jsx(Tag, {
3881
+ type: Tag === "button" ? "button" : undefined,
3882
+ "aria-label": "Close notification",
3883
+ class: className,
3884
+ style,
3885
+ onClick,
3886
+ ...rest,
3887
+ children
3888
+ });
3889
+ }
3890
+ var Toast = Object.assign(ToastRoot, {
3891
+ Root: ToastRoot,
3892
+ Provider: ToastProvider,
3893
+ Viewport: ToastViewport,
3894
+ Title: ToastTitle,
3895
+ Description: ToastDescription,
3896
+ Close: ToastClose
3897
+ });
3898
+ // src/ui/tooltip.tsx
3899
+ var TooltipContext = createContext(null);
3900
+ function useTooltipContext() {
3901
+ return useContext(TooltipContext);
3902
+ }
3903
+ function TooltipRoot(props) {
3904
+ const [open, setOpen] = createControllableSignal({
3905
+ value: props.open,
3906
+ defaultValue: props.defaultOpen ?? false,
3907
+ onChange: props.onOpenChange
3908
+ });
3909
+ const tooltipId = createId("tooltip");
3910
+ const triggerRef = { current: null };
3911
+ const ctx = {
3912
+ open,
3913
+ setOpen,
3914
+ openDelay: props.openDelay ?? 150,
3915
+ closeDelay: props.closeDelay ?? 100,
3916
+ tooltipId,
3917
+ triggerRef
3918
+ };
3919
+ if (props.content !== undefined) {
3920
+ return TooltipContext.Provider({
3921
+ value: ctx,
3922
+ children: () => /* @__PURE__ */ jsxs("span", {
3923
+ class: "visage-tooltip-root",
3924
+ style: { position: "relative", display: "inline-flex", alignItems: "center" },
3925
+ children: [
3926
+ /* @__PURE__ */ jsx(TooltipTrigger, {
3927
+ as: props.triggerAs ?? "button",
3928
+ class: props.triggerClass,
3929
+ style: {
3930
+ background: "transparent",
3931
+ border: "none",
3932
+ padding: 0,
3933
+ display: "inline-flex",
3934
+ alignItems: "center",
3935
+ cursor: "help"
3936
+ },
3937
+ children: typeof props.children === "function" ? props.children() : props.children
3938
+ }),
3939
+ /* @__PURE__ */ jsx(TooltipContent, {
3940
+ side: props.side,
3941
+ class: props.contentClass,
3942
+ style: props.contentStyle,
3943
+ portalled: props.portalled ?? false,
3944
+ children: typeof props.content === "function" ? props.content() : props.content
3945
+ })
3946
+ ]
3947
+ })
3948
+ });
3949
+ }
3950
+ return TooltipContext.Provider({
3951
+ value: ctx,
3952
+ children: props.children
3953
+ });
3954
+ }
3955
+ function TooltipTrigger(props) {
3956
+ const ctx = useContext(TooltipContext);
3957
+ let openTimer = null;
3958
+ let closeTimer = null;
3959
+ const clearTimers = () => {
3960
+ if (openTimer)
3961
+ clearTimeout(openTimer);
3962
+ if (closeTimer)
3963
+ clearTimeout(closeTimer);
3964
+ openTimer = null;
3965
+ closeTimer = null;
3966
+ };
3967
+ const handleMouseEnter = (e) => {
3968
+ if (props.onMouseEnter)
3969
+ props.onMouseEnter(e);
3970
+ clearTimers();
3971
+ if (!ctx)
3972
+ return;
3973
+ if (ctx.openDelay > 0) {
3974
+ openTimer = setTimeout(() => ctx.setOpen(true), ctx.openDelay);
3975
+ } else {
3976
+ ctx.setOpen(true);
3977
+ }
3978
+ };
3979
+ const handleMouseLeave = (e) => {
3980
+ if (props.onMouseLeave)
3981
+ props.onMouseLeave(e);
3982
+ clearTimers();
3983
+ if (!ctx)
3984
+ return;
3985
+ if (ctx.closeDelay > 0) {
3986
+ closeTimer = setTimeout(() => ctx.setOpen(false), ctx.closeDelay);
3987
+ } else {
3988
+ ctx.setOpen(false);
3989
+ }
3990
+ };
3991
+ const handleFocus = (e) => {
3992
+ if (props.onFocus)
3993
+ props.onFocus(e);
3994
+ clearTimers();
3995
+ ctx?.setOpen(true);
3996
+ };
3997
+ const handleBlur = (e) => {
3998
+ if (props.onBlur)
3999
+ props.onBlur(e);
4000
+ clearTimers();
4001
+ ctx?.setOpen(false);
4002
+ };
4003
+ onCleanup(clearTimers);
4004
+ const {
4005
+ as: Tag = "button",
4006
+ children,
4007
+ onMouseEnter,
4008
+ onMouseLeave,
4009
+ onFocus,
4010
+ onBlur,
4011
+ class: className,
4012
+ style,
4013
+ ...rest
4014
+ } = props;
4015
+ return /* @__PURE__ */ jsx(Tag, {
4016
+ ref: (el) => {
4017
+ if (ctx)
4018
+ ctx.triggerRef.current = el;
4019
+ },
4020
+ type: Tag === "button" ? "button" : undefined,
4021
+ tabIndex: Tag === "button" ? undefined : 0,
4022
+ "aria-describedby": ctx?.tooltipId,
4023
+ "data-state": () => ctx?.open() ? "open" : "closed",
4024
+ class: className,
4025
+ style: { display: "inline-flex", alignItems: "center", ...style },
4026
+ onMouseEnter: handleMouseEnter,
4027
+ onMouseLeave: handleMouseLeave,
4028
+ onFocus: handleFocus,
4029
+ onBlur: handleBlur,
4030
+ ...rest,
4031
+ children
4032
+ });
4033
+ }
4034
+ function TooltipPortal(props) {
4035
+ return /* @__PURE__ */ jsx(Portal, {
4036
+ mount: props.mount,
4037
+ children: props.children
4038
+ });
4039
+ }
4040
+ function TooltipContent(props) {
4041
+ const ctx = useContext(TooltipContext);
4042
+ const isOpen = () => ctx ? ctx.open() : false;
4043
+ const {
4044
+ forceMount,
4045
+ as: Tag = "div",
4046
+ children,
4047
+ class: className,
4048
+ style,
4049
+ portalled = true,
4050
+ mount,
4051
+ ...rest
4052
+ } = props;
4053
+ const content = forceMount ? /* @__PURE__ */ jsx(Tag, {
4054
+ id: ctx?.tooltipId,
4055
+ role: "tooltip",
4056
+ "data-state": () => isOpen() ? "open" : "closed",
4057
+ hidden: () => !isOpen(),
4058
+ class: className,
4059
+ style,
4060
+ ...rest,
4061
+ children
4062
+ }) : /* @__PURE__ */ jsx(Show, {
4063
+ when: isOpen,
4064
+ children: /* @__PURE__ */ jsx(Tag, {
4065
+ id: ctx?.tooltipId,
4066
+ role: "tooltip",
4067
+ "data-state": "open",
4068
+ class: className,
4069
+ style,
4070
+ ...rest,
4071
+ children
4072
+ })
4073
+ });
4074
+ return portalled ? /* @__PURE__ */ jsx(Portal, {
4075
+ mount,
4076
+ children: content
4077
+ }) : content;
4078
+ }
4079
+ var Tooltip = Object.assign(TooltipRoot, {
4080
+ Root: TooltipRoot,
4081
+ Trigger: TooltipTrigger,
4082
+ Portal: TooltipPortal,
4083
+ Content: TooltipContent
4084
+ });
4085
+ export {
4086
+ Accordion,
4087
+ AccordionContent,
4088
+ AccordionItem,
4089
+ AccordionTrigger,
4090
+ Center,
4091
+ Command,
4092
+ CommandDialog,
4093
+ CommandEmpty,
4094
+ CommandGroup,
4095
+ CommandInput,
4096
+ CommandItem,
4097
+ CommandList,
4098
+ DataTable,
4099
+ Dialog,
4100
+ DialogClose,
4101
+ DialogContent,
4102
+ DialogDescription,
4103
+ DialogOverlay,
4104
+ DialogPortal,
4105
+ DialogTitle,
4106
+ DialogTrigger,
4107
+ DropdownMenu,
4108
+ DropdownMenuContent,
4109
+ DropdownMenuItem,
4110
+ DropdownMenuPortal,
4111
+ DropdownMenuSeparator,
4112
+ DropdownMenuTrigger,
4113
+ Grid,
4114
+ Popover,
4115
+ PopoverClose,
4116
+ PopoverContent,
4117
+ PopoverPortal,
4118
+ PopoverTrigger,
4119
+ Row,
4120
+ Spacer,
4121
+ Stack,
4122
+ Switch,
4123
+ SwitchThumb,
4124
+ Tabs,
4125
+ TabsContent,
4126
+ TabsList,
4127
+ TabsTrigger,
4128
+ Toast,
4129
+ ToastClose,
4130
+ ToastDescription,
4131
+ ToastProvider,
4132
+ ToastTitle,
4133
+ ToastViewport,
4134
+ Tooltip,
4135
+ TooltipContent,
4136
+ TooltipPortal,
4137
+ TooltipTrigger,
4138
+ createControllableSignal,
4139
+ createIcon,
4140
+ createId,
4141
+ createToastManager,
4142
+ defaultToastManager,
4143
+ onClickOutside,
4144
+ toast,
4145
+ trapFocus,
4146
+ useAccordionContext,
4147
+ useAccordionItemContext,
4148
+ useCommandContext,
4149
+ useDialogContext,
4150
+ useDropdownMenuContext,
4151
+ usePopoverContext,
4152
+ useTabsContext,
4153
+ useToast,
4154
+ useTooltipContext
4155
+ };