@tangle-network/sandbox-ui 0.10.4 → 0.10.6

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.
@@ -115,11 +115,107 @@ var SelectSeparator = React.forwardRef(({ className, ...props }, ref) => /* @__P
115
115
  ));
116
116
  SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
117
117
 
118
+ // src/primitives/segmented-control.tsx
119
+ import * as React2 from "react";
120
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
121
+ function SegmentedControl({
122
+ value,
123
+ onValueChange,
124
+ options,
125
+ variant = "row",
126
+ className,
127
+ ...rest
128
+ }) {
129
+ if (typeof process !== "undefined" && process?.env?.NODE_ENV !== "production" && !rest["aria-label"] && !rest["aria-labelledby"]) {
130
+ console.warn(
131
+ '[SegmentedControl] role="radiogroup" requires either aria-label or aria-labelledby for accessibility.'
132
+ );
133
+ }
134
+ const optionRefs = React2.useRef(/* @__PURE__ */ new Map());
135
+ const hasMatch = options.some((o) => o.value === value);
136
+ const handleKeyDown = (e) => {
137
+ if (options.length === 0) return;
138
+ let idx = options.findIndex((o) => o.value === value);
139
+ if (idx === -1) idx = 0;
140
+ let next;
141
+ if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (idx + 1) % options.length;
142
+ else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = (idx - 1 + options.length) % options.length;
143
+ else if (e.key === "Home") next = 0;
144
+ else if (e.key === "End") next = options.length - 1;
145
+ if (next !== void 0) {
146
+ e.preventDefault();
147
+ if (options[next].value !== value) {
148
+ onValueChange(options[next].value);
149
+ }
150
+ optionRefs.current.get(options[next].value)?.focus();
151
+ }
152
+ };
153
+ return /* @__PURE__ */ jsx2(
154
+ "div",
155
+ {
156
+ role: "radiogroup",
157
+ id: rest.id,
158
+ "aria-label": rest["aria-label"],
159
+ "aria-labelledby": rest["aria-labelledby"],
160
+ onKeyDown: handleKeyDown,
161
+ className: cn(
162
+ "flex gap-1",
163
+ variant === "row" && "flex-wrap items-center rounded-lg border border-border bg-card p-1",
164
+ variant === "tabs" && "flex-nowrap items-end border-b border-border pb-0 overflow-x-auto",
165
+ className
166
+ ),
167
+ children: options.map((option, i) => {
168
+ const active = option.value === value;
169
+ const focusable = active || !hasMatch && i === 0;
170
+ return /* @__PURE__ */ jsxs2(
171
+ "button",
172
+ {
173
+ ref: (el) => {
174
+ if (el) optionRefs.current.set(option.value, el);
175
+ else optionRefs.current.delete(option.value);
176
+ },
177
+ type: "button",
178
+ role: "radio",
179
+ "aria-checked": active,
180
+ tabIndex: focusable ? 0 : -1,
181
+ onClick: () => {
182
+ if (!active) onValueChange(option.value);
183
+ },
184
+ className: cn(
185
+ "relative inline-flex items-center gap-2 whitespace-nowrap text-sm transition-colors",
186
+ variant === "row" && "rounded-md px-3 py-1.5",
187
+ variant === "tabs" && "rounded-none border-b-2 -mb-px px-4 py-2",
188
+ // Active styling is the ONLY styled state — unselected
189
+ // segments stay transparent on purpose so they don't
190
+ // compete visually with the selection.
191
+ active ? variant === "row" ? "border border-transparent bg-[var(--accent-surface)] text-[var(--accent-text)] font-semibold" : "border-[var(--accent-text)] text-[var(--accent-text)] font-semibold" : variant === "row" ? "border border-transparent text-muted-foreground hover:text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"
192
+ ),
193
+ children: [
194
+ /* @__PURE__ */ jsx2("span", { children: option.label }),
195
+ option.adornment && /* @__PURE__ */ jsx2(
196
+ "span",
197
+ {
198
+ className: cn(
199
+ "text-xs",
200
+ active ? "text-[var(--accent-text)]/80" : "text-muted-foreground"
201
+ ),
202
+ children: option.adornment
203
+ }
204
+ )
205
+ ]
206
+ },
207
+ option.value
208
+ );
209
+ })
210
+ }
211
+ );
212
+ }
213
+
118
214
  // src/primitives/switch.tsx
