@epoch32/visage 0.0.0-stage → 1.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 (135) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +110 -2
  3. package/dist/src/api/index.js +4002 -0
  4. package/dist/src/charts/index.js +2717 -0
  5. package/dist/src/devtools/index.js +4677 -0
  6. package/dist/src/dom/index.js +1550 -0
  7. package/dist/src/form/index.js +1415 -0
  8. package/dist/src/index.js +11826 -0
  9. package/dist/src/jsx-runtime/index.js +1630 -0
  10. package/dist/src/query/index.js +2422 -0
  11. package/dist/src/router/index.js +1856 -0
  12. package/dist/src/rpc/index.js +3484 -0
  13. package/dist/src/server/index.js +1173 -0
  14. package/dist/src/signals/index.js +1077 -0
  15. package/dist/src/style/index.js +2340 -0
  16. package/dist/src/template/index.js +1149 -0
  17. package/dist/src/ui/index.js +4155 -0
  18. package/dist/src/virtual/index.js +1955 -0
  19. package/dist/src/vite/index.js +984 -0
  20. package/package.json +140 -4
  21. package/src/api/client.ts +371 -0
  22. package/src/api/file-router.ts +183 -0
  23. package/src/api/handler.ts +326 -0
  24. package/src/api/index.ts +71 -0
  25. package/src/api/middleware.ts +54 -0
  26. package/src/api/pragma.ts +155 -0
  27. package/src/api/procedure.ts +172 -0
  28. package/src/api/types.ts +249 -0
  29. package/src/charts/Area.tsx +111 -0
  30. package/src/charts/Axis.tsx +126 -0
  31. package/src/charts/Bar.tsx +86 -0
  32. package/src/charts/CartesianGrid.tsx +72 -0
  33. package/src/charts/Chart.tsx +269 -0
  34. package/src/charts/Cursor.tsx +42 -0
  35. package/src/charts/Legend.tsx +56 -0
  36. package/src/charts/Line.tsx +106 -0
  37. package/src/charts/Pie.tsx +88 -0
  38. package/src/charts/Tooltip.tsx +127 -0
  39. package/src/charts/context.ts +30 -0
  40. package/src/charts/index.ts +14 -0
  41. package/src/charts/path.ts +155 -0
  42. package/src/charts/scale.ts +133 -0
  43. package/src/charts/types.ts +50 -0
  44. package/src/devtools/DomTab.tsx +134 -0
  45. package/src/devtools/GraphInspector.tsx +196 -0
  46. package/src/devtools/GraphTab.tsx +315 -0
  47. package/src/devtools/QueryTab.tsx +200 -0
  48. package/src/devtools/RpcTab.tsx +190 -0
  49. package/src/devtools/SignalsTab.tsx +129 -0
  50. package/src/devtools/component.tsx +243 -0
  51. package/src/devtools/highlighter.ts +134 -0
  52. package/src/devtools/hub.ts +175 -0
  53. package/src/devtools/index.ts +20 -0
  54. package/src/devtools/styles.ts +313 -0
  55. package/src/devtools/types.ts +45 -0
  56. package/src/dom/async.ts +232 -0
  57. package/src/dom/control-flow.ts +353 -0
  58. package/src/dom/index.ts +32 -0
  59. package/src/dom/lazy.ts +82 -0
  60. package/src/dom/render.ts +286 -0
  61. package/src/dom/resource.ts +120 -0
  62. package/src/form/form.ts +218 -0
  63. package/src/form/index.ts +17 -0
  64. package/src/form/schema.ts +299 -0
  65. package/src/index.ts +413 -0
  66. package/src/jsx-dev-runtime/index.ts +1 -0
  67. package/src/jsx-runtime/index.ts +112 -0
  68. package/src/jsx-runtime/jsx.d.ts +278 -0
  69. package/src/query/create-mutation.ts +64 -0
  70. package/src/query/create-query.ts +426 -0
  71. package/src/query/focus-manager.ts +68 -0
  72. package/src/query/index.ts +63 -0
  73. package/src/query/mutation-cache.ts +138 -0
  74. package/src/query/online-manager.ts +67 -0
  75. package/src/query/query-cache.ts +369 -0
  76. package/src/query/query-client.ts +248 -0
  77. package/src/query/types.ts +221 -0
  78. package/src/query/utils.ts +132 -0
  79. package/src/router/index.ts +19 -0
  80. package/src/router/router.tsx +352 -0
  81. package/src/rpc/client.ts +317 -0
  82. package/src/rpc/error.ts +70 -0
  83. package/src/rpc/index.ts +52 -0
  84. package/src/rpc/procedure.ts +88 -0
  85. package/src/rpc/router.ts +105 -0
  86. package/src/rpc/server.ts +511 -0
  87. package/src/rpc/types.ts +328 -0
  88. package/src/server/hydrate.ts +21 -0
  89. package/src/server/index.ts +10 -0
  90. package/src/server/render-to-stream.ts +31 -0
  91. package/src/server/render-to-string.ts +125 -0
  92. package/src/signals/computed.ts +217 -0
  93. package/src/signals/context.ts +89 -0
  94. package/src/signals/effect.ts +161 -0
  95. package/src/signals/index.ts +57 -0
  96. package/src/signals/scope.ts +132 -0
  97. package/src/signals/signal.ts +203 -0
  98. package/src/signals/store.ts +163 -0
  99. package/src/signals/system.ts +124 -0
  100. package/src/signals/types.ts +64 -0
  101. package/src/style/component.tsx +122 -0
  102. package/src/style/create-style.ts +229 -0
  103. package/src/style/cx.ts +75 -0
  104. package/src/style/hash.ts +19 -0
  105. package/src/style/index.ts +8 -0
  106. package/src/style/layout.tsx +406 -0
  107. package/src/style/manager.ts +87 -0
  108. package/src/style/parser.ts +257 -0
  109. package/src/style/scale.ts +237 -0
  110. package/src/template/index.ts +4 -0
  111. package/src/template/template.ts +126 -0
  112. package/src/ui/accordion.tsx +286 -0
  113. package/src/ui/command-dialog.tsx +49 -0
  114. package/src/ui/command.tsx +400 -0
  115. package/src/ui/data-table.tsx +322 -0
  116. package/src/ui/dialog.tsx +362 -0
  117. package/src/ui/dropdown-menu.tsx +381 -0
  118. package/src/ui/icon.tsx +69 -0
  119. package/src/ui/index.ts +138 -0
  120. package/src/ui/layout.tsx +13 -0
  121. package/src/ui/popover.tsx +249 -0
  122. package/src/ui/switch.tsx +114 -0
  123. package/src/ui/tabs.tsx +297 -0
  124. package/src/ui/toast.tsx +280 -0
  125. package/src/ui/tooltip.tsx +262 -0
  126. package/src/ui/utils.ts +110 -0
  127. package/src/virtual/index.ts +12 -0
  128. package/src/virtual/virtual-list.tsx +185 -0
  129. package/src/virtual/virtualizer.ts +274 -0
  130. package/src/vite/hmr.ts +38 -0
  131. package/src/vite/index.ts +3 -0
  132. package/src/vite/lucide.ts +124 -0
  133. package/src/vite/plugin.ts +102 -0
  134. package/src/vite/rpc-middleware.ts +82 -0
  135. package/src/vite/types.ts +65 -0