119
215
  import * as SwitchPrimitives from "@radix-ui/react-switch";
120
- import * as React2 from "react";
121
- import { jsx as jsx2 } from "react/jsx-runtime";
122
- var Switch = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
216
+ import * as React3 from "react";
217
+ import { jsx as jsx3 } from "react/jsx-runtime";
218
+ var Switch = React3.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx3(
123
219
  SwitchPrimitives.Root,
124
220
  {
125
221
  className: cn(
@@ -128,7 +224,7 @@ var Switch = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
128
224
  ),
129
225
  ...props,
130
226
  ref,
131
- children: /* @__PURE__ */ jsx2(
227
+ children: /* @__PURE__ */ jsx3(
132
228
  SwitchPrimitives.Thumb,
133
229
  {
134
230
  className: cn(
@@ -149,8 +245,8 @@ import {
149
245
  Info,
150
246
  X
151
247
  } from "lucide-react";
152
- import * as React3 from "react";
153
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
248
+ import * as React4 from "react";
249
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
154
250
  var toastVariants = cva(
155
251
  "pointer-events-auto relative flex w-full items-center justify-between gap-3 overflow-hidden rounded-lg border p-4 shadow-lg transition-all",
156
252
  {
@@ -183,28 +279,28 @@ function ToastComponent({
183
279
  onDismiss
184
280
  }) {
185
281
  const Icon2 = icons[variant];
186
- return /* @__PURE__ */ jsxs2(
282
+ return /* @__PURE__ */ jsxs3(
187
283
  "div",
188
284
  {
189
285
  className: cn(toastVariants({ variant })),
190
286
  role: "alert",
191
287
  "aria-live": "polite",
192
288
  children: [
193
- /* @__PURE__ */ jsxs2("div", { className: "flex items-start gap-3", children: [
194
- /* @__PURE__ */ jsx3(Icon2, { className: "h-5 w-5 shrink-0", "aria-hidden": "true" }),
195
- /* @__PURE__ */ jsxs2("div", { className: "flex-1", children: [
196
- /* @__PURE__ */ jsx3("p", { className: "font-medium text-sm", children: title }),
197
- description && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-sm opacity-80", children: description })
289
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-start gap-3", children: [
290
+ /* @__PURE__ */ jsx4(Icon2, { className: "h-5 w-5 shrink-0", "aria-hidden": "true" }),
291
+ /* @__PURE__ */ jsxs3("div", { className: "flex-1", children: [
292
+ /* @__PURE__ */ jsx4("p", { className: "font-medium text-sm", children: title }),
293
+ description && /* @__PURE__ */ jsx4("p", { className: "mt-1 text-sm opacity-80", children: description })
198
294
  ] })
199
295
  ] }),
200
- /* @__PURE__ */ jsx3(
296
+ /* @__PURE__ */ jsx4(
201
297
  "button",
202
298
  {
203
299
  type: "button",
204
300
  onClick: () => onDismiss(id),
205
301
  className: "shrink-0 rounded-md p-1 opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2",
206
302
  "aria-label": "Dismiss notification",
207
- children: /* @__PURE__ */ jsx3(X, { className: "h-4 w-4" })
303
+ children: /* @__PURE__ */ jsx4(X, { className: "h-4 w-4" })
208
304
  }
209
305
  )
210
306
  ]
@@ -212,22 +308,22 @@ function ToastComponent({
212
308
  );
213
309
  }
214
310
  function ToastContainer({ toasts, onDismiss }) {
215
- return /* @__PURE__ */ jsx3(
311
+ return /* @__PURE__ */ jsx4(
216
312
  "div",
217
313
  {
218
314
  className: "fixed right-4 bottom-4 z-50 flex max-w-md flex-col gap-2",
219
315
  "aria-label": "Notifications",
220
- children: toasts.map((toast) => /* @__PURE__ */ jsx3(ToastComponent, { ...toast, onDismiss }, toast.id))
316
+ children: toasts.map((toast) => /* @__PURE__ */ jsx4(ToastComponent, { ...toast, onDismiss }, toast.id))
221
317
  }
222
318
  );
223
319
  }
224
- var ToastContext = React3.createContext(null);
320
+ var ToastContext = React4.createContext(null);
225
321
  function ToastProvider({ children }) {
226
- const [toasts, setToasts] = React3.useState([]);
227
- const dismiss = React3.useCallback((id) => {
322
+ const [toasts, setToasts] = React4.useState([]);
323
+ const dismiss = React4.useCallback((id) => {
228
324
  setToasts((prev) => prev.filter((t) => t.id !== id));
229
325
  }, []);
230
- const toast = React3.useCallback(
326
+ const toast = React4.useCallback(
231
327
  (input) => {
232
328
  const id = Math.random().toString(36).slice(2);
233
329
  const newToast = { id, ...input };
@@ -239,41 +335,41 @@ function ToastProvider({ children }) {
239
335
  },
240
336
  [dismiss]
241
337
  );
242
- const success = React3.useCallback(
338
+ const success = React4.useCallback(
243
339
  (title, description) => {
244
340
  toast({ title, description, variant: "success" });
245
341
  },
246
342
  [toast]
247
343
  );
248
- const error = React3.useCallback(
344
+ const error = React4.useCallback(
249
345
  (title, description) => {
250
346
  toast({ title, description, variant: "error" });
251
347
  },
252
348
  [toast]
253
349
  );
254
- const warning = React3.useCallback(
350
+ const warning = React4.useCallback(
255
351
  (title, description) => {
256
352
  toast({ title, description, variant: "warning" });
257
353
  },
258
354
  [toast]
259
355
  );
260
- const info = React3.useCallback(
356
+ const info = React4.useCallback(
261
357
  (title, description) => {
262
358
  toast({ title, description, variant: "info" });
263
359
  },
264
360
  [toast]
265
361
  );
266
- const value = React3.useMemo(
362
+ const value = React4.useMemo(
267
363
  () => ({ toasts, toast, success, error, warning, info, dismiss }),
268
364
  [toasts, toast, success, error, warning, info, dismiss]
269
365
  );
270
- return /* @__PURE__ */ jsxs2(ToastContext.Provider, { value, children: [
366
+ return /* @__PURE__ */ jsxs3(ToastContext.Provider, { value, children: [
271
367
  children,
272
- /* @__PURE__ */ jsx3(ToastContainer, { toasts, onDismiss: dismiss })
368
+ /* @__PURE__ */ jsx4(ToastContainer, { toasts, onDismiss: dismiss })
273
369
  ] });
274
370
  }
275
371
  function useToast() {
276
- const context = React3.useContext(ToastContext);
372
+ const context = React4.useContext(ToastContext);
277
373
  if (!context) {
278
374
  throw new Error("useToast must be used within a ToastProvider");
279
375
  }
@@ -283,12 +379,12 @@ function useToast() {
283
379
  // src/primitives/label.tsx
284
380
  import * as LabelPrimitive from "@radix-ui/react-label";
285
381
  import { cva as cva2 } from "class-variance-authority";
286
- import * as React4 from "react";
287
- import { jsx as jsx4 } from "react/jsx-runtime";
382
+ import * as React5 from "react";
383
+ import { jsx as jsx5 } from "react/jsx-runtime";
288
384
  var labelVariants = cva2(
289
385
  "font-medium text-sm leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
290
386
  );
291
- var Label2 = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx4(
387
+ var Label2 = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
292
388
  LabelPrimitive.Root,
293
389
  {
294
390
  ref,
@@ -299,10 +395,10 @@ var Label2 = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
299
395
  Label2.displayName = LabelPrimitive.Root.displayName;
300
396
 
301
397
  // src/primitives/terminal-display.tsx
302
- import * as React5 from "react";
303
- import { useEffect, useRef } from "react";
304
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
305
- var TerminalDisplay = React5.forwardRef(
398
+ import * as React6 from "react";
399
+ import { useEffect, useRef as useRef2 } from "react";
400
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
401
+ var TerminalDisplay = React6.forwardRef(
306
402
  ({
307
403
  className,
308
404
  variant = "default",
@@ -313,7 +409,7 @@ var TerminalDisplay = React5.forwardRef(
313
409
  children,
314
410
  ...props
315
411
  }, ref) => {
316
- const containerRef = useRef(null);
412
+ const containerRef = useRef2(null);
317
413
  useEffect(() => {
318
414
  if (autoScroll && containerRef.current) {
319
415
  containerRef.current.scrollTop = containerRef.current.scrollHeight;
@@ -323,7 +419,7 @@ var TerminalDisplay = React5.forwardRef(
323
419
  default: "border-border",
324
420
  sandbox: "border-border shadow-[var(--shadow-accent)]"
325
421
  };
326
- return /* @__PURE__ */ jsxs3(
422
+ return /* @__PURE__ */ jsxs4(
327
423
  "div",
328
424
  {
329
425
  ref,
@@ -334,8 +430,8 @@ var TerminalDisplay = React5.forwardRef(
334
430
  ),
335
431
  ...props,
336
432
  children: [
337
- showHeader && /* @__PURE__ */ jsx5("div", { className: "flex items-center border-b border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground text-xs", children: title }) }),
338
- /* @__PURE__ */ jsx5(
433
+ showHeader && /* @__PURE__ */ jsx6("div", { className: "flex items-center border-b border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx6("span", { className: "text-muted-foreground text-xs", children: title }) }),
434
+ /* @__PURE__ */ jsx6(
339
435
  "div",
340
436
  {
341
437
  ref: containerRef,
@@ -350,7 +446,7 @@ var TerminalDisplay = React5.forwardRef(
350
446
  }
351
447
  );
352
448
  TerminalDisplay.displayName = "TerminalDisplay";
353
- var TerminalLine = React5.forwardRef(
449
+ var TerminalLine = React6.forwardRef(
354
450
  ({ className, type = "output", prompt = "$", timestamp, children, ...props }, ref) => {
355
451
  const typeStyles = {
356
452
  input: "text-foreground",
@@ -362,7 +458,7 @@ var TerminalLine = React5.forwardRef(
362
458
  command: "text-foreground",
363
459
  warning: "text-[var(--surface-warning-text)]"
364
460
  };
365
- return /* @__PURE__ */ jsxs3(
461
+ return /* @__PURE__ */ jsxs4(
366
462
  "div",
367
463
  {
368
464
  ref,
@@ -373,21 +469,21 @@ var TerminalLine = React5.forwardRef(
373
469
  ),
374
470
  ...props,
375
471
  children: [
376
- (type === "input" || type === "command") && /* @__PURE__ */ jsx5("span", { className: "shrink-0 select-none text-[var(--surface-success-text)]", children: prompt }),
377
- type === "thinking" && /* @__PURE__ */ jsx5("span", { className: "shrink-0 select-none", children: "..." }),
378
- timestamp && /* @__PURE__ */ jsxs3("span", { className: "shrink-0 select-none text-muted-foreground opacity-50", children: [
472
+ (type === "input" || type === "command") && /* @__PURE__ */ jsx6("span", { className: "shrink-0 select-none text-[var(--surface-success-text)]", children: prompt }),
473
+ type === "thinking" && /* @__PURE__ */ jsx6("span", { className: "shrink-0 select-none", children: "..." }),
474
+ timestamp && /* @__PURE__ */ jsxs4("span", { className: "shrink-0 select-none text-muted-foreground opacity-50", children: [
379
475
  "[",
380
476
  timestamp,
381
477
  "]"
382
478
  ] }),
383
- /* @__PURE__ */ jsx5("span", { className: "whitespace-pre-wrap break-all", children })
479
+ /* @__PURE__ */ jsx6("span", { className: "whitespace-pre-wrap break-all", children })
384
480
  ]
385
481
  }
386
482
  );
387
483
  }
388
484
  );
389
485
  TerminalLine.displayName = "TerminalLine";
390
- var TerminalCursor = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
486
+ var TerminalCursor = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx6(
391
487
  "span",
392
488
  {
393
489
  ref,
@@ -399,9 +495,9 @@ var TerminalCursor = React5.forwardRef(({ className, ...props }, ref) => /* @__P
399
495
  }
400
496
  ));
401
497
  TerminalCursor.displayName = "TerminalCursor";
402
- var TerminalInput = React5.forwardRef(
498
+ var TerminalInput = React6.forwardRef(
403
499
  ({ className, onSubmit, variant = "default", ...props }, ref) => {
404
- const [value, setValue] = React5.useState("");
500
+ const [value, setValue] = React6.useState("");
405
501
  const handleKeyDown = (e) => {
406
502
  if (e.key === "Enter" && value.trim() && onSubmit) {
407
503
  onSubmit(value.trim());
@@ -412,7 +508,7 @@ var TerminalInput = React5.forwardRef(
412
508
  default: "border-border focus-within:border-border",
413
509
  sandbox: "border-border focus-within:border-[var(--border-accent-hover)]"
414
510
  };
415
- return /* @__PURE__ */ jsxs3(
511
+ return /* @__PURE__ */ jsxs4(
416
512
  "div",
417
513
  {
418
514
  className: cn(
@@ -421,8 +517,8 @@ var TerminalInput = React5.forwardRef(
421
517
  className
422
518
  ),
423
519
  children: [
424
- /* @__PURE__ */ jsx5("span", { className: "mr-2 select-none text-[var(--surface-success-text)]", children: "$" }),
425
- /* @__PURE__ */ jsx5(
520
+ /* @__PURE__ */ jsx6("span", { className: "mr-2 select-none text-[var(--surface-success-text)]", children: "$" }),
521
+ /* @__PURE__ */ jsx6(
426
522
  "input",
427
523
  {
428
524
  ref,
@@ -434,7 +530,7 @@ var TerminalInput = React5.forwardRef(
434
530
  ...props
435
531
  }
436
532
  ),
437
- /* @__PURE__ */ jsx5(TerminalCursor, {})
533
+ /* @__PURE__ */ jsx6(TerminalCursor, {})
438
534
  ]
439
535
  }
440
536
  );
@@ -443,8 +539,8 @@ var TerminalInput = React5.forwardRef(
443
539
  TerminalInput.displayName = "TerminalInput";
444
540
 
445
541
  // src/primitives/drop-zone.tsx
446
- import { useCallback as useCallback2, useRef as useRef2, useState as useState3 } from "react";
447
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
542
+ import { useCallback as useCallback2, useRef as useRef3, useState as useState3 } from "react";
543
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
448
544
  function DropZone({
449
545
  onDrop,
450
546
  accept,
@@ -457,7 +553,7 @@ function DropZone({
457
553
  className
458
554
  }) {
459
555
  const [dragOver, setDragOver] = useState3(false);
460
- const counter = useRef2(0);
556
+ const counter = useRef3(0);
461
557
  const isAccepted = useCallback2(
462
558
  (file) => {
463
559
  if (!accept) return true;
@@ -500,7 +596,7 @@ function DropZone({
500
596
  },
501
597
  [disabled, accept, isAccepted, onDrop]
502
598
  );
503
- return /* @__PURE__ */ jsxs4(
599
+ return /* @__PURE__ */ jsxs5(
504
600
  "div",
505
601
  {
506
602
  onDragEnter: handleDragEnter,
@@ -509,15 +605,15 @@ function DropZone({
509
605
  onDrop: handleDrop,
510
606
  className: cn("relative", className),
511
607
  children: [
512
- dragOver && (overlay || /* @__PURE__ */ jsx6("div", { className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none bg-background", children: /* @__PURE__ */ jsxs4("div", { className: "rounded-2xl border-2 border-dashed border-border bg-card p-16 text-center shadow-[var(--shadow-dropdown)] max-w-lg mx-auto", children: [
513
- /* @__PURE__ */ jsx6("div", { className: "mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-2xl border border-border bg-[var(--accent-surface-soft)]", children: typeof icon === "string" ? /* @__PURE__ */ jsxs4("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "h-10 w-10 text-[var(--accent-text)]", children: [
514
- /* @__PURE__ */ jsx6("title", { children: "Upload" }),
515
- /* @__PURE__ */ jsx6("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
516
- /* @__PURE__ */ jsx6("polyline", { points: "17 8 12 3 7 8" }),
517
- /* @__PURE__ */ jsx6("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
608
+ dragOver && (overlay || /* @__PURE__ */ jsx7("div", { className: "fixed inset-0 z-[100] flex items-center justify-center pointer-events-none bg-background", children: /* @__PURE__ */ jsxs5("div", { className: "rounded-2xl border-2 border-dashed border-border bg-card p-16 text-center shadow-[var(--shadow-dropdown)] max-w-lg mx-auto", children: [
609
+ /* @__PURE__ */ jsx7("div", { className: "mx-auto mb-6 flex h-20 w-20 items-center justify-center rounded-2xl border border-border bg-[var(--accent-surface-soft)]", children: typeof icon === "string" ? /* @__PURE__ */ jsxs5("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "h-10 w-10 text-[var(--accent-text)]", children: [
610
+ /* @__PURE__ */ jsx7("title", { children: "Upload" }),
611
+ /* @__PURE__ */ jsx7("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
612
+ /* @__PURE__ */ jsx7("polyline", { points: "17 8 12 3 7 8" }),
613
+ /* @__PURE__ */ jsx7("line", { x1: "12", x2: "12", y1: "3", y2: "15" })
518
614
  ] }) : icon }),
519
- /* @__PURE__ */ jsx6("h2", { className: "text-2xl font-bold text-foreground", children: title }),
520
- /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
615
+ /* @__PURE__ */ jsx7("h2", { className: "text-2xl font-bold text-foreground", children: title }),
616
+ /* @__PURE__ */ jsx7("p", { className: "mt-2 text-sm text-muted-foreground", children: description })
521
617
  ] }) })),
522
618
  children
523
619
  ]
@@ -527,7 +623,7 @@ function DropZone({
527
623
 
528
624
  // src/primitives/upload-progress.tsx
529
625
  import { AlertCircle as AlertCircle2, CheckCircle2 as CheckCircle22, FileText, Loader2, RefreshCw, X as X2 } from "lucide-react";
530
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
626
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
531
627
  function formatSize(bytes) {
532
628
  if (bytes < 1024) return `${bytes}B`;
533
629
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}KB`;
@@ -535,7 +631,7 @@ function formatSize(bytes) {
535
631
  }
536
632
  function UploadProgress({ files, onRemove, onRetry, className }) {
537
633
  if (files.length === 0) return null;
538
- return /* @__PURE__ */ jsx7("div", { className: cn("space-y-2", className), children: files.map((file) => /* @__PURE__ */ jsxs5(
634
+ return /* @__PURE__ */ jsx8("div", { className: cn("space-y-2", className), children: files.map((file) => /* @__PURE__ */ jsxs6(
539
635
  "div",
540
636
  {
541
637
  className: cn(
@@ -543,41 +639,41 @@ function UploadProgress({ files, onRemove, onRetry, className }) {
543
639
  file.status === "error" ? "border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)]" : file.status === "complete" ? "border-[var(--surface-success-border)] bg-[var(--surface-success-bg)]" : "border-border bg-card"
544
640
  ),
545
641
  children: [
546
- file.status === "complete" && /* @__PURE__ */ jsx7(CheckCircle22, { className: "h-4 w-4 shrink-0 text-[var(--surface-success-text)]" }),
547
- file.status === "error" && /* @__PURE__ */ jsx7(AlertCircle2, { className: "h-4 w-4 shrink-0 text-[var(--surface-danger-text)]" }),
548
- file.status === "uploading" && /* @__PURE__ */ jsx7(Loader2, { className: "h-4 w-4 shrink-0 animate-spin text-primary" }),
549
- file.status === "pending" && /* @__PURE__ */ jsx7(FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
550
- /* @__PURE__ */ jsxs5("div", { className: "min-w-0 flex-1", children: [
551
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
552
- /* @__PURE__ */ jsx7("span", { className: "truncate font-medium text-foreground", children: file.name }),
553
- /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatSize(file.size) })
642
+ file.status === "complete" && /* @__PURE__ */ jsx8(CheckCircle22, { className: "h-4 w-4 shrink-0 text-[var(--surface-success-text)]" }),
643
+ file.status === "error" && /* @__PURE__ */ jsx8(AlertCircle2, { className: "h-4 w-4 shrink-0 text-[var(--surface-danger-text)]" }),
644
+ file.status === "uploading" && /* @__PURE__ */ jsx8(Loader2, { className: "h-4 w-4 shrink-0 animate-spin text-primary" }),
645
+ file.status === "pending" && /* @__PURE__ */ jsx8(FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
646
+ /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1", children: [
647
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
648
+ /* @__PURE__ */ jsx8("span", { className: "truncate font-medium text-foreground", children: file.name }),
649
+ /* @__PURE__ */ jsx8("span", { className: "shrink-0 text-xs text-muted-foreground", children: formatSize(file.size) })
554
650
  ] }),
555
- file.status === "uploading" && file.progress !== void 0 && /* @__PURE__ */ jsx7("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted/50", children: /* @__PURE__ */ jsx7(
651
+ file.status === "uploading" && file.progress !== void 0 && /* @__PURE__ */ jsx8("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted/50", children: /* @__PURE__ */ jsx8(
556
652
  "div",
557
653
  {
558
654
  className: "h-full rounded-full bg-primary transition-all",
559
655
  style: { width: `${file.progress}%` }
560
656
  }
561
657
  ) }),
562
- file.status === "error" && file.error && /* @__PURE__ */ jsx7("p", { className: "mt-0.5 text-xs text-[var(--surface-danger-text)]", children: file.error })
658
+ file.status === "error" && file.error && /* @__PURE__ */ jsx8("p", { className: "mt-0.5 text-xs text-[var(--surface-danger-text)]", children: file.error })
563
659
  ] }),
564
- /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-1", children: [
565
- file.status === "error" && onRetry && /* @__PURE__ */ jsx7(
660
+ /* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 items-center gap-1", children: [
661
+ file.status === "error" && onRetry && /* @__PURE__ */ jsx8(
566
662
  "button",
567
663
  {
568
664
  type: "button",
569
665
  onClick: () => onRetry(file.id),
570
666
  className: "rounded p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
571
- children: /* @__PURE__ */ jsx7(RefreshCw, { className: "h-3.5 w-3.5" })
667
+ children: /* @__PURE__ */ jsx8(RefreshCw, { className: "h-3.5 w-3.5" })
572
668
  }
573
669
  ),
574
- onRemove && /* @__PURE__ */ jsx7(
670
+ onRemove && /* @__PURE__ */ jsx8(
575
671
  "button",
576
672
  {
577
673
  type: "button",
578
674
  onClick: () => onRemove(file.id),
579
675
  className: "rounded p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground",
580
- children: /* @__PURE__ */ jsx7(X2, { className: "h-3.5 w-3.5" })
676
+ children: /* @__PURE__ */ jsx8(X2, { className: "h-3.5 w-3.5" })
581
677
  }
582
678
  )
583
679
  ] })
@@ -588,9 +684,9 @@ function UploadProgress({ files, onRemove, onRetry, className }) {
588
684
  }
589
685
 
590
686
  // src/primitives/sidebar-drop-zone.tsx
591
- import { useCallback as useCallback3, useRef as useRef3, useState as useState4 } from "react";
687
+ import { useCallback as useCallback3, useRef as useRef4, useState as useState4 } from "react";
592
688
  import { Upload } from "lucide-react";
593
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
689
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
594
690
  function SidebarDropZone({
595
691
  onDrop,
596
692
  accept,
@@ -602,7 +698,7 @@ function SidebarDropZone({
602
698
  className
603
699
  }) {
604
700
  const [dragOver, setDragOver] = useState4(false);
605
- const counter = useRef3(0);
701
+ const counter = useRef4(0);
606
702
  const isAccepted = useCallback3(
607
703
  (file) => {
608
704
  if (!accept) return true;
@@ -650,7 +746,7 @@ function SidebarDropZone({
650
746
  [disabled, accept, isAccepted, onDrop]
651
747
  );
652
748
  const isVisible = persistent || dragOver;
653
- return /* @__PURE__ */ jsx8(
749
+ return /* @__PURE__ */ jsx9(
654
750
  "div",
655
751
  {
656
752
  onDragEnter: handleDragEnter,
@@ -664,16 +760,16 @@ function SidebarDropZone({
664
760
  disabled && "opacity-50 pointer-events-none",
665
761
  className
666
762
  ),
667
- children: isVisible && /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center gap-2 text-center", children: [
668
- /* @__PURE__ */ jsx8("div", { className: cn(
763
+ children: isVisible && /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-center gap-2 text-center", children: [
764
+ /* @__PURE__ */ jsx9("div", { className: cn(
669
765
  "flex h-8 w-8 items-center justify-center rounded-lg transition-colors",
670
766
  dragOver ? "bg-[var(--brand-cool,hsl(var(--primary)))]/15 text-[var(--brand-cool,hsl(var(--primary)))]" : "text-[var(--text-muted,hsl(var(--muted-foreground)))]"
671
- ), children: icon ?? /* @__PURE__ */ jsx8(Upload, { className: "h-4 w-4" }) }),
672
- /* @__PURE__ */ jsx8("p", { className: cn(
767
+ ), children: icon ?? /* @__PURE__ */ jsx9(Upload, { className: "h-4 w-4" }) }),
768
+ /* @__PURE__ */ jsx9("p", { className: cn(
673
769
  "text-xs font-medium",
674
770
  dragOver ? "text-[var(--text-primary,hsl(var(--foreground)))]" : "text-[var(--text-muted,hsl(var(--muted-foreground)))]"
675
771
  ), children: title }),
676
- description && /* @__PURE__ */ jsx8("p", { className: "text-[10px] text-[var(--text-muted,hsl(var(--muted-foreground)))]", children: description })
772
+ description && /* @__PURE__ */ jsx9("p", { className: "text-[10px] text-[var(--text-muted,hsl(var(--muted-foreground)))]", children: description })
677
773
  ] })
678
774
  }
679
775
  );
@@ -690,6 +786,7 @@ export {
690
786
  SelectLabel,
691
787
  SelectItem,
692
788
  SelectSeparator,
789
+ SegmentedControl,
693
790
  Switch,
694
791
  ToastContainer,
695
792
  ToastProvider,
@@ -255,7 +255,8 @@ function BillingDashboard({
255
255
  import { Check, Zap } from "lucide-react";
256
256
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
257
257
  function formatPrice(cents) {
258
- return `$${Math.round(cents / 100)}`;
258
+ if (!Number.isFinite(cents) || cents < 0) return "$0";
259
+ return cents % 100 === 0 ? `$${cents / 100}` : `$${(cents / 100).toFixed(2)}`;
259
260
  }
260
261
  function PricingPage({
261
262
  tiers,
@@ -486,6 +487,7 @@ function UsageChart({ data, title, unit, className }) {
486
487
 
487
488
  export {
488
489
  BillingDashboard,
490
+ formatPrice,
489
491
  PricingPage,
490
492
  UsageChart
491
493
  };