@@ -0,0 +1,2717 @@
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/charts/context.ts
1052
+ var ChartContext = createContext(undefined);
1053
+ function useChartContext() {
1054
+ const ctx = useContext(ChartContext);
1055
+ if (!ctx) {
1056
+ throw new Error("Visage Chart child component must be rendered within a <Chart> container.");
1057
+ }
1058
+ return ctx;
1059
+ }
1060
+
1061
+ // src/charts/path.ts
1062
+ function pathLine(points, options = {}) {
1063
+ if (points.length === 0)
1064
+ return "";
1065
+ if (points.length === 1) {
1066
+ const p = points[0];
1067
+ return `M ${p.x.toFixed(2)},${p.y.toFixed(2)}`;
1068
+ }
1069
+ const curve = options.curve ?? "linear";
1070
+ if (curve === "smooth" && points.length >= 2) {
1071
+ if (points.length === 2) {
1072
+ const p0 = points[0];
1073
+ const p1 = points[1];
1074
+ return `M ${p0.x.toFixed(2)},${p0.y.toFixed(2)} L ${p1.x.toFixed(2)},${p1.y.toFixed(2)}`;
1075
+ }
1076
+ const n = points.length;
1077
+ const dx = [];
1078
+ const dy = [];
1079
+ const slopes = [];
1080
+ for (let i = 0;i < n - 1; i++) {
1081
+ const pA = points[i];
1082
+ const pB = points[i + 1];
1083
+ const deltaX = pB.x - pA.x;
1084
+ const deltaY = pB.y - pA.y;
1085
+ dx.push(deltaX);
1086
+ dy.push(deltaY);
1087
+ slopes.push(deltaX === 0 ? 0 : deltaY / deltaX);
1088
+ }
1089
+ const m = new Array(n).fill(0);
1090
+ m[0] = slopes[0];
1091
+ m[n - 1] = slopes[n - 2];
1092
+ for (let i = 1;i < n - 1; i++) {
1093
+ const sPrev = slopes[i - 1];
1094
+ const sNext = slopes[i];
1095
+ if (sPrev * sNext <= 0) {
1096
+ m[i] = 0;
1097
+ } else {
1098
+ const dxPrev = dx[i - 1];
1099
+ const dxNext = dx[i];
1100
+ const common = dxPrev + dxNext;
1101
+ m[i] = common === 0 ? 0 : 3 * common / ((common + dxNext) / sPrev + (common + dxPrev) / sNext);
1102
+ }
1103
+ }
1104
+ let d = `M ${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;
1105
+ for (let i = 0;i < n - 1; i++) {
1106
+ const p1 = points[i];
1107
+ const p2 = points[i + 1];
1108
+ const deltaX = dx[i];
1109
+ const cp1x = p1.x + deltaX / 3;
1110
+ const cp1y = p1.y + m[i] * deltaX / 3;
1111
+ const cp2x = p2.x - deltaX / 3;
1112
+ const cp2y = p2.y - m[i + 1] * deltaX / 3;
1113
+ d += ` C ${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`;
1114
+ }
1115
+ return d;
1116
+ }
1117
+ if (curve === "step") {
1118
+ let d = `M ${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;
1119
+ for (let i = 0;i < points.length - 1; i++) {
1120
+ const p1 = points[i];
1121
+ const p2 = points[i + 1];
1122
+ const midX = (p1.x + p2.x) / 2;
1123
+ d += ` L ${midX.toFixed(2)},${p1.y.toFixed(2)} L ${midX.toFixed(2)},${p2.y.toFixed(2)} L ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`;
1124
+ }
1125
+ return d;
1126
+ }
1127
+ let d = `M ${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;
1128
+ for (let i = 1;i < points.length; i++) {
1129
+ d += ` L ${points[i].x.toFixed(2)},${points[i].y.toFixed(2)}`;
1130
+ }
1131
+ return d;
1132
+ }
1133
+ function pathArea(points, baselineY, options = {}) {
1134
+ if (points.length === 0)
1135
+ return "";
1136
+ const lineD = pathLine(points, options);
1137
+ if (!lineD)
1138
+ return "";
1139
+ const first = points[0];
1140
+ const last = points[points.length - 1];
1141
+ return `${lineD} L ${last.x.toFixed(2)},${baselineY.toFixed(2)} L ${first.x.toFixed(2)},${baselineY.toFixed(2)} Z`;
1142
+ }
1143
+ function pathArc(options) {
1144
+ const { cx, cy, innerRadius, outerRadius, startAngle, endAngle } = options;
1145
+ const cosStart = Math.cos(startAngle);
1146
+ const sinStart = Math.sin(startAngle);
1147
+ const cosEnd = Math.cos(endAngle);
1148
+ const sinEnd = Math.sin(endAngle);
1149
+ const x0 = cx + outerRadius * cosStart;
1150
+ const y0 = cy + outerRadius * sinStart;
1151
+ const x1 = cx + outerRadius * cosEnd;
1152
+ const y1 = cy + outerRadius * sinEnd;
1153
+ const largeArcFlag = endAngle - startAngle <= Math.PI ? 0 : 1;
1154
+ if (innerRadius <= 0) {
1155
+ return `M ${cx.toFixed(2)},${cy.toFixed(2)} L ${x0.toFixed(2)},${y0.toFixed(2)} A ${outerRadius.toFixed(2)},${outerRadius.toFixed(2)} 0 ${largeArcFlag} 1 ${x1.toFixed(2)},${y1.toFixed(2)} Z`;
1156
+ }
1157
+ const x2 = cx + innerRadius * cosEnd;
1158
+ const y2 = cy + innerRadius * sinEnd;
1159
+ const x3 = cx + innerRadius * cosStart;
1160
+ const y3 = cy + innerRadius * sinStart;
1161
+ return `M ${x0.toFixed(2)},${y0.toFixed(2)} A ${outerRadius.toFixed(2)},${outerRadius.toFixed(2)} 0 ${largeArcFlag} 1 ${x1.toFixed(2)},${y1.toFixed(2)} L ${x2.toFixed(2)},${y2.toFixed(2)} A ${innerRadius.toFixed(2)},${innerRadius.toFixed(2)} 0 ${largeArcFlag} 0 ${x3.toFixed(2)},${y3.toFixed(2)} Z`;
1162
+ }
1163
+
1164
+ // src/dom/resource.ts
1165
+ var SuspenseContext = createContext(null);
1166
+ function createResource(sourceOrFetcher, maybeFetcher) {
1167
+ const isDirect = typeof maybeFetcher !== "function";
1168
+ const fetcher = isDirect ? sourceOrFetcher : maybeFetcher;
1169
+ const source = isDirect ? null : sourceOrFetcher;
1170
+ const data = signal(undefined);
1171
+ const loading = signal(true);
1172
+ const error = signal(null);
1173
+ let currentPromise = null;
1174
+ let requestId = 0;
1175
+ const load = async (arg) => {
1176
+ const currentReq = ++requestId;
1177
+ loading.set(true);
1178
+ error.set(null);
1179
+ const promise = isDirect ? fetcher() : fetcher(arg);
1180
+ currentPromise = promise;
1181
+ const suspense = useContext(SuspenseContext);
1182
+ if (suspense) {
1183
+ suspense.registerPromise(promise);
1184
+ }
1185
+ try {
1186
+ const res = await promise;
1187
+ if (currentReq === requestId) {
1188
+ data.set(res);
1189
+ loading.set(false);
1190
+ currentPromise = null;
1191
+ }
1192
+ return res;
1193
+ } catch (err) {
1194
+ if (currentReq === requestId) {
1195
+ error.set(err);
1196
+ loading.set(false);
1197
+ currentPromise = null;
1198
+ }
1199
+ throw err;
1200
+ }
1201
+ };
1202
+ if (source) {
1203
+ effect(() => {
1204
+ const sourceVal = resolveValue(source);
1205
+ if (sourceVal !== false && sourceVal !== null && sourceVal !== undefined) {
1206
+ load(sourceVal).catch(() => {});
1207
+ }
1208
+ });
1209
+ } else {
1210
+ load().catch(() => {});
1211
+ }
1212
+ const accessor = () => {
1213
+ if (loading() && currentPromise) {
1214
+ const suspense = useContext(SuspenseContext);
1215
+ if (suspense) {
1216
+ suspense.registerPromise(currentPromise);
1217
+ }
1218
+ }
1219
+ return data();
1220
+ };
1221
+ Object.defineProperties(accessor, {
1222
+ loading: { get: () => loading },
1223
+ error: { get: () => error },
1224
+ mutate: { value: (val) => data.set(val) },
1225
+ refetch: { value: () => source ? load(resolveValue(source)) : load() }
1226
+ });
1227
+ return accessor;
1228
+ }
1229
+
1230
+ // src/dom/lazy.ts
1231
+ function lazy(importer) {
1232
+ let loadedComponent = null;
1233
+ let loadingPromise = null;
1234
+ const preload = () => {
1235
+ if (loadedComponent) {
1236
+ return Promise.resolve(loadedComponent);
1237
+ }
1238
+ if (!loadingPromise) {
1239
+ loadingPromise = importer().then((mod) => {
1240
+ const comp = mod && typeof mod === "object" && "default" in mod ? mod.default : mod;
1241
+ loadedComponent = comp;
1242
+ return comp;
1243
+ }).catch((err) => {
1244
+ loadingPromise = null;
1245
+ throw err;
1246
+ });
1247
+ }
1248
+ return loadingPromise;
1249
+ };
1250
+ const LazyWrapper = (props) => {
1251
+ if (loadedComponent) {
1252
+ return loadedComponent(props);
1253
+ }
1254
+ const promise = preload();
1255
+ const suspense = useContext(SuspenseContext);
1256
+ if (suspense) {
1257
+ suspense.registerPromise(promise);
1258
+ }
1259
+ const res = createResource(() => promise);
1260
+ return () => {
1261
+ const Comp = res();
1262
+ return Comp ? Comp(props) : null;
1263
+ };
1264
+ };
1265
+ LazyWrapper.preload = preload;
1266
+ return LazyWrapper;
1267
+ }
1268
+ // src/dom/async.ts
1269
+ function Suspense(props) {
1270
+ if (typeof document === "undefined") {
1271
+ return typeof props.children === "function" ? props.children() : props.children;
1272
+ }
1273
+ const marker = document.createTextNode("");
1274
+ const initialFrag = document.createDocumentFragment();
1275
+ const pendingCount = signal(0);
1276
+ let currentScope = null;
1277
+ let currentNodes = [];
1278
+ let isMounted = false;
1279
+ const suspenseValue = {
1280
+ registerPromise(p) {
1281
+ pendingCount.update((c) => c + 1);
1282
+ p.finally(() => {
1283
+ pendingCount.update((c) => Math.max(0, c - 1));
1284
+ });
1285
+ }
1286
+ };
1287
+ const renderContent = (content) => {
1288
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
1289
+ if (!parent)
1290
+ return;
1291
+ for (const n of currentNodes) {
1292
+ if (n.parentNode)
1293
+ n.parentNode.removeChild(n);
1294
+ }
1295
+ currentNodes = [];
1296
+ const frag = document.createDocumentFragment();
1297
+ insertChild(frag, content);
1298
+ currentNodes = Array.from(frag.childNodes);
1299
+ if (marker.parentNode) {
1300
+ marker.parentNode.insertBefore(frag, marker);
1301
+ } else if (!isMounted) {
1302
+ initialFrag.appendChild(frag);
1303
+ }
1304
+ };
1305
+ effect(() => {
1306
+ if (currentScope) {
1307
+ currentScope.dispose();
1308
+ currentScope = null;
1309
+ }
1310
+ currentScope = new Scope(getActiveScope());
1311
+ runInScope(currentScope, () => {
1312
+ let threwPromise = null;
1313
+ let rendered = null;
1314
+ try {
1315
+ const SuspenseProvider = SuspenseContext.Provider;
1316
+ rendered = SuspenseProvider({
1317
+ value: suspenseValue,
1318
+ children: props.children
1319
+ });
1320
+ } catch (err) {
1321
+ if (err && typeof err.then === "function") {
1322
+ threwPromise = err;
1323
+ suspenseValue.registerPromise(err);
1324
+ } else {
1325
+ throw err;
1326
+ }
1327
+ }
1328
+ if (pendingCount() > 0 || threwPromise) {
1329
+ renderContent(props.fallback);
1330
+ } else {
1331
+ renderContent(rendered);
1332
+ }
1333
+ });
1334
+ });
1335
+ isMounted = true;
1336
+ initialFrag.appendChild(marker);
1337
+ onCleanup(() => {
1338
+ if (currentScope)
1339
+ currentScope.dispose();
1340
+ });
1341
+ return initialFrag;
1342
+ }
1343
+ function ErrorBoundary(props) {
1344
+ if (typeof document === "undefined") {
1345
+ try {
1346
+ return typeof props.children === "function" ? props.children() : props.children;
1347
+ } catch (err) {
1348
+ return typeof props.fallback === "function" ? props.fallback(err, () => {}) : props.fallback;
1349
+ }
1350
+ }
1351
+ const marker = document.createTextNode("");
1352
+ const initialFrag = document.createDocumentFragment();
1353
+ const currentError = signal(null);
1354
+ let currentScope = null;
1355
+ let currentNodes = [];
1356
+ let isMounted = false;
1357
+ const reset = () => {
1358
+ currentError.set(null);
1359
+ };
1360
+ const renderNodes = (child) => {
1361
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
1362
+ if (!parent)
1363
+ return;
1364
+ for (const n of currentNodes) {
1365
+ if (n.parentNode)
1366
+ n.parentNode.removeChild(n);
1367
+ }
1368
+ currentNodes = [];
1369
+ const frag = document.createDocumentFragment();
1370
+ insertChild(frag, child);
1371
+ currentNodes = Array.from(frag.childNodes);
1372
+ if (marker.parentNode) {
1373
+ marker.parentNode.insertBefore(frag, marker);
1374
+ } else if (!isMounted) {
1375
+ initialFrag.appendChild(frag);
1376
+ }
1377
+ };
1378
+ effect(() => {
1379
+ const err = currentError();
1380
+ if (currentScope) {
1381
+ currentScope.dispose();
1382
+ currentScope = null;
1383
+ }
1384
+ currentScope = new Scope(getActiveScope());
1385
+ runInScope(currentScope, () => {
1386
+ if (err !== null) {
1387
+ const fallbackNode = typeof props.fallback === "function" ? props.fallback(err, reset) : props.fallback;
1388
+ renderNodes(fallbackNode);
1389
+ } else {
1390
+ try {
1391
+ const content = typeof props.children === "function" ? props.children() : props.children;
1392
+ renderNodes(content);
1393
+ } catch (catchedErr) {
1394
+ currentError.set(catchedErr);
1395
+ }
1396
+ }
1397
+ });
1398
+ });
1399
+ isMounted = true;
1400
+ initialFrag.appendChild(marker);
1401
+ onCleanup(() => {
1402
+ if (currentScope)
1403
+ currentScope.dispose();
1404
+ });
1405
+ return initialFrag;
1406
+ }
1407
+ // src/dom/control-flow.ts
1408
+ function Show(props) {
1409
+ if (typeof document === "undefined") {
1410
+ const condition = resolveValue(props.when);
1411
+ if (condition) {
1412
+ return typeof props.children === "function" && props.children.length > 0 ? props.children(() => resolveValue(props.when)) : typeof props.children === "function" ? props.children() : props.children;
1413
+ }
1414
+ return props.fallback ?? null;
1415
+ }
1416
+ const marker = document.createTextNode("");
1417
+ const initialFrag = document.createDocumentFragment();
1418
+ let currentScope = null;
1419
+ let currentContent = [];
1420
+ let isMounted = false;
1421
+ effect(() => {
1422
+ const condition = resolveValue(props.when);
1423
+ if (currentScope) {
1424
+ currentScope.dispose();
1425
+ currentScope = null;
1426
+ }
1427
+ for (const node of currentContent) {
1428
+ if (node.parentNode) {
1429
+ node.parentNode.removeChild(node);
1430
+ }
1431
+ }
1432
+ currentContent = [];
1433
+ const frag = document.createDocumentFragment();
1434
+ if (condition) {
1435
+ currentScope = new Scope(getActiveScope());
1436
+ untrack(() => {
1437
+ runInScope(currentScope, () => {
1438
+ const childRes = typeof props.children === "function" && props.children.length > 0 ? props.children(() => resolveValue(props.when)) : typeof props.children === "function" ? props.children() : props.children;
1439
+ insertChild(frag, childRes);
1440
+ });
1441
+ });
1442
+ } else if (props.fallback !== undefined) {
1443
+ currentScope = new Scope(getActiveScope());
1444
+ untrack(() => {
1445
+ runInScope(currentScope, () => {
1446
+ insertChild(frag, props.fallback);
1447
+ });
1448
+ });
1449
+ }
1450
+ currentContent = Array.from(frag.childNodes);
1451
+ if (marker.parentNode) {
1452
+ marker.parentNode.insertBefore(frag, marker);
1453
+ } else if (!isMounted) {
1454
+ initialFrag.appendChild(frag);
1455
+ }
1456
+ });
1457
+ isMounted = true;
1458
+ initialFrag.appendChild(marker);
1459
+ onCleanup(() => {
1460
+ if (currentScope) {
1461
+ currentScope.dispose();
1462
+ }
1463
+ });
1464
+ return initialFrag;
1465
+ }
1466
+ function For(props) {
1467
+ if (typeof document === "undefined") {
1468
+ const list = resolveValue(props.each) ?? [];
1469
+ if (list.length === 0) {
1470
+ return props.fallback ?? null;
1471
+ }
1472
+ return list.map((item, idx) => props.children(item, () => idx));
1473
+ }
1474
+ const marker = document.createTextNode("");
1475
+ const initialFrag = document.createDocumentFragment();
1476
+ let items = [];
1477
+ let fallbackScope = null;
1478
+ let fallbackNodes = [];
1479
+ let isMounted = false;
1480
+ effect(() => {
1481
+ const list = resolveValue(props.each) ?? [];
1482
+ const parent = marker.parentNode ?? (!isMounted ? initialFrag : null);
1483
+ if (list.length === 0) {
1484
+ for (const rec of items) {
1485
+ rec.scope.dispose();
1486
+ for (const node of rec.nodes) {
1487
+ if (node.parentNode)
1488
+ node.parentNode.removeChild(node);
1489
+ }
1490
+ }
1491
+ items = [];
1492
+ if (props.fallback !== undefined && fallbackNodes.length === 0 && parent) {
1493
+ fallbackScope = new Scope(getActiveScope());
1494
+ untrack(() => {
1495
+ runInScope(fallbackScope, () => {
1496
+ const frag = document.createDocumentFragment();
1497
+ insertChild(frag, props.fallback);
1498
+ fallbackNodes = Array.from(frag.childNodes);
1499
+ if (marker.parentNode) {
1500
+ marker.parentNode.insertBefore(frag, marker);
1501
+ } else if (!isMounted) {
1502
+ initialFrag.appendChild(frag);
1503
+ }
1504
+ });
1505
+ });
1506
+ }
1507
+ return;
1508
+ }
1509
+ if (fallbackNodes.length > 0) {
1510
+ if (fallbackScope) {
1511
+ fallbackScope.dispose();
1512
+ fallbackScope = null;
1513
+ }
1514
+ for (const node of fallbackNodes) {
1515
+ if (node.parentNode)
1516
+ node.parentNode.removeChild(node);
1517
+ }
1518
+ fallbackNodes = [];
1519
+ }
1520
+ if (!parent)
1521
+ return;
1522
+ const newItems = [];
1523
+ const prevMap = new Map;
1524
+ for (const rec of items) {
1525
+ prevMap.set(rec.item, rec);
1526
+ }
1527
+ for (let i = 0;i < list.length; i++) {
1528
+ const item = list[i];
1529
+ const existing = prevMap.get(item);
1530
+ if (existing) {
1531
+ existing.indexSignal(i);
1532
+ newItems.push(existing);
1533
+ prevMap.delete(item);
1534
+ } else {
1535
+ let indexVal = i;
1536
+ const indexSubscribers = new Set;
1537
+ const indexSignal = (...args) => {
1538
+ if (args.length > 0 && args[0] !== undefined && args[0] !== indexVal) {
1539
+ indexVal = args[0];
1540
+ for (const sub of Array.from(indexSubscribers))
1541
+ sub();
1542
+ }
1543
+ return indexVal;
1544
+ };
1545
+ const itemScope = new Scope(getActiveScope());
1546
+ let itemNodes = [];
1547
+ untrack(() => {
1548
+ runInScope(itemScope, () => {
1549
+ const frag = document.createDocumentFragment();
1550
+ const child = props.children(item, indexSignal);
1551
+ insertChild(frag, child);
1552
+ itemNodes = Array.from(frag.childNodes);
1553
+ });
1554
+ });
1555
+ newItems.push({
1556
+ item,
1557
+ scope: itemScope,
1558
+ nodes: itemNodes,
1559
+ indexSignal
1560
+ });
1561
+ }
1562
+ }
1563
+ for (const [, removed] of prevMap) {
1564
+ removed.scope.dispose();
1565
+ for (const node of removed.nodes) {
1566
+ if (node.parentNode)
1567
+ node.parentNode.removeChild(node);
1568
+ }
1569
+ }
1570
+ if (marker.parentNode) {
1571
+ let currentMarker = marker;
1572
+ for (let i = newItems.length - 1;i >= 0; i--) {
1573
+ const rec = newItems[i];
1574
+ for (let j = rec.nodes.length - 1;j >= 0; j--) {
1575
+ const node = rec.nodes[j];
1576
+ if (node.nextSibling !== currentMarker) {
1577
+ marker.parentNode.insertBefore(node, currentMarker);
1578
+ }
1579
+ currentMarker = node;
1580
+ }
1581
+ }
1582
+ } else if (!isMounted) {
1583
+ for (const rec of newItems) {
1584
+ for (const node of rec.nodes) {
1585
+ initialFrag.appendChild(node);
1586
+ }
1587
+ }
1588
+ }
1589
+ items = newItems;
1590
+ });
1591
+ isMounted = true;
1592
+ initialFrag.appendChild(marker);
1593
+ onCleanup(() => {
1594
+ for (const rec of items) {
1595
+ rec.scope.dispose();
1596
+ }
1597
+ if (fallbackScope) {
1598
+ fallbackScope.dispose();
1599
+ }
1600
+ });
1601
+ return initialFrag;
1602
+ }
1603
+ function Portal(props) {
1604
+ if (typeof document === "undefined") {
1605
+ return null;
1606
+ }
1607
+ const marker = document.createTextNode("");
1608
+ let currentScope = null;
1609
+ let nodes = [];
1610
+ effect(() => {
1611
+ const target = props.mount ?? (typeof document !== "undefined" ? document.body : null);
1612
+ if (!target)
1613
+ return;
1614
+ if (currentScope) {
1615
+ currentScope.dispose();
1616
+ currentScope = null;
1617
+ }
1618
+ for (const node of nodes) {
1619
+ if (node.parentNode) {
1620
+ node.parentNode.removeChild(node);
1621
+ }
1622
+ }
1623
+ nodes = [];
1624
+ currentScope = new Scope(getActiveScope());
1625
+ untrack(() => {
1626
+ runInScope(currentScope, () => {
1627
+ const childRes = typeof props.children === "function" ? props.children() : props.children;
1628
+ const frag = document.createDocumentFragment();
1629
+ insertChild(frag, childRes);
1630
+ nodes = Array.from(frag.childNodes);
1631
+ target.appendChild(frag);
1632
+ });
1633
+ });
1634
+ });
1635
+ onCleanup(() => {
1636
+ if (currentScope) {
1637
+ currentScope.dispose();
1638
+ currentScope = null;
1639
+ }
1640
+ for (const node of nodes) {
1641
+ if (node.parentNode) {
1642
+ node.parentNode.removeChild(node);
1643
+ }
1644
+ }
1645
+ nodes = [];
1646
+ });
1647
+ return marker;
1648
+ }
1649
+ // src/jsx-runtime/index.ts
1650
+ var SVG_NS = "http://www.w3.org/2000/svg";
1651
+ var SVG_TAGS = new Set([
1652
+ "svg",
1653
+ "path",
1654
+ "circle",
1655
+ "rect",
1656
+ "g",
1657
+ "line",
1658
+ "polyline",
1659
+ "polygon",
1660
+ "text",
1661
+ "defs",
1662
+ "clipPath",
1663
+ "linearGradient",
1664
+ "radialGradient",
1665
+ "stop"
1666
+ ]);
1667
+ function Fragment(props) {
1668
+ if (typeof document === "undefined") {
1669
+ return props.children !== undefined ? props.children : [];
1670
+ }
1671
+ const fragment = document.createDocumentFragment();
1672
+ if (props.children !== undefined) {
1673
+ insertChild(fragment, props.children);
1674
+ }
1675
+ return fragment;
1676
+ }
1677
+ function jsx(type, props = {}, key) {
1678
+ if (typeof type === "function") {
1679
+ return type(props, key);
1680
+ }
1681
+ if (typeof type === "string") {
1682
+ const { children, ...restProps } = props;
1683
+ if (typeof document === "undefined") {
1684
+ const attributes = new Map;
1685
+ for (const propName in restProps) {
1686
+ const val = restProps[propName];
1687
+ if (propName === "className" || propName === "class") {
1688
+ const resolved = typeof val === "function" ? val() : val;
1689
+ if (resolved)
1690
+ attributes.set("class", resolved);
1691
+ } else if (propName === "style") {
1692
+ const val = restProps[propName];
1693
+ const resolved = resolveValue(val);
1694
+ if (typeof resolved === "string") {
1695
+ attributes.set("style", resolved);
1696
+ } else if (typeof resolved === "object" && resolved !== null) {
1697
+ const styleStr = Object.entries(resolved).map(([k, v]) => {
1698
+ const finalVal = resolveValue(v);
1699
+ const formatted = formatStyleProp(k, finalVal);
1700
+ if (!formatted)
1701
+ return "";
1702
+ const kebab = k.startsWith("--") ? k : k.replace(/([A-Z])/g, "-$1").toLowerCase();
1703
+ return `${kebab}: ${formatted}`;
1704
+ }).filter(Boolean).join("; ");
1705
+ if (styleStr)
1706
+ attributes.set("style", styleStr);
1707
+ }
1708
+ } else if (!propName.startsWith("on")) {
1709
+ const resolved = typeof val === "function" ? val() : val;
1710
+ if (resolved === true) {
1711
+ attributes.set(propName, propName);
1712
+ } else if (resolved !== false && resolved !== null && resolved !== undefined) {
1713
+ attributes.set(propName, resolved);
1714
+ }
1715
+ }
1716
+ }
1717
+ const childNodes = children !== undefined ? Array.isArray(children) ? children : [children] : [];
1718
+ return {
1719
+ tagName: type,
1720
+ attributes,
1721
+ childNodes
1722
+ };
1723
+ }
1724
+ const isSvg = SVG_TAGS.has(type);
1725
+ const element = isSvg ? document.createElementNS(SVG_NS, type) : document.createElement(type);
1726
+ for (const propName in restProps) {
1727
+ setAttribute(element, propName, restProps[propName]);
1728
+ }
1729
+ if (children !== undefined) {
1730
+ insertChild(element, children);
1731
+ }
1732
+ return element;
1733
+ }
1734
+ return type;
1735
+ }
1736
+ var jsxs = jsx;
1737
+ var jsxDEV = jsx;
1738
+
1739
+ // src/charts/Area.tsx
1740
+ function Area(props) {
1741
+ return () => {
1742
+ const ctx = useChartContext();
1743
+ const stroke = props.stroke ?? "#a855f7";
1744
+ const strokeWidth = props.strokeWidth ?? 2;
1745
+ const fill = props.fill ?? "rgba(168, 85, 247, 0.15)";
1746
+ const fillOpacity = props.fillOpacity ?? 1;
1747
+ const curve = props.curve ?? "smooth";
1748
+ const id = `area-${props.dataKey}-${Math.random().toString(36).slice(2, 7)}`;
1749
+ ctx.registerSeries({
1750
+ id,
1751
+ dataKey: props.dataKey,
1752
+ type: "area",
1753
+ color: stroke,
1754
+ name: props.name ?? props.dataKey
1755
+ });
1756
+ onCleanup(() => {
1757
+ ctx.unregisterSeries(id);
1758
+ });
1759
+ return /* @__PURE__ */ jsx("g", {
1760
+ class: `visage-area-${props.dataKey}`,
1761
+ opacity: props.opacity ?? 1,
1762
+ children: () => {
1763
+ const dataArr = ctx.data();
1764
+ if (dataArr.length === 0)
1765
+ return null;
1766
+ const xScale = ctx.xScale();
1767
+ const yScale = ctx.yScale();
1768
+ const baselineY = ctx.innerHeight();
1769
+ const points = [];
1770
+ for (let i = 0;i < dataArr.length; i++) {
1771
+ const item = dataArr[i];
1772
+ const val = item[props.dataKey];
1773
+ if (typeof val !== "number" || Number.isNaN(val))
1774
+ continue;
1775
+ let x = 0;
1776
+ if (xScale.type === "band") {
1777
+ x = xScale(i) + xScale.bandwidth() / 2;
1778
+ } else {
1779
+ x = xScale(i);
1780
+ }
1781
+ const y = yScale(val);
1782
+ points.push({ x, y });
1783
+ }
1784
+ const areaD = pathArea(points, baselineY, { curve });
1785
+ const lineD = pathLine(points, { curve });
1786
+ const dots = [];
1787
+ if (props.dot && points.length > 0) {
1788
+ const dotCfg = typeof props.dot === "object" ? props.dot : {};
1789
+ const r = dotCfg.r ?? 3.5;
1790
+ const dotFill = dotCfg.fill ?? "#ffffff";
1791
+ const dotStroke = dotCfg.stroke ?? stroke;
1792
+ for (let i = 0;i < points.length; i++) {
1793
+ const p = points[i];
1794
+ dots.push(/* @__PURE__ */ jsx("circle", {
1795
+ cx: p.x,
1796
+ cy: p.y,
1797
+ r,
1798
+ fill: dotFill,
1799
+ stroke: dotStroke,
1800
+ "stroke-width": 2
1801
+ }));
1802
+ }
1803
+ }
1804
+ return [
1805
+ /* @__PURE__ */ jsx("path", {
1806
+ d: areaD,
1807
+ fill,
1808
+ "fill-opacity": fillOpacity
1809
+ }),
1810
+ /* @__PURE__ */ jsx("path", {
1811
+ d: lineD,
1812
+ fill: "none",
1813
+ stroke,
1814
+ "stroke-width": strokeWidth,
1815
+ "stroke-linejoin": "round",
1816
+ "stroke-linecap": "round"
1817
+ }),
1818
+ ...dots
1819
+ ];
1820
+ }
1821
+ });
1822
+ };
1823
+ }
1824
+ // src/charts/Axis.tsx
1825
+ function XAxis(props) {
1826
+ return () => {
1827
+ const ctx = useChartContext();
1828
+ if (props.dataKey) {
1829
+ ctx.setXDataKey(props.dataKey);
1830
+ onCleanup(() => {
1831
+ if (ctx.xDataKey() === props.dataKey) {
1832
+ ctx.setXDataKey("");
1833
+ }
1834
+ });
1835
+ }
1836
+ const stroke = props.stroke ?? "#94a3b8";
1837
+ const fontSize = props.fontSize ?? 11;
1838
+ const hideLine = props.hideLine ?? false;
1839
+ const w = ctx.innerWidth();
1840
+ const h = ctx.innerHeight();
1841
+ const xScale = ctx.xScale();
1842
+ const dataArr = ctx.data();
1843
+ const elements = [];
1844
+ if (!hideLine) {
1845
+ elements.push(/* @__PURE__ */ jsx("line", {
1846
+ x1: 0,
1847
+ y1: h,
1848
+ x2: w,
1849
+ y2: h,
1850
+ stroke,
1851
+ "stroke-width": 1
1852
+ }));
1853
+ }
1854
+ if (xScale.type === "band") {
1855
+ const ticks = xScale.ticks();
1856
+ const bw = xScale.bandwidth();
1857
+ for (let i = 0;i < ticks.length; i++) {
1858
+ const val = ticks[i];
1859
+ const x = xScale(i) + bw / 2;
1860
+ const text = props.tickFormat ? props.tickFormat(val, i) : String(val);
1861
+ elements.push(/* @__PURE__ */ jsx("text", {
1862
+ x,
1863
+ y: h + 16,
1864
+ "text-anchor": "middle",
1865
+ "font-size": fontSize,
1866
+ fill: stroke,
1867
+ children: text
1868
+ }));
1869
+ }
1870
+ } else {
1871
+ const count = props.tickCount ?? 5;
1872
+ const ticks = xScale.ticks(count);
1873
+ for (let i = 0;i < ticks.length; i++) {
1874
+ const tickIdx = ticks[i];
1875
+ const x = xScale(tickIdx);
1876
+ const idx = Math.max(0, Math.min(dataArr.length - 1, Math.round(tickIdx)));
1877
+ const rawItem = dataArr[idx];
1878
+ const rawVal = props.dataKey && rawItem ? rawItem[props.dataKey] : idx;
1879
+ const text = props.tickFormat ? props.tickFormat(rawVal, i) : String(rawVal ?? idx);
1880
+ elements.push(/* @__PURE__ */ jsx("text", {
1881
+ x,
1882
+ y: h + 16,
1883
+ "text-anchor": "middle",
1884
+ "font-size": fontSize,
1885
+ fill: stroke,
1886
+ children: text
1887
+ }));
1888
+ }
1889
+ }
1890
+ return /* @__PURE__ */ jsx("g", {
1891
+ class: "visage-x-axis",
1892
+ children: elements
1893
+ });
1894
+ };
1895
+ }
1896
+ function YAxis(props) {
1897
+ return () => {
1898
+ const ctx = useChartContext();
1899
+ const stroke = props.stroke ?? "#94a3b8";
1900
+ const fontSize = props.fontSize ?? 11;
1901
+ const hideLine = props.hideLine ?? true;
1902
+ const unit = props.unit ?? "";
1903
+ const h = ctx.innerHeight();
1904
+ const yScale = ctx.yScale();
1905
+ const ticks = yScale.ticks(props.tickCount ?? 5);
1906
+ const elements = [];
1907
+ if (!hideLine) {
1908
+ elements.push(/* @__PURE__ */ jsx("line", {
1909
+ x1: 0,
1910
+ y1: 0,
1911
+ x2: 0,
1912
+ y2: h,
1913
+ stroke,
1914
+ "stroke-width": 1
1915
+ }));
1916
+ }
1917
+ for (let i = 0;i < ticks.length; i++) {
1918
+ const val = ticks[i];
1919
+ const y = yScale(val);
1920
+ const formatted = props.tickFormat ? props.tickFormat(val, i) : unit ? `${val}${unit}` : String(val);
1921
+ elements.push(/* @__PURE__ */ jsx("text", {
1922
+ x: -8,
1923
+ y: y + 4,
1924
+ "text-anchor": "end",
1925
+ "font-size": fontSize,
1926
+ fill: stroke,
1927
+ children: formatted
1928
+ }));
1929
+ }
1930
+ return /* @__PURE__ */ jsx("g", {
1931
+ class: "visage-y-axis",
1932
+ children: elements
1933
+ });
1934
+ };
1935
+ }
1936
+ // src/charts/Bar.tsx
1937
+ function Bar(props) {
1938
+ return () => {
1939
+ const ctx = useChartContext();
1940
+ const fill = props.fill ?? "#6366f1";
1941
+ const radius = props.radius ?? 4;
1942
+ const id = `bar-${props.dataKey}-${Math.random().toString(36).slice(2, 7)}`;
1943
+ ctx.registerSeries({
1944
+ id,
1945
+ dataKey: props.dataKey,
1946
+ type: "bar",
1947
+ color: fill,
1948
+ name: props.name ?? props.dataKey
1949
+ });
1950
+ onCleanup(() => {
1951
+ ctx.unregisterSeries(id);
1952
+ });
1953
+ return /* @__PURE__ */ jsx("g", {
1954
+ class: `visage-bar-${props.dataKey}`,
1955
+ opacity: props.opacity ?? 1,
1956
+ children: () => {
1957
+ const dataArr = ctx.data();
1958
+ if (dataArr.length === 0)
1959
+ return null;
1960
+ const xScale = ctx.xScale();
1961
+ const yScale = ctx.yScale();
1962
+ const baselineY = ctx.innerHeight();
1963
+ const allBars = ctx.series().filter((s) => s.type === "bar");
1964
+ const barIndex = allBars.findIndex((s) => s.id === id);
1965
+ const totalBars = Math.max(1, allBars.length);
1966
+ const bars = [];
1967
+ for (let i = 0;i < dataArr.length; i++) {
1968
+ const item = dataArr[i];
1969
+ const val = item[props.dataKey];
1970
+ if (typeof val !== "number" || Number.isNaN(val))
1971
+ continue;
1972
+ let slotX = 0;
1973
+ let slotW = 20;
1974
+ if (xScale.type === "band") {
1975
+ slotX = xScale(i);
1976
+ slotW = xScale.bandwidth();
1977
+ } else {
1978
+ const stepW = ctx.innerWidth() / Math.max(1, dataArr.length);
1979
+ slotX = xScale(i) - stepW / 2;
1980
+ slotW = stepW * 0.8;
1981
+ }
1982
+ const subBarW = slotW / totalBars;
1983
+ const barW = props.maxWidth ? Math.min(props.maxWidth, subBarW) : subBarW;
1984
+ const barX = slotX + (barIndex >= 0 ? barIndex * subBarW : 0) + (subBarW - barW) / 2;
1985
+ const y = yScale(val);
1986
+ const h = Math.max(0, baselineY - y);
1987
+ bars.push(/* @__PURE__ */ jsx("rect", {
1988
+ x: barX,
1989
+ y,
1990
+ width: barW,
1991
+ height: h,
1992
+ rx: radius,
1993
+ ry: radius,
1994
+ fill
1995
+ }));
1996
+ }
1997
+ return bars;
1998
+ }
1999
+ });
2000
+ };
2001
+ }
2002
+ // src/charts/CartesianGrid.tsx
2003
+ function CartesianGrid(props) {
2004
+ return () => {
2005
+ const ctx = useChartContext();
2006
+ const horizontal = props.horizontal ?? true;
2007
+ const vertical = props.vertical ?? false;
2008
+ const stroke = props.stroke ?? "#e2e8f0";
2009
+ const strokeWidth = props.strokeWidth ?? 1;
2010
+ const strokeDasharray = props.strokeDasharray;
2011
+ const opacity = props.opacity ?? 0.8;
2012
+ const lines = [];
2013
+ const w = ctx.innerWidth();
2014
+ const h = ctx.innerHeight();
2015
+ const yScale = ctx.yScale();
2016
+ const xScale = ctx.xScale();
2017
+ if (horizontal) {
2018
+ const ticks = yScale.ticks(5);
2019
+ for (const t of ticks) {
2020
+ const y = yScale(t);
2021
+ lines.push(/* @__PURE__ */ jsx("line", {
2022
+ x1: 0,
2023
+ y1: y,
2024
+ x2: w,
2025
+ y2: y,
2026
+ stroke,
2027
+ "stroke-width": strokeWidth,
2028
+ "stroke-dasharray": strokeDasharray
2029
+ }));
2030
+ }
2031
+ }
2032
+ if (vertical) {
2033
+ const ticks = xScale.ticks(5);
2034
+ for (const t of ticks) {
2035
+ const x = xScale(t);
2036
+ lines.push(/* @__PURE__ */ jsx("line", {
2037
+ x1: x,
2038
+ y1: 0,
2039
+ x2: x,
2040
+ y2: h,
2041
+ stroke,
2042
+ "stroke-width": strokeWidth,
2043
+ "stroke-dasharray": strokeDasharray
2044
+ }));
2045
+ }
2046
+ }
2047
+ return /* @__PURE__ */ jsx("g", {
2048
+ class: "visage-cartesian-grid",
2049
+ opacity,
2050
+ children: lines
2051
+ });
2052
+ };
2053
+ }
2054
+ // src/charts/scale.ts
2055
+ function generateNiceTicks(min, max, count = 5) {
2056
+ if (min === max)
2057
+ return [min];
2058
+ if (count <= 0)
2059
+ return [];
2060
+ const span = max - min;
2061
+ const rawStep = span / count;
2062
+ const magnitude = 10 ** Math.floor(Math.log10(rawStep));
2063
+ const err = rawStep / magnitude;
2064
+ let step;
2065
+ if (err >= 7.5) {
2066
+ step = 10 * magnitude;
2067
+ } else if (err >= 3.5) {
2068
+ step = 5 * magnitude;
2069
+ } else if (err >= 1.5) {
2070
+ step = 2 * magnitude;
2071
+ } else {
2072
+ step = 1 * magnitude;
2073
+ }
2074
+ const start = Math.floor(min / step) * step;
2075
+ const end = Math.ceil(max / step) * step;
2076
+ const ticks = [];
2077
+ for (let current = start;current <= end + step * 0.5; current += step) {
2078
+ const rounded = Number(current.toPrecision(12));
2079
+ ticks.push(rounded);
2080
+ }
2081
+ return ticks;
2082
+ }
2083
+ function createLinearScale(domain, range, options = {}) {
2084
+ let [d0, d1] = domain;
2085
+ const [r0, r1] = range;
2086
+ if (options.nice && d0 !== d1) {
2087
+ const ticks = generateNiceTicks(d0, d1, 5);
2088
+ if (ticks.length > 0) {
2089
+ d0 = Math.min(d0, ticks[0]);
2090
+ d1 = Math.max(d1, ticks[ticks.length - 1]);
2091
+ }
2092
+ }
2093
+ const fn = (val) => {
2094
+ let v = val;
2095
+ if (options.clamp) {
2096
+ const minD = Math.min(d0, d1);
2097
+ const maxD = Math.max(d0, d1);
2098
+ v = Math.max(minD, Math.min(maxD, v));
2099
+ }
2100
+ const ratio = d1 === d0 ? 0 : (v - d0) / (d1 - d0);
2101
+ return r0 + ratio * (r1 - r0);
2102
+ };
2103
+ fn.type = "linear";
2104
+ fn.domain = [d0, d1];
2105
+ fn.range = [r0, r1];
2106
+ fn.invert = (pixel) => {
2107
+ const ratio = r1 === r0 ? 0 : (pixel - r0) / (r1 - r0);
2108
+ return d0 + ratio * (d1 - d0);
2109
+ };
2110
+ fn.ticks = (count = 5) => {
2111
+ return generateNiceTicks(d0, d1, count);
2112
+ };
2113
+ return fn;
2114
+ }
2115
+ function createBandScale(domain, range, options = {}) {
2116
+ const paddingInner = options.paddingInner ?? 0.2;
2117
+ const paddingOuter = options.paddingOuter ?? 0.1;
2118
+ const n = domain.length;
2119
+ const totalSteps = Math.max(1, n - paddingInner + 2 * paddingOuter);
2120
+ const step = (range[1] - range[0]) / totalSteps;
2121
+ const bandwidth = step * (1 - paddingInner);
2122
+ const fn = (val) => {
2123
+ let idx = -1;
2124
+ if (typeof val === "number" && Number.isInteger(val) && val >= 0 && val < domain.length) {
2125
+ idx = val;
2126
+ } else {
2127
+ idx = domain.indexOf(val);
2128
+ }
2129
+ if (idx === -1)
2130
+ return range[0];
2131
+ return range[0] + (idx + paddingOuter) * step;
2132
+ };
2133
+ fn.type = "band";
2134
+ fn.domain = [...domain];
2135
+ fn.range = [range[0], range[1]];
2136
+ fn.bandwidth = () => bandwidth;
2137
+ fn.step = () => step;
2138
+ fn.ticks = () => [...domain];
2139
+ return fn;
2140
+ }
2141
+
2142
+ // src/charts/Chart.tsx
2143
+ var DEFAULT_MARGIN = {
2144
+ top: 16,
2145
+ right: 16,
2146
+ bottom: 24,
2147
+ left: 36
2148
+ };
2149
+ function Chart(props) {
2150
+ const margin = {
2151
+ ...DEFAULT_MARGIN,
2152
+ ...props.margin
2153
+ };
2154
+ const initialW = typeof props.width === "number" ? props.width : 500;
2155
+ const initialH = typeof props.height === "number" ? props.height : 300;
2156
+ const measuredWidth = signal(initialW);
2157
+ const measuredHeight = signal(initialH);
2158
+ let containerEl = null;
2159
+ const handleRef = (el) => {
2160
+ containerEl = el;
2161
+ if (typeof ResizeObserver !== "undefined") {
2162
+ const ro = new ResizeObserver((entries) => {
2163
+ for (const entry of entries) {
2164
+ const cr = entry.contentRect;
2165
+ if (cr.width > 0)
2166
+ measuredWidth.set(cr.width);
2167
+ if (cr.height > 0)
2168
+ measuredHeight.set(cr.height);
2169
+ }
2170
+ });
2171
+ ro.observe(el);
2172
+ onCleanup(() => ro.disconnect());
2173
+ } else {
2174
+ if (el.clientWidth > 0)
2175
+ measuredWidth.set(el.clientWidth);
2176
+ if (el.clientHeight > 0)
2177
+ measuredHeight.set(el.clientHeight);
2178
+ }
2179
+ };
2180
+ const innerWidth = computed(() => Math.max(10, measuredWidth() - margin.left - margin.right));
2181
+ const innerHeight = computed(() => Math.max(10, measuredHeight() - margin.top - margin.bottom));
2182
+ const rawData = () => resolveValue(props.data) || [];
2183
+ const seriesList = signal([]);
2184
+ const xDataKey = signal(undefined);
2185
+ const registerSeries = (meta) => {
2186
+ untrack(() => {
2187
+ seriesList.update((prev) => {
2188
+ if (prev.some((s) => s.id === meta.id))
2189
+ return prev;
2190
+ return [...prev, meta];
2191
+ });
2192
+ });
2193
+ };
2194
+ const unregisterSeries = (id) => {
2195
+ untrack(() => {
2196
+ seriesList.update((prev) => prev.filter((s) => s.id !== id));
2197
+ });
2198
+ };
2199
+ const hoverState = signal({
2200
+ active: false,
2201
+ x: 0,
2202
+ y: 0,
2203
+ index: -1
2204
+ });
2205
+ const xScale = computed(() => {
2206
+ const dataArr = rawData();
2207
+ const w = innerWidth();
2208
+ const key = xDataKey();
2209
+ const hasBarSeries = untrack(() => seriesList().some((s) => s.type === "bar"));
2210
+ if (hasBarSeries && key && dataArr.length > 0) {
2211
+ const categories = dataArr.map((d) => String(d[key]));
2212
+ return createBandScale(categories, [0, w], {
2213
+ paddingInner: 0.1,
2214
+ paddingOuter: 0.05
2215
+ });
2216
+ }
2217
+ const maxIdx = Math.max(1, dataArr.length - 1);
2218
+ return createLinearScale([0, maxIdx], [0, w]);
2219
+ });
2220
+ const yScale = computed(() => {
2221
+ const h = innerHeight();
2222
+ const dataArr = rawData();
2223
+ const currentSeries = seriesList();
2224
+ let minY = 0;
2225
+ let maxY = 10;
2226
+ if (props.yDomain) {
2227
+ minY = props.yDomain[0];
2228
+ maxY = props.yDomain[1];
2229
+ } else if (dataArr.length > 0 && currentSeries.length > 0) {
2230
+ let foundMin = Infinity;
2231
+ let foundMax = -Infinity;
2232
+ for (const item of dataArr) {
2233
+ for (const s of currentSeries) {
2234
+ const val = item[s.dataKey];
2235
+ if (typeof val === "number" && !Number.isNaN(val)) {
2236
+ if (val < foundMin)
2237
+ foundMin = val;
2238
+ if (val > foundMax)
2239
+ foundMax = val;
2240
+ }
2241
+ }
2242
+ }
2243
+ if (foundMax > -Infinity) {
2244
+ minY = Math.min(0, foundMin);
2245
+ maxY = foundMax === 0 ? 1 : foundMax * 1.1;
2246
+ }
2247
+ }
2248
+ return createLinearScale([minY, maxY], [h, 0], { nice: true });
2249
+ });
2250
+ const handlePointer = (clientX, clientY) => {
2251
+ if (!containerEl)
2252
+ return;
2253
+ const rect = containerEl.getBoundingClientRect();
2254
+ const relX = clientX - rect.left - margin.left;
2255
+ const relY = clientY - rect.top - margin.top;
2256
+ const w = innerWidth();
2257
+ const h = innerHeight();
2258
+ if (relX < 0 || relX > w || relY < 0 || relY > h) {
2259
+ hoverState.set({ active: false, x: 0, y: 0, index: -1 });
2260
+ return;
2261
+ }
2262
+ const dataArr = rawData();
2263
+ if (dataArr.length === 0)
2264
+ return;
2265
+ const count = dataArr.length;
2266
+ const stepW = w / Math.max(1, count - 1);
2267
+ const rawIdx = Math.round(relX / stepW);
2268
+ const clampedIdx = Math.max(0, Math.min(count - 1, rawIdx));
2269
+ hoverState.set({
2270
+ active: true,
2271
+ x: relX + margin.left,
2272
+ y: relY + margin.top,
2273
+ index: clampedIdx,
2274
+ datum: dataArr[clampedIdx]
2275
+ });
2276
+ };
2277
+ const handleMouseMove = (e) => {
2278
+ handlePointer(e.clientX, e.clientY);
2279
+ };
2280
+ const handleMouseLeave = () => {
2281
+ hoverState.set({ active: false, x: 0, y: 0, index: -1 });
2282
+ };
2283
+ const handleTouchMove = (e) => {
2284
+ const touch = e.touches[0];
2285
+ if (touch)
2286
+ handlePointer(touch.clientX, touch.clientY);
2287
+ };
2288
+ const handleTouchEnd = () => {
2289
+ hoverState.set({ active: false, x: 0, y: 0, index: -1 });
2290
+ };
2291
+ const ctxValue = {
2292
+ data: rawData,
2293
+ width: () => measuredWidth(),
2294
+ height: () => measuredHeight(),
2295
+ margin,
2296
+ innerWidth: () => innerWidth(),
2297
+ innerHeight: () => innerHeight(),
2298
+ xScale: () => xScale(),
2299
+ yScale: () => yScale(),
2300
+ hoverState: () => hoverState(),
2301
+ setHoverState: (s) => hoverState.set(s),
2302
+ xDataKey: () => xDataKey(),
2303
+ setXDataKey: (k) => xDataKey.set(k),
2304
+ series: () => seriesList(),
2305
+ registerSeries,
2306
+ unregisterSeries
2307
+ };
2308
+ const containerStyle = {
2309
+ position: "relative",
2310
+ width: typeof props.width === "number" ? `${props.width}px` : props.width ?? "100%",
2311
+ height: typeof props.height === "number" ? `${props.height}px` : props.height ?? "300px",
2312
+ touchAction: "none",
2313
+ userSelect: "none",
2314
+ ...props.style
2315
+ };
2316
+ const rawChildren = Array.isArray(props.children) ? props.children : [props.children];
2317
+ const childrenList = [];
2318
+ const stack = [...rawChildren];
2319
+ while (stack.length > 0) {
2320
+ const item = stack.shift();
2321
+ if (Array.isArray(item)) {
2322
+ stack.unshift(...item);
2323
+ } else if (item !== null && item !== undefined && item !== false) {
2324
+ childrenList.push(item);
2325
+ }
2326
+ }
2327
+ const svgChildren = [];
2328
+ const overlayChildren = [];
2329
+ for (const child of childrenList) {
2330
+ if (typeof child === "function" && child.__visage_overlay) {
2331
+ overlayChildren.push(child);
2332
+ } else {
2333
+ svgChildren.push(child);
2334
+ }
2335
+ }
2336
+ return ChartContext.Provider({
2337
+ value: ctxValue,
2338
+ children: () => /* @__PURE__ */ jsxs("div", {
2339
+ ref: handleRef,
2340
+ class: props.class || props.className,
2341
+ style: containerStyle,
2342
+ onMouseMove: handleMouseMove,
2343
+ onMouseLeave: handleMouseLeave,
2344
+ onTouchMove: handleTouchMove,
2345
+ onTouchEnd: handleTouchEnd,
2346
+ children: [
2347
+ /* @__PURE__ */ jsxs("svg", {
2348
+ role: "img",
2349
+ "aria-label": props["aria-label"] ?? "Data visualization chart",
2350
+ viewBox: () => `0 0 ${measuredWidth()} ${measuredHeight()}`,
2351
+ width: "100%",
2352
+ height: "100%",
2353
+ style: { overflow: "visible", display: "block" },
2354
+ children: [
2355
+ /* @__PURE__ */ jsx("title", {
2356
+ children: props.title ?? "Data Visualization Chart"
2357
+ }),
2358
+ /* @__PURE__ */ jsx("g", {
2359
+ transform: `translate(${margin.left}, ${margin.top})`,
2360
+ children: svgChildren
2361
+ })
2362
+ ]
2363
+ }),
2364
+ overlayChildren
2365
+ ]
2366
+ })
2367
+ });
2368
+ }
2369
+ // src/charts/Cursor.tsx
2370
+ function ChartCursor(props) {
2371
+ return () => {
2372
+ const ctx = useChartContext();
2373
+ const stroke = props.stroke ?? "#94a3b8";
2374
+ const strokeWidth = props.strokeWidth ?? 1;
2375
+ const strokeDasharray = props.strokeDasharray ?? "4 4";
2376
+ const opacity = props.opacity ?? 0.8;
2377
+ const hover = ctx.hoverState();
2378
+ if (!hover.active)
2379
+ return null;
2380
+ const h = ctx.innerHeight();
2381
+ const x = hover.x - ctx.margin.left;
2382
+ return /* @__PURE__ */ jsx("g", {
2383
+ class: "visage-chart-cursor",
2384
+ children: /* @__PURE__ */ jsx("line", {
2385
+ x1: x,
2386
+ y1: 0,
2387
+ x2: x,
2388
+ y2: h,
2389
+ stroke,
2390
+ "stroke-width": strokeWidth,
2391
+ "stroke-dasharray": strokeDasharray,
2392
+ opacity
2393
+ })
2394
+ });
2395
+ };
2396
+ }
2397
+ // src/charts/Legend.tsx
2398
+ function ChartLegend(props) {
2399
+ const render = () => {
2400
+ const ctx = useChartContext();
2401
+ const align = props.align ?? "center";
2402
+ const justifyMap = {
2403
+ left: "flex-start",
2404
+ center: "center",
2405
+ right: "flex-end"
2406
+ };
2407
+ const series = ctx.series();
2408
+ return /* @__PURE__ */ jsx("div", {
2409
+ class: props.class || props.className,
2410
+ style: {
2411
+ display: "flex",
2412
+ alignItems: "center",
2413
+ justifyContent: justifyMap[align],
2414
+ gap: "16px",
2415
+ paddingTop: "8px",
2416
+ fontSize: "12px",
2417
+ color: "#475569"
2418
+ },
2419
+ children: series.map((s) => /* @__PURE__ */ jsxs("div", {
2420
+ style: { display: "flex", alignItems: "center", gap: "6px" },
2421
+ children: [
2422
+ /* @__PURE__ */ jsx("span", {
2423
+ style: {
2424
+ width: "10px",
2425
+ height: "10px",
2426
+ borderRadius: "3px",
2427
+ background: s.color ?? "#8b5cf6"
2428
+ }
2429
+ }),
2430
+ /* @__PURE__ */ jsx("span", {
2431
+ children: s.name ?? s.dataKey
2432
+ })
2433
+ ]
2434
+ }))
2435
+ });
2436
+ };
2437
+ render.__visage_overlay = true;
2438
+ return render;
2439
+ }
2440
+ var Legend = ChartLegend;
2441
+ // src/charts/Line.tsx
2442
+ function Line(props) {
2443
+ return () => {
2444
+ const ctx = useChartContext();
2445
+ const stroke = props.stroke ?? "#8b5cf6";
2446
+ const strokeWidth = props.strokeWidth ?? 2;
2447
+ const curve = props.curve ?? "linear";
2448
+ const id = `line-${props.dataKey}-${Math.random().toString(36).slice(2, 7)}`;
2449
+ ctx.registerSeries({
2450
+ id,
2451
+ dataKey: props.dataKey,
2452
+ type: "line",
2453
+ color: stroke,
2454
+ name: props.name ?? props.dataKey
2455
+ });
2456
+ onCleanup(() => {
2457
+ ctx.unregisterSeries(id);
2458
+ });
2459
+ return /* @__PURE__ */ jsx("g", {
2460
+ class: `visage-line-${props.dataKey}`,
2461
+ opacity: props.opacity ?? 1,
2462
+ children: () => {
2463
+ const dataArr = ctx.data();
2464
+ if (dataArr.length === 0)
2465
+ return null;
2466
+ const xScale = ctx.xScale();
2467
+ const yScale = ctx.yScale();
2468
+ const points = [];
2469
+ for (let i = 0;i < dataArr.length; i++) {
2470
+ const item = dataArr[i];
2471
+ const val = item[props.dataKey];
2472
+ if (typeof val !== "number" || Number.isNaN(val))
2473
+ continue;
2474
+ let x = 0;
2475
+ if (xScale.type === "band") {
2476
+ x = xScale(i) + xScale.bandwidth() / 2;
2477
+ } else {
2478
+ x = xScale(i);
2479
+ }
2480
+ const y = yScale(val);
2481
+ points.push({ x, y });
2482
+ }
2483
+ const d = pathLine(points, { curve });
2484
+ const dots = [];
2485
+ if (props.dot && points.length > 0) {
2486
+ const dotCfg = typeof props.dot === "object" ? props.dot : {};
2487
+ const r = dotCfg.r ?? 3.5;
2488
+ const fill = dotCfg.fill ?? "#ffffff";
2489
+ const dotStroke = dotCfg.stroke ?? stroke;
2490
+ const dotSw = dotCfg.strokeWidth ?? 2;
2491
+ for (let i = 0;i < points.length; i++) {
2492
+ const p = points[i];
2493
+ dots.push(/* @__PURE__ */ jsx("circle", {
2494
+ cx: p.x,
2495
+ cy: p.y,
2496
+ r,
2497
+ fill,
2498
+ stroke: dotStroke,
2499
+ "stroke-width": dotSw
2500
+ }));
2501
+ }
2502
+ }
2503
+ return [
2504
+ /* @__PURE__ */ jsx("path", {
2505
+ d,
2506
+ fill: "none",
2507
+ stroke,
2508
+ "stroke-width": strokeWidth,
2509
+ "stroke-dasharray": props.strokeDasharray,
2510
+ "stroke-linejoin": "round",
2511
+ "stroke-linecap": "round"
2512
+ }),
2513
+ ...dots
2514
+ ];
2515
+ }
2516
+ });
2517
+ };
2518
+ }
2519
+ // src/charts/Pie.tsx
2520
+ var DEFAULT_PALETTE = [
2521
+ "#8b5cf6",
2522
+ "#ec4899",
2523
+ "#3b82f6",
2524
+ "#10b981",
2525
+ "#f59e0b",
2526
+ "#6366f1",
2527
+ "#14b8a6",
2528
+ "#ef4444"
2529
+ ];
2530
+ function Pie(props) {
2531
+ return () => {
2532
+ const ctx = useChartContext();
2533
+ const innerRadius = props.innerRadius ?? 0;
2534
+ const outerRadius = props.outerRadius ?? 80;
2535
+ const colors = props.colors ?? DEFAULT_PALETTE;
2536
+ const padAngle = props.padAngle ?? 0.02;
2537
+ return /* @__PURE__ */ jsx("g", {
2538
+ class: "visage-pie",
2539
+ children: () => {
2540
+ const dataArr = ctx.data();
2541
+ if (dataArr.length === 0)
2542
+ return null;
2543
+ const w = ctx.innerWidth();
2544
+ const h = ctx.innerHeight();
2545
+ const centerX = props.cx ?? w / 2;
2546
+ const centerY = props.cy ?? h / 2;
2547
+ let total = 0;
2548
+ for (const item of dataArr) {
2549
+ const val = Number(item[props.dataKey]) || 0;
2550
+ total += val;
2551
+ }
2552
+ if (total === 0)
2553
+ return null;
2554
+ const slices = [];
2555
+ let currentAngle = -Math.PI / 2;
2556
+ for (let i = 0;i < dataArr.length; i++) {
2557
+ const item = dataArr[i];
2558
+ const val = Number(item[props.dataKey]) || 0;
2559
+ const sliceAngle = val / total * (2 * Math.PI);
2560
+ const startAngle = currentAngle + (val > 0 ? padAngle / 2 : 0);
2561
+ const endAngle = currentAngle + sliceAngle - (val > 0 ? padAngle / 2 : 0);
2562
+ currentAngle += sliceAngle;
2563
+ if (val <= 0 || endAngle <= startAngle)
2564
+ continue;
2565
+ const d = pathArc({
2566
+ cx: centerX,
2567
+ cy: centerY,
2568
+ innerRadius,
2569
+ outerRadius,
2570
+ startAngle,
2571
+ endAngle
2572
+ });
2573
+ const fill = colors[i % colors.length];
2574
+ slices.push(/* @__PURE__ */ jsx("path", {
2575
+ d,
2576
+ fill,
2577
+ stroke: "#ffffff",
2578
+ "stroke-width": 1.5
2579
+ }));
2580
+ }
2581
+ return slices;
2582
+ }
2583
+ });
2584
+ };
2585
+ }
2586
+ // src/charts/Tooltip.tsx
2587
+ function ChartTooltip(props) {
2588
+ const render = () => {
2589
+ const ctx = useChartContext();
2590
+ const hover = ctx.hoverState();
2591
+ if (!hover.active || !hover.datum)
2592
+ return null;
2593
+ const w = ctx.width();
2594
+ const datum = hover.datum;
2595
+ const series = ctx.series();
2596
+ const xKey = ctx.xDataKey();
2597
+ const cardWidth = 160;
2598
+ let left = hover.x + 14;
2599
+ if (left + cardWidth > w) {
2600
+ left = Math.max(10, hover.x - cardWidth - 14);
2601
+ }
2602
+ const top = Math.max(10, hover.y - 30);
2603
+ if (props.content) {
2604
+ return /* @__PURE__ */ jsx("div", {
2605
+ style: {
2606
+ position: "absolute",
2607
+ left: `${left}px`,
2608
+ top: `${top}px`,
2609
+ pointerEvents: "none",
2610
+ zIndex: 50
2611
+ },
2612
+ children: props.content(datum, series)
2613
+ });
2614
+ }
2615
+ const label = xKey && datum[xKey] !== undefined ? datum[xKey] : `#${hover.index + 1}`;
2616
+ const formattedLabel = props.labelFormat ? props.labelFormat(label) : String(label);
2617
+ return /* @__PURE__ */ jsxs("div", {
2618
+ class: props.class || props.className,
2619
+ style: {
2620
+ position: "absolute",
2621
+ left: `${left}px`,
2622
+ top: `${top}px`,
2623
+ pointerEvents: "none",
2624
+ zIndex: 50,
2625
+ minWidth: `${cardWidth}px`,
2626
+ padding: "8px 12px",
2627
+ borderRadius: "10px",
2628
+ background: "rgba(255, 255, 255, 0.92)",
2629
+ backdropFilter: "blur(12px)",
2630
+ WebkitBackdropFilter: "blur(12px)",
2631
+ border: "1px solid rgba(226, 232, 240, 0.8)",
2632
+ boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.05)",
2633
+ fontSize: "12px",
2634
+ color: "#1e293b",
2635
+ lineHeight: "1.4"
2636
+ },
2637
+ children: [
2638
+ /* @__PURE__ */ jsx("div", {
2639
+ style: {
2640
+ fontWeight: "600",
2641
+ color: "#475569",
2642
+ marginBottom: "6px",
2643
+ borderBottom: "1px solid #f1f5f9",
2644
+ paddingBottom: "4px"
2645
+ },
2646
+ children: formattedLabel
2647
+ }),
2648
+ /* @__PURE__ */ jsx("div", {
2649
+ style: { display: "flex", flexDirection: "column", gap: "4px" },
2650
+ children: series.map((s) => {
2651
+ const rawVal = datum[s.dataKey];
2652
+ if (rawVal === undefined || rawVal === null)
2653
+ return null;
2654
+ const valStr = props.format ? props.format(rawVal, s.name ?? s.dataKey) : String(rawVal);
2655
+ return /* @__PURE__ */ jsxs("div", {
2656
+ style: {
2657
+ display: "flex",
2658
+ alignItems: "center",
2659
+ justifyContent: "space-between",
2660
+ gap: "8px"
2661
+ },
2662
+ children: [
2663
+ /* @__PURE__ */ jsxs("div", {
2664
+ style: { display: "flex", alignItems: "center", gap: "6px" },
2665
+ children: [
2666
+ /* @__PURE__ */ jsx("span", {
2667
+ style: {
2668
+ width: "8px",
2669
+ height: "8px",
2670
+ borderRadius: "50%",
2671
+ background: s.color ?? "#8b5cf6"
2672
+ }
2673
+ }),
2674
+ /* @__PURE__ */ jsx("span", {
2675
+ style: { color: "#64748b" },
2676
+ children: s.name ?? s.dataKey
2677
+ })
2678
+ ]
2679
+ }),
2680
+ /* @__PURE__ */ jsx("span", {
2681
+ style: { fontWeight: "600", color: "#0f172a" },
2682
+ children: valStr
2683
+ })
2684
+ ]
2685
+ });
2686
+ })
2687
+ })
2688
+ ]
2689
+ });
2690
+ };
2691
+ render.__visage_overlay = true;
2692
+ return render;
2693
+ }
2694
+ var Tooltip = ChartTooltip;
2695
+ export {
2696
+ Area,
2697
+ Bar,
2698
+ CartesianGrid,
2699
+ Chart,
2700
+ ChartContext,
2701
+ ChartCursor,
2702
+ ChartLegend,
2703
+ ChartTooltip,
2704
+ Legend,
2705
+ Line,
2706
+ Pie,
2707
+ Tooltip,
2708
+ XAxis,
2709
+ YAxis,
2710
+ createBandScale,
2711
+ createLinearScale,
2712
+ generateNiceTicks,
2713
+ pathArc,
2714
+ pathArea,
2715
+ pathLine,
2716
+ useChartContext
2717
+ };