@cytario/design 1.13.1 → 1.15.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.
package/dist/index.js CHANGED
@@ -542,6 +542,7 @@ function Select({
542
542
  items,
543
543
  placeholder = "Select an option",
544
544
  errorMessage,
545
+ hideLabel = false,
545
546
  isDisabled,
546
547
  isRequired,
547
548
  className,
@@ -561,8 +562,9 @@ function Select({
561
562
  Label2,
562
563
  {
563
564
  className: [
564
- "text-[length:var(--font-size-sm)] font-[var(--font-weight-medium)] text-[var(--color-text-primary)]"
565
- ].join(" "),
565
+ "text-[length:var(--font-size-sm)] font-[var(--font-weight-medium)] text-[var(--color-text-primary)]",
566
+ hideLabel && "sr-only"
567
+ ].filter(Boolean).join(" "),
566
568
  children: [
567
569
  label,
568
570
  isRequired && /* @__PURE__ */ jsx7(
@@ -2141,35 +2143,320 @@ function SegmentedControlItem({
2141
2143
  );
2142
2144
  }
2143
2145
 
2146
+ // src/components/FileCard/FileCard.tsx
2147
+ import { useCallback as useCallback3 } from "react";
2148
+ import {
2149
+ File as File2,
2150
+ FileSpreadsheet,
2151
+ Folder as Folder2,
2152
+ Image,
2153
+ Info as Info2,
2154
+ Microscope
2155
+ } from "lucide-react";
2156
+ import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
2157
+ function getFileIcon(type, extension) {
2158
+ if (type === "directory") return Folder2;
2159
+ const ext = (extension ?? "").toLowerCase();
2160
+ if (ext === "ome.tif" || ext === "ome.tiff") return Microscope;
2161
+ if (/^(tiff?|png|jpe?g)$/.test(ext)) return Image;
2162
+ if (/^(csv|parquet)$/.test(ext)) return FileSpreadsheet;
2163
+ return File2;
2164
+ }
2165
+ function getTypeLabel(type, extension) {
2166
+ if (type === "directory") return "Folder";
2167
+ const ext = (extension ?? "").toLowerCase();
2168
+ if (ext === "ome.tif" || ext === "ome.tiff") return "OME-TIFF";
2169
+ if (/^tiff?$/.test(ext)) return "TIFF";
2170
+ if (ext === "csv") return "CSV";
2171
+ if (ext === "parquet") return "Parquet";
2172
+ if (ext === "png") return "PNG";
2173
+ if (/^jpe?g$/.test(ext)) return "JPEG";
2174
+ return ext.toUpperCase() || "File";
2175
+ }
2176
+ function FileIcon({
2177
+ type,
2178
+ extension,
2179
+ size = 16
2180
+ }) {
2181
+ const IconComponent = getFileIcon(type, extension);
2182
+ return /* @__PURE__ */ jsx30(
2183
+ IconComponent,
2184
+ {
2185
+ size,
2186
+ className: "shrink-0 text-[var(--color-text-secondary)]"
2187
+ }
2188
+ );
2189
+ }
2190
+ function FileCard({
2191
+ name,
2192
+ type,
2193
+ size,
2194
+ extension,
2195
+ compact = false,
2196
+ children,
2197
+ onInfo,
2198
+ href,
2199
+ onPress,
2200
+ className
2201
+ }) {
2202
+ const isInteractive = !!href || !!onPress;
2203
+ const radius = compact ? "rounded-[var(--border-radius-md)]" : "rounded-[var(--border-radius-lg)]";
2204
+ const IconComponent = getFileIcon(type, extension);
2205
+ const iconSize = compact ? 24 : 32;
2206
+ const iconColor = type === "directory" ? "text-[var(--color-text-tertiary)]" : "text-[var(--color-text-secondary)]";
2207
+ const thumbnailClass = compact ? "aspect-square rounded-t-[var(--border-radius-md)]" : "aspect-[4/3] rounded-t-[var(--border-radius-lg)]";
2208
+ const handleInfoClick = useCallback3(
2209
+ (e) => {
2210
+ if (isInteractive) {
2211
+ e.stopPropagation();
2212
+ e.preventDefault();
2213
+ }
2214
+ onInfo?.();
2215
+ },
2216
+ [onInfo, isInteractive]
2217
+ );
2218
+ const handleKeyDown = useCallback3(
2219
+ (e) => {
2220
+ if (onPress && (e.key === "Enter" || e.key === " ")) {
2221
+ e.preventDefault();
2222
+ onPress();
2223
+ }
2224
+ },
2225
+ [onPress]
2226
+ );
2227
+ const cardContent = /* @__PURE__ */ jsxs20(Fragment8, { children: [
2228
+ /* @__PURE__ */ jsxs20(
2229
+ "div",
2230
+ {
2231
+ className: `shrink-0 relative overflow-hidden bg-[var(--color-neutral-900)] ${thumbnailClass}`,
2232
+ children: [
2233
+ children ? /* @__PURE__ */ jsx30("div", { className: "h-full w-full overflow-hidden", children }) : /* @__PURE__ */ jsx30("div", { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx30(IconComponent, { size: iconSize, className: iconColor }) }),
2234
+ onInfo && /* @__PURE__ */ jsx30(
2235
+ "div",
2236
+ {
2237
+ className: [
2238
+ "absolute opacity-0 group-hover:opacity-100 group-focus-within:opacity-100",
2239
+ "transition-opacity duration-150",
2240
+ compact ? "bottom-1.5 right-1.5" : "bottom-2 right-2"
2241
+ ].join(" "),
2242
+ children: /* @__PURE__ */ jsx30(
2243
+ "span",
2244
+ {
2245
+ onClick: handleInfoClick,
2246
+ onKeyDown: (e) => {
2247
+ if (e.key === "Enter" || e.key === " ") {
2248
+ handleInfoClick(e);
2249
+ }
2250
+ },
2251
+ role: "presentation",
2252
+ children: /* @__PURE__ */ jsx30(
2253
+ IconButton,
2254
+ {
2255
+ icon: Info2,
2256
+ "aria-label": `Show info for ${name}`,
2257
+ variant: "ghost",
2258
+ size: "sm",
2259
+ className: "bg-[var(--color-neutral-900)]/75 text-[var(--color-text-inverse)] hover:bg-[var(--color-neutral-900)]/90 rounded-[var(--border-radius-sm)]",
2260
+ onPress: onInfo
2261
+ }
2262
+ )
2263
+ }
2264
+ )
2265
+ }
2266
+ )
2267
+ ]
2268
+ }
2269
+ ),
2270
+ /* @__PURE__ */ jsx30(
2271
+ "div",
2272
+ {
2273
+ className: [
2274
+ "flex flex-col border-t border-[var(--color-border-default)]",
2275
+ "bg-[var(--color-surface-default)]",
2276
+ compact ? "px-2 py-1.5 rounded-b-[var(--border-radius-md)]" : "gap-0.5 px-3 py-2 rounded-b-[var(--border-radius-lg)]"
2277
+ ].join(" "),
2278
+ children: compact ? /* @__PURE__ */ jsx30("span", { className: "text-xs font-medium text-[var(--color-text-primary)] truncate", children: name }) : /* @__PURE__ */ jsxs20(Fragment8, { children: [
2279
+ /* @__PURE__ */ jsxs20("span", { className: "flex items-center gap-1.5", children: [
2280
+ /* @__PURE__ */ jsx30(FileIcon, { type, extension, size: 16 }),
2281
+ /* @__PURE__ */ jsx30("span", { className: "text-sm font-medium text-[var(--color-text-primary)] truncate", children: name })
2282
+ ] }),
2283
+ size && /* @__PURE__ */ jsx30("span", { className: "text-xs text-[var(--color-text-secondary)] tabular-nums pl-[22px]", children: size })
2284
+ ] })
2285
+ }
2286
+ )
2287
+ ] });
2288
+ const baseStyles = [
2289
+ "group flex flex-col overflow-hidden",
2290
+ radius,
2291
+ "border border-[var(--color-border-default)]",
2292
+ "shadow-sm",
2293
+ "transition-all",
2294
+ isInteractive && "hover:border-[var(--color-border-focus)] hover:shadow-md cursor-pointer",
2295
+ isInteractive && "focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)] focus-visible:ring-offset-2 outline-none",
2296
+ className
2297
+ ].filter(Boolean).join(" ");
2298
+ if (href) {
2299
+ return /* @__PURE__ */ jsx30(
2300
+ "a",
2301
+ {
2302
+ href,
2303
+ "aria-label": name,
2304
+ className: [baseStyles, "no-underline"].join(" "),
2305
+ children: cardContent
2306
+ }
2307
+ );
2308
+ }
2309
+ if (onPress) {
2310
+ return /* @__PURE__ */ jsx30(
2311
+ "div",
2312
+ {
2313
+ role: "button",
2314
+ tabIndex: 0,
2315
+ "aria-label": name,
2316
+ className: baseStyles,
2317
+ onClick: onPress,
2318
+ onKeyDown: handleKeyDown,
2319
+ children: cardContent
2320
+ }
2321
+ );
2322
+ }
2323
+ return /* @__PURE__ */ jsx30("div", { className: baseStyles, children: cardContent });
2324
+ }
2325
+
2144
2326
  // src/components/StorageConnectionCard/StorageConnectionCard.tsx
2145
- import { AlertCircle, Database, Info as Info2 } from "lucide-react";
2327
+ import { useCallback as useCallback4 } from "react";
2328
+ import { AlertCircle, Database, Info as Info3 } from "lucide-react";
2329
+ import { twMerge as twMerge9 } from "tailwind-merge";
2330
+
2331
+ // src/components/Pill/Pill.tsx
2146
2332
  import { twMerge as twMerge7 } from "tailwind-merge";
2147
- import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
2333
+ import { jsx as jsx31 } from "react/jsx-runtime";
2334
+ var HASH_PALETTE = [
2335
+ "teal",
2336
+ // sky
2337
+ "amber",
2338
+ // amber
2339
+ "green",
2340
+ // emerald
2341
+ "rose",
2342
+ // rose
2343
+ "purple",
2344
+ // violet
2345
+ "amber",
2346
+ // orange (mapped to amber -- closest warm token)
2347
+ "teal",
2348
+ // teal
2349
+ "rose"
2350
+ // fuchsia (mapped to rose -- closest pink token)
2351
+ ];
2352
+ function pillColorFromName(name) {
2353
+ let hash = 0;
2354
+ for (let i = 0; i < name.length; i++) {
2355
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
2356
+ }
2357
+ return HASH_PALETTE[Math.abs(hash) % HASH_PALETTE.length];
2358
+ }
2359
+ var colorStyles = {
2360
+ neutral: "bg-[var(--color-badge-neutral-bg)] text-[var(--color-badge-neutral-text)]",
2361
+ purple: "bg-[var(--color-badge-purple-bg)] text-[var(--color-badge-purple-text)]",
2362
+ teal: "bg-[var(--color-badge-teal-bg)] text-[var(--color-badge-teal-text)]",
2363
+ rose: "bg-[var(--color-badge-rose-bg)] text-[var(--color-badge-rose-text)]",
2364
+ slate: "bg-[var(--color-badge-slate-bg)] text-[var(--color-badge-slate-text)]",
2365
+ green: "bg-[var(--color-badge-green-bg)] text-[var(--color-badge-green-text)]",
2366
+ amber: "bg-[var(--color-badge-amber-bg)] text-[var(--color-badge-amber-text)]"
2367
+ };
2368
+ var dotColorStyles = {
2369
+ neutral: "bg-[var(--color-badge-neutral-text)]",
2370
+ purple: "bg-[var(--color-badge-purple-text)]",
2371
+ teal: "bg-[var(--color-badge-teal-text)]",
2372
+ rose: "bg-[var(--color-badge-rose-text)]",
2373
+ slate: "bg-[var(--color-badge-slate-text)]",
2374
+ green: "bg-[var(--color-badge-green-text)]",
2375
+ amber: "bg-[var(--color-badge-amber-text)]"
2376
+ };
2377
+ function resolveColor(color, name) {
2378
+ if (color && color !== "auto") return color;
2379
+ if (name) return pillColorFromName(name);
2380
+ return "neutral";
2381
+ }
2382
+ function Pill({ children, color, name, className }) {
2383
+ const resolved = resolveColor(color, name);
2384
+ return /* @__PURE__ */ jsx31(
2385
+ "span",
2386
+ {
2387
+ className: twMerge7(
2388
+ "inline-flex items-center rounded-full",
2389
+ "px-2 py-0.5",
2390
+ "text-[length:var(--font-size-xs)] font-[number:var(--font-weight-medium)] leading-[var(--line-height-tight)]",
2391
+ colorStyles[resolved],
2392
+ className
2393
+ ),
2394
+ children
2395
+ }
2396
+ );
2397
+ }
2398
+
2399
+ // src/components/Pill/GroupPill.tsx
2400
+ import { twMerge as twMerge8 } from "tailwind-merge";
2401
+ import { jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
2402
+ function GroupPill({
2403
+ path,
2404
+ visibleCount = 3,
2405
+ className
2406
+ }) {
2407
+ const segments = path.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
2408
+ if (segments.length === 0) return null;
2409
+ const hiddenCount = Math.max(0, segments.length - visibleCount);
2410
+ const hiddenSegments = segments.slice(0, hiddenCount);
2411
+ const visibleSegments = segments.slice(hiddenCount);
2412
+ return /* @__PURE__ */ jsxs21(
2413
+ "span",
2414
+ {
2415
+ className: twMerge8(
2416
+ "inline-flex items-center gap-1",
2417
+ className
2418
+ ),
2419
+ "aria-label": `Group: ${segments.join(" / ")}`,
2420
+ children: [
2421
+ hiddenSegments.map((segment, index) => {
2422
+ const color = pillColorFromName(segment);
2423
+ return /* @__PURE__ */ jsx32(
2424
+ "span",
2425
+ {
2426
+ className: twMerge8(
2427
+ "inline-block size-2 shrink-0 rounded-full",
2428
+ dotColorStyles[color]
2429
+ ),
2430
+ "aria-hidden": "true",
2431
+ title: segment
2432
+ },
2433
+ `dot-${index}-${segment}`
2434
+ );
2435
+ }),
2436
+ visibleSegments.map((segment, index) => /* @__PURE__ */ jsx32(Pill, { name: segment, children: segment }, `pill-${index}-${segment}`))
2437
+ ]
2438
+ }
2439
+ );
2440
+ }
2441
+
2442
+ // src/components/StorageConnectionCard/StorageConnectionCard.tsx
2443
+ import { Fragment as Fragment9, jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
2148
2444
  var statusDotStyles = {
2149
2445
  connected: "bg-[var(--color-status-success)]",
2150
2446
  error: "border-2 border-[var(--color-status-danger)] bg-transparent",
2151
2447
  loading: "bg-[var(--color-status-warning)] animate-pulse"
2152
2448
  };
2153
2449
  var providerConfig = {
2154
- aws: { label: "AWS", color: "bg-[var(--color-badge-purple-bg)] text-[var(--color-badge-purple-text)]" },
2155
- azure: { label: "Azure", color: "bg-[var(--color-badge-teal-bg)] text-[var(--color-badge-teal-text)]" },
2156
- gcp: { label: "GCP", color: "bg-[var(--color-badge-slate-bg)] text-[var(--color-badge-slate-text)]" },
2157
- minio: { label: "MinIO", color: "bg-[var(--color-badge-rose-bg)] text-[var(--color-badge-rose-text)]" }
2450
+ aws: { label: "AWS", color: "purple" },
2451
+ azure: { label: "Azure", color: "teal" },
2452
+ gcp: { label: "GCP", color: "slate" },
2453
+ minio: { label: "MinIO", color: "rose" }
2158
2454
  };
2159
2455
  function ProviderBadge({ provider }) {
2160
2456
  const config = providerConfig[provider.toLowerCase()];
2161
2457
  const label = config?.label ?? provider;
2162
- const colorClass = config?.color ?? "bg-[var(--color-badge-neutral-bg)] text-[var(--color-badge-neutral-text)]";
2163
- return /* @__PURE__ */ jsx30(
2164
- "span",
2165
- {
2166
- className: twMerge7(
2167
- "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
2168
- colorClass
2169
- ),
2170
- children: label
2171
- }
2172
- );
2458
+ const color = config?.color ?? "neutral";
2459
+ return /* @__PURE__ */ jsx33(Pill, { color, children: label });
2173
2460
  }
2174
2461
  function PreviewArea({
2175
2462
  status = "connected",
@@ -2177,11 +2464,11 @@ function PreviewArea({
2177
2464
  children
2178
2465
  }) {
2179
2466
  if (status === "loading") {
2180
- return /* @__PURE__ */ jsx30("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx30(Spinner, { size: "lg", "aria-label": "Loading connection" }) });
2467
+ return /* @__PURE__ */ jsx33("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx33(Spinner, { size: "lg", "aria-label": "Loading connection" }) });
2181
2468
  }
2182
2469
  if (status === "error") {
2183
- return /* @__PURE__ */ jsxs20("div", { className: "flex h-full flex-col items-center justify-center gap-2 bg-[var(--color-surface-danger)] px-4", children: [
2184
- /* @__PURE__ */ jsx30(
2470
+ return /* @__PURE__ */ jsxs22("div", { className: "flex h-full flex-col items-center justify-center gap-2 bg-[var(--color-surface-danger)] px-4", children: [
2471
+ /* @__PURE__ */ jsx33(
2185
2472
  Icon,
2186
2473
  {
2187
2474
  icon: AlertCircle,
@@ -2189,13 +2476,13 @@ function PreviewArea({
2189
2476
  className: "text-[var(--color-text-danger)]"
2190
2477
  }
2191
2478
  ),
2192
- errorMessage && /* @__PURE__ */ jsx30("p", { className: "text-center text-xs text-[var(--color-text-danger)]", children: errorMessage })
2479
+ errorMessage && /* @__PURE__ */ jsx33("p", { className: "text-center text-xs text-[var(--color-text-danger)]", children: errorMessage })
2193
2480
  ] });
2194
2481
  }
2195
2482
  if (children) {
2196
- return /* @__PURE__ */ jsx30("div", { className: "h-full w-full overflow-hidden", children });
2483
+ return /* @__PURE__ */ jsx33("div", { className: "h-full w-full overflow-hidden", children });
2197
2484
  }
2198
- return /* @__PURE__ */ jsx30("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx30(
2485
+ return /* @__PURE__ */ jsx33("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx33(
2199
2486
  Icon,
2200
2487
  {
2201
2488
  icon: Database,
@@ -2213,42 +2500,73 @@ function StorageConnectionCard({
2213
2500
  imageCount,
2214
2501
  children,
2215
2502
  href,
2503
+ onPress,
2216
2504
  onInfo,
2217
2505
  className
2218
2506
  }) {
2219
- const cardContent = /* @__PURE__ */ jsxs20(Fragment8, { children: [
2220
- /* @__PURE__ */ jsx30("div", { className: "aspect-[4/3] bg-[var(--color-neutral-900)] overflow-hidden rounded-t-[var(--border-radius-lg)]", children: /* @__PURE__ */ jsx30(PreviewArea, { status, errorMessage, children }) }),
2221
- /* @__PURE__ */ jsxs20("div", { className: "flex flex-col gap-1.5 border-t border-[var(--color-border-default)] bg-[var(--color-surface-default)] px-3 py-2.5 rounded-b-[var(--border-radius-lg)]", children: [
2222
- /* @__PURE__ */ jsxs20("div", { className: "flex items-start gap-2", children: [
2223
- status && /* @__PURE__ */ jsx30(
2507
+ const isInteractive = !!href || !!onPress;
2508
+ const handleInfoPress = useCallback4(
2509
+ (e) => {
2510
+ if (isInteractive) {
2511
+ e.stopPropagation();
2512
+ e.preventDefault();
2513
+ }
2514
+ onInfo?.();
2515
+ },
2516
+ [onInfo, isInteractive]
2517
+ );
2518
+ const handleKeyDown = useCallback4(
2519
+ (e) => {
2520
+ if (onPress && (e.key === "Enter" || e.key === " ")) {
2521
+ e.preventDefault();
2522
+ onPress();
2523
+ }
2524
+ },
2525
+ [onPress]
2526
+ );
2527
+ const cardContent = /* @__PURE__ */ jsxs22(Fragment9, { children: [
2528
+ /* @__PURE__ */ jsx33("div", { className: "aspect-[4/3] bg-[var(--color-neutral-900)] overflow-hidden rounded-t-[var(--border-radius-lg)]", children: /* @__PURE__ */ jsx33(PreviewArea, { status, errorMessage, children }) }),
2529
+ /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1.5 border-t border-[var(--color-border-default)] bg-[var(--color-surface-default)] px-3 py-2.5 rounded-b-[var(--border-radius-lg)]", children: [
2530
+ /* @__PURE__ */ jsxs22("div", { className: "flex items-start gap-2", children: [
2531
+ status && /* @__PURE__ */ jsx33(
2224
2532
  "span",
2225
2533
  {
2226
- className: twMerge7(
2534
+ className: twMerge9(
2227
2535
  "mt-1.5 h-2 w-2 shrink-0 rounded-full",
2228
2536
  statusDotStyles[status]
2229
2537
  ),
2230
2538
  "aria-label": `Status: ${status}`
2231
2539
  }
2232
2540
  ),
2233
- /* @__PURE__ */ jsx30("span", { className: "min-w-0 flex-1 line-clamp-2 text-sm font-medium text-[var(--color-text-primary)]", children: name }),
2234
- onInfo && /* @__PURE__ */ jsx30(
2235
- IconButton,
2541
+ /* @__PURE__ */ jsx33("span", { className: "min-w-0 flex-1 line-clamp-2 text-sm font-medium text-[var(--color-text-primary)]", children: name }),
2542
+ onInfo && /* @__PURE__ */ jsx33(
2543
+ "span",
2236
2544
  {
2237
- icon: Info2,
2238
- "aria-label": "Connection info",
2239
- variant: "ghost",
2240
- size: "sm",
2241
- className: "shrink-0 -mt-1 -mr-1",
2242
- onPress: () => {
2243
- onInfo();
2244
- }
2545
+ onClick: handleInfoPress,
2546
+ onKeyDown: (e) => {
2547
+ if (e.key === "Enter" || e.key === " ") {
2548
+ handleInfoPress(e);
2549
+ }
2550
+ },
2551
+ role: "presentation",
2552
+ children: /* @__PURE__ */ jsx33(
2553
+ IconButton,
2554
+ {
2555
+ icon: Info3,
2556
+ "aria-label": "Connection info",
2557
+ variant: "ghost",
2558
+ size: "sm",
2559
+ className: "shrink-0 -mt-1 -mr-1",
2560
+ onPress: onInfo
2561
+ }
2562
+ )
2245
2563
  }
2246
2564
  )
2247
2565
  ] }),
2248
- (provider || imageCount != null && (!status || status === "connected")) && /* @__PURE__ */ jsxs20("div", { className: twMerge7("flex items-center gap-2", status && "pl-4"), children: [
2249
- provider && /* @__PURE__ */ jsx30(ProviderBadge, { provider }),
2250
- provider && region && /* @__PURE__ */ jsx30("span", { className: "shrink-0 text-xs text-[var(--color-text-secondary)]", children: region }),
2251
- imageCount != null && (!status || status === "connected") && /* @__PURE__ */ jsxs20("span", { className: "ml-auto shrink-0 text-xs tabular-nums text-[var(--color-text-tertiary)]", children: [
2566
+ (provider || imageCount != null && (!status || status === "connected")) && /* @__PURE__ */ jsxs22("div", { className: twMerge9("flex items-center gap-2", status && "pl-4"), children: [
2567
+ provider && /* @__PURE__ */ jsx33(ProviderBadge, { provider }),
2568
+ provider && region && /* @__PURE__ */ jsx33("span", { className: "shrink-0 text-xs text-[var(--color-text-secondary)]", children: region }),
2569
+ imageCount != null && (!status || status === "connected") && /* @__PURE__ */ jsxs22("span", { className: "ml-auto shrink-0 text-xs tabular-nums text-[var(--color-text-secondary)]", children: [
2252
2570
  imageCount,
2253
2571
  " ",
2254
2572
  imageCount === 1 ? "image" : "images"
@@ -2256,22 +2574,36 @@ function StorageConnectionCard({
2256
2574
  ] })
2257
2575
  ] })
2258
2576
  ] });
2259
- const baseStyles = twMerge7(
2577
+ const baseStyles = twMerge9(
2260
2578
  "flex flex-col overflow-hidden rounded-[var(--border-radius-lg)]",
2261
2579
  "border border-[var(--color-border-default)]",
2262
2580
  "shadow-sm transition-all",
2263
- href && "hover:border-[var(--color-border-focus)] hover:shadow-md cursor-pointer",
2581
+ isInteractive && "hover:border-[var(--color-border-focus)] hover:shadow-md cursor-pointer",
2582
+ isInteractive && "focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)] focus-visible:ring-offset-2 outline-none",
2264
2583
  className
2265
2584
  );
2266
2585
  if (href) {
2267
- return /* @__PURE__ */ jsx30("a", { href, className: twMerge7(baseStyles, "no-underline"), children: cardContent });
2586
+ return /* @__PURE__ */ jsx33("a", { href, className: twMerge9(baseStyles, "no-underline"), children: cardContent });
2268
2587
  }
2269
- return /* @__PURE__ */ jsx30("div", { className: baseStyles, children: cardContent });
2588
+ if (onPress) {
2589
+ return /* @__PURE__ */ jsx33(
2590
+ "div",
2591
+ {
2592
+ role: "button",
2593
+ tabIndex: 0,
2594
+ className: baseStyles,
2595
+ onClick: onPress,
2596
+ onKeyDown: handleKeyDown,
2597
+ children: cardContent
2598
+ }
2599
+ );
2600
+ }
2601
+ return /* @__PURE__ */ jsx33("div", { className: baseStyles, children: cardContent });
2270
2602
  }
2271
2603
 
2272
2604
  // src/components/Badge/Badge.tsx
2273
- import { twMerge as twMerge8 } from "tailwind-merge";
2274
- import { jsx as jsx31, jsxs as jsxs21 } from "react/jsx-runtime";
2605
+ import { twMerge as twMerge10 } from "tailwind-merge";
2606
+ import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
2275
2607
  var variantStyles4 = {
2276
2608
  neutral: "bg-[var(--color-badge-neutral-bg)] text-[var(--color-badge-neutral-text)]",
2277
2609
  purple: "bg-[var(--color-badge-purple-bg)] text-[var(--color-badge-purple-text)]",
@@ -2296,10 +2628,10 @@ function Badge({
2296
2628
  icon: IconComponent,
2297
2629
  className
2298
2630
  }) {
2299
- return /* @__PURE__ */ jsxs21(
2631
+ return /* @__PURE__ */ jsxs23(
2300
2632
  "span",
2301
2633
  {
2302
- className: twMerge8(
2634
+ className: twMerge10(
2303
2635
  "inline-flex items-center gap-1 rounded-[var(--border-radius-full)]",
2304
2636
  "text-[length:var(--font-size-xs)] font-[number:var(--font-weight-medium)] leading-[var(--line-height-tight)]",
2305
2637
  variantStyles4[variant],
@@ -2307,7 +2639,7 @@ function Badge({
2307
2639
  className
2308
2640
  ),
2309
2641
  children: [
2310
- IconComponent && /* @__PURE__ */ jsx31(IconComponent, { size: iconSizeMap4[size], "aria-hidden": "true" }),
2642
+ IconComponent && /* @__PURE__ */ jsx34(IconComponent, { size: iconSizeMap4[size], "aria-hidden": "true" }),
2311
2643
  children
2312
2644
  ]
2313
2645
  }
@@ -2315,8 +2647,9 @@ function Badge({
2315
2647
  }
2316
2648
 
2317
2649
  // src/components/Card/Card.tsx
2318
- import { twMerge as twMerge9 } from "tailwind-merge";
2319
- import { Fragment as Fragment9, jsx as jsx32, jsxs as jsxs22 } from "react/jsx-runtime";
2650
+ import { useCallback as useCallback5 } from "react";
2651
+ import { twMerge as twMerge11 } from "tailwind-merge";
2652
+ import { Fragment as Fragment10, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
2320
2653
  var paddingStyles = {
2321
2654
  none: "p-0",
2322
2655
  sm: "p-3",
@@ -2329,32 +2662,42 @@ function Card({
2329
2662
  footer,
2330
2663
  padding = "md",
2331
2664
  href,
2665
+ onPress,
2332
2666
  interactive = false,
2333
2667
  className
2334
2668
  }) {
2335
- const isInteractive = interactive || !!href;
2336
- const containerClass = twMerge9(
2669
+ const isInteractive = interactive || !!href || !!onPress;
2670
+ const containerClass = twMerge11(
2337
2671
  "bg-[var(--color-surface-default)] border border-[var(--color-border-default)] rounded-[var(--border-radius-lg)] overflow-hidden shadow-sm",
2338
- isInteractive && "transition-shadow hover:shadow-md hover:border-[var(--color-border-focus)] cursor-pointer",
2339
- href && "block focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)] focus-visible:ring-offset-2 outline-none",
2672
+ isInteractive && "transition-all hover:shadow-md hover:border-[var(--color-border-focus)] cursor-pointer",
2673
+ (href || onPress) && "block focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)] focus-visible:ring-offset-2 outline-none",
2340
2674
  className
2341
2675
  );
2342
- const content = /* @__PURE__ */ jsxs22(Fragment9, { children: [
2343
- header && /* @__PURE__ */ jsx32(
2676
+ const handleKeyDown = useCallback5(
2677
+ (e) => {
2678
+ if (onPress && (e.key === "Enter" || e.key === " ")) {
2679
+ e.preventDefault();
2680
+ onPress();
2681
+ }
2682
+ },
2683
+ [onPress]
2684
+ );
2685
+ const content = /* @__PURE__ */ jsxs24(Fragment10, { children: [
2686
+ header && /* @__PURE__ */ jsx35(
2344
2687
  "div",
2345
2688
  {
2346
- className: twMerge9(
2689
+ className: twMerge11(
2347
2690
  "border-b border-[var(--color-border-default)]",
2348
2691
  paddingStyles[padding]
2349
2692
  ),
2350
2693
  children: header
2351
2694
  }
2352
2695
  ),
2353
- /* @__PURE__ */ jsx32("div", { className: paddingStyles[padding], children }),
2354
- footer && /* @__PURE__ */ jsx32(
2696
+ /* @__PURE__ */ jsx35("div", { className: paddingStyles[padding], children }),
2697
+ footer && /* @__PURE__ */ jsx35(
2355
2698
  "div",
2356
2699
  {
2357
- className: twMerge9(
2700
+ className: twMerge11(
2358
2701
  "border-t border-[var(--color-border-default)]",
2359
2702
  paddingStyles[padding]
2360
2703
  ),
@@ -2363,15 +2706,28 @@ function Card({
2363
2706
  )
2364
2707
  ] });
2365
2708
  if (href) {
2366
- return /* @__PURE__ */ jsx32("a", { href, className: containerClass, children: content });
2709
+ return /* @__PURE__ */ jsx35("a", { href, className: containerClass, children: content });
2367
2710
  }
2368
- return /* @__PURE__ */ jsx32("div", { className: containerClass, children: content });
2711
+ if (onPress) {
2712
+ return /* @__PURE__ */ jsx35(
2713
+ "div",
2714
+ {
2715
+ role: "button",
2716
+ tabIndex: 0,
2717
+ className: containerClass,
2718
+ onClick: onPress,
2719
+ onKeyDown: handleKeyDown,
2720
+ children: content
2721
+ }
2722
+ );
2723
+ }
2724
+ return /* @__PURE__ */ jsx35("div", { className: containerClass, children: content });
2369
2725
  }
2370
2726
 
2371
2727
  // src/components/DeltaIndicator/DeltaIndicator.tsx
2372
2728
  import { ArrowUp, ArrowDown, Minus } from "lucide-react";
2373
- import { twMerge as twMerge10 } from "tailwind-merge";
2374
- import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
2729
+ import { twMerge as twMerge12 } from "tailwind-merge";
2730
+ import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
2375
2731
  function getDirection(current, previous) {
2376
2732
  const diff = current - previous;
2377
2733
  if (diff > 0) return "increase";
@@ -2424,16 +2780,16 @@ function DeltaIndicator({
2424
2780
  className
2425
2781
  }) {
2426
2782
  if (unavailable) {
2427
- return /* @__PURE__ */ jsxs23(
2783
+ return /* @__PURE__ */ jsxs25(
2428
2784
  "span",
2429
2785
  {
2430
- className: twMerge10(
2786
+ className: twMerge12(
2431
2787
  "inline-flex items-center gap-1 font-[number:var(--font-weight-medium)]",
2432
2788
  "text-[var(--color-text-tertiary)]",
2433
2789
  className
2434
2790
  ),
2435
2791
  children: [
2436
- label && /* @__PURE__ */ jsx33("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2792
+ label && /* @__PURE__ */ jsx36("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2437
2793
  unavailableText
2438
2794
  ]
2439
2795
  }
@@ -2441,7 +2797,7 @@ function DeltaIndicator({
2441
2797
  }
2442
2798
  const diff = current - previous;
2443
2799
  const direction = getDirection(current, previous);
2444
- const colorStyles = reverseColor ? reverseDirectionColors[direction] : directionColors[direction];
2800
+ const colorStyles2 = reverseColor ? reverseDirectionColors[direction] : directionColors[direction];
2445
2801
  const IconComponent = directionIcons[direction];
2446
2802
  const isNew = previous === 0 && current > 0;
2447
2803
  let valueText;
@@ -2463,12 +2819,12 @@ function DeltaIndicator({
2463
2819
  }
2464
2820
  }
2465
2821
  const isPill = mode === "pill";
2466
- return /* @__PURE__ */ jsxs23(
2822
+ return /* @__PURE__ */ jsxs25(
2467
2823
  "span",
2468
2824
  {
2469
- className: twMerge10(
2825
+ className: twMerge12(
2470
2826
  "inline-flex items-center gap-1 font-[number:var(--font-weight-medium)]",
2471
- colorStyles,
2827
+ colorStyles2,
2472
2828
  isPill && [
2473
2829
  "rounded-[var(--border-radius-full)] px-2 py-0.5",
2474
2830
  "text-[length:var(--font-size-xs)]",
@@ -2477,8 +2833,8 @@ function DeltaIndicator({
2477
2833
  className
2478
2834
  ),
2479
2835
  children: [
2480
- label && /* @__PURE__ */ jsx33("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2481
- /* @__PURE__ */ jsx33(IconComponent, { size: 14, "aria-hidden": true }),
2836
+ label && /* @__PURE__ */ jsx36("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2837
+ /* @__PURE__ */ jsx36(IconComponent, { size: 14, "aria-hidden": true }),
2482
2838
  valueText
2483
2839
  ]
2484
2840
  }
@@ -2486,8 +2842,8 @@ function DeltaIndicator({
2486
2842
  }
2487
2843
 
2488
2844
  // src/components/ProgressBar/ProgressBar.tsx
2489
- import { twMerge as twMerge11 } from "tailwind-merge";
2490
- import { jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
2845
+ import { twMerge as twMerge13 } from "tailwind-merge";
2846
+ import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2491
2847
  var fillStyles = {
2492
2848
  brand: "bg-[var(--color-progress-fill)]",
2493
2849
  success: "bg-[var(--color-progress-fill-success)]",
@@ -2510,12 +2866,12 @@ function ProgressBar({
2510
2866
  className
2511
2867
  }) {
2512
2868
  const clampedValue = Math.min(100, Math.max(0, value));
2513
- return /* @__PURE__ */ jsxs24("div", { className: twMerge11("w-full", className), children: [
2514
- (label || description || showValue) && /* @__PURE__ */ jsxs24("div", { className: "flex items-center justify-between mb-2", children: [
2515
- /* @__PURE__ */ jsx34("span", { className: "text-[length:var(--font-size-sm)] font-[number:var(--font-weight-medium)] text-[var(--color-text-primary)]", children: label }),
2516
- /* @__PURE__ */ jsx34("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)]", children: description ?? (showValue ? `${clampedValue}%` : null) })
2869
+ return /* @__PURE__ */ jsxs26("div", { className: twMerge13("w-full", className), children: [
2870
+ (label || description || showValue) && /* @__PURE__ */ jsxs26("div", { className: "flex items-center justify-between mb-2", children: [
2871
+ /* @__PURE__ */ jsx37("span", { className: "text-[length:var(--font-size-sm)] font-[number:var(--font-weight-medium)] text-[var(--color-text-primary)]", children: label }),
2872
+ /* @__PURE__ */ jsx37("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)]", children: description ?? (showValue ? `${clampedValue}%` : null) })
2517
2873
  ] }),
2518
- /* @__PURE__ */ jsx34(
2874
+ /* @__PURE__ */ jsx37(
2519
2875
  "div",
2520
2876
  {
2521
2877
  role: "progressbar",
@@ -2523,14 +2879,14 @@ function ProgressBar({
2523
2879
  "aria-valuemin": 0,
2524
2880
  "aria-valuemax": 100,
2525
2881
  "aria-label": label ?? "Progress",
2526
- className: twMerge11(
2882
+ className: twMerge13(
2527
2883
  "w-full rounded-[var(--border-radius-full)] bg-[var(--color-progress-track)]",
2528
2884
  sizeStyles8[size]
2529
2885
  ),
2530
- children: /* @__PURE__ */ jsx34(
2886
+ children: /* @__PURE__ */ jsx37(
2531
2887
  "div",
2532
2888
  {
2533
- className: twMerge11(
2889
+ className: twMerge13(
2534
2890
  "h-full rounded-[var(--border-radius-full)] transition-all duration-300",
2535
2891
  fillStyles[variant]
2536
2892
  ),
@@ -2545,17 +2901,17 @@ function ProgressBar({
2545
2901
  // src/components/Banner/Banner.tsx
2546
2902
  import { useState as useState3 } from "react";
2547
2903
  import {
2548
- Info as Info3,
2904
+ Info as Info4,
2549
2905
  AlertTriangle,
2550
2906
  AlertCircle as AlertCircle2,
2551
2907
  CheckCircle2,
2552
2908
  X as X3
2553
2909
  } from "lucide-react";
2554
- import { twMerge as twMerge12 } from "tailwind-merge";
2555
- import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
2910
+ import { twMerge as twMerge14 } from "tailwind-merge";
2911
+ import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
2556
2912
  var variantConfig2 = {
2557
2913
  info: {
2558
- icon: Info3,
2914
+ icon: Info4,
2559
2915
  containerClass: "bg-[var(--color-banner-info-bg)] border-[var(--color-banner-info-border)] text-[var(--color-banner-info-text)]",
2560
2916
  iconClass: "text-[var(--color-banner-info-icon)]",
2561
2917
  role: "status"
@@ -2596,40 +2952,40 @@ function Banner({
2596
2952
  setDismissed(true);
2597
2953
  onDismiss?.();
2598
2954
  };
2599
- return /* @__PURE__ */ jsxs25(
2955
+ return /* @__PURE__ */ jsxs27(
2600
2956
  "div",
2601
2957
  {
2602
2958
  role: config.role,
2603
- className: twMerge12(
2959
+ className: twMerge14(
2604
2960
  "flex items-start gap-[var(--spacing-3)] rounded-[var(--border-radius-lg)] border px-[var(--spacing-4)] py-[var(--spacing-3)]",
2605
2961
  "text-[length:var(--font-size-sm)]",
2606
2962
  config.containerClass,
2607
2963
  className
2608
2964
  ),
2609
2965
  children: [
2610
- /* @__PURE__ */ jsx35(
2966
+ /* @__PURE__ */ jsx38(
2611
2967
  IconComponent,
2612
2968
  {
2613
2969
  size: 20,
2614
- className: twMerge12("shrink-0 mt-0.5", config.iconClass),
2970
+ className: twMerge14("shrink-0 mt-0.5", config.iconClass),
2615
2971
  "aria-hidden": "true"
2616
2972
  }
2617
2973
  ),
2618
- /* @__PURE__ */ jsxs25("div", { className: "flex-1", children: [
2619
- title && /* @__PURE__ */ jsxs25("span", { className: "font-[number:var(--font-weight-medium)]", children: [
2974
+ /* @__PURE__ */ jsxs27("div", { className: "flex-1", children: [
2975
+ title && /* @__PURE__ */ jsxs27("span", { className: "font-[number:var(--font-weight-medium)]", children: [
2620
2976
  title,
2621
2977
  " \u2014 "
2622
2978
  ] }),
2623
2979
  children
2624
2980
  ] }),
2625
- dismissible && /* @__PURE__ */ jsx35(
2981
+ dismissible && /* @__PURE__ */ jsx38(
2626
2982
  "button",
2627
2983
  {
2628
2984
  type: "button",
2629
2985
  onClick: handleDismiss,
2630
2986
  className: "shrink-0 rounded-[var(--border-radius-sm)] p-0.5 opacity-70 hover:opacity-100 transition-opacity outline-none focus-visible:ring-2 focus-visible:ring-current",
2631
2987
  "aria-label": "Dismiss",
2632
- children: /* @__PURE__ */ jsx35(X3, { size: 16, "aria-hidden": "true" })
2988
+ children: /* @__PURE__ */ jsx38(X3, { size: 16, "aria-hidden": "true" })
2633
2989
  }
2634
2990
  )
2635
2991
  ]
@@ -2638,8 +2994,8 @@ function Banner({
2638
2994
  }
2639
2995
 
2640
2996
  // src/components/MetricCard/MetricCard.tsx
2641
- import { twMerge as twMerge13 } from "tailwind-merge";
2642
- import { Fragment as Fragment10, jsx as jsx36, jsxs as jsxs26 } from "react/jsx-runtime";
2997
+ import { twMerge as twMerge15 } from "tailwind-merge";
2998
+ import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
2643
2999
  var sizeConfig = {
2644
3000
  sm: {
2645
3001
  padding: "p-3",
@@ -2661,30 +3017,209 @@ function MetricCard({
2661
3017
  className
2662
3018
  }) {
2663
3019
  const config = sizeConfig[size];
2664
- const containerClass = twMerge13(
3020
+ const containerClass = twMerge15(
2665
3021
  "bg-[var(--color-surface-default)] border border-[var(--color-border-default)] rounded-[var(--border-radius-lg)] shadow-sm",
2666
3022
  config.padding,
2667
3023
  href && "block transition-shadow hover:shadow-md hover:border-[var(--color-border-focus)] focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)] focus-visible:ring-offset-2 outline-none",
2668
3024
  className
2669
3025
  );
2670
- const content = /* @__PURE__ */ jsxs26(Fragment10, { children: [
2671
- /* @__PURE__ */ jsx36("div", { className: twMerge13(config.labelClass, "text-[var(--color-text-secondary)]"), children: label }),
2672
- /* @__PURE__ */ jsx36(
3026
+ const content = /* @__PURE__ */ jsxs28(Fragment11, { children: [
3027
+ /* @__PURE__ */ jsx39("div", { className: twMerge15(config.labelClass, "text-[var(--color-text-secondary)]"), children: label }),
3028
+ /* @__PURE__ */ jsx39(
2673
3029
  "div",
2674
3030
  {
2675
- className: twMerge13(
3031
+ className: twMerge15(
2676
3032
  config.valueClass,
2677
3033
  "font-[number:var(--font-weight-semibold)] text-[var(--color-text-primary)] mt-1 tabular-nums"
2678
3034
  ),
2679
3035
  children: value
2680
3036
  }
2681
3037
  ),
2682
- secondary && /* @__PURE__ */ jsx36("div", { className: "mt-1 text-sm", children: secondary })
3038
+ secondary && /* @__PURE__ */ jsx39("div", { className: "mt-1 text-sm", children: secondary })
2683
3039
  ] });
2684
3040
  if (href) {
2685
- return /* @__PURE__ */ jsx36("a", { href, className: containerClass, children: content });
3041
+ return /* @__PURE__ */ jsx39("a", { href, className: containerClass, children: content });
2686
3042
  }
2687
- return /* @__PURE__ */ jsx36("div", { className: containerClass, children: content });
3043
+ return /* @__PURE__ */ jsx39("div", { className: containerClass, children: content });
3044
+ }
3045
+
3046
+ // src/components/SectionHeader/SectionHeader.tsx
3047
+ import { twMerge as twMerge16 } from "tailwind-merge";
3048
+ import { jsx as jsx40, jsxs as jsxs29 } from "react/jsx-runtime";
3049
+ function SectionHeader({
3050
+ title,
3051
+ children,
3052
+ className
3053
+ }) {
3054
+ return /* @__PURE__ */ jsxs29(
3055
+ "div",
3056
+ {
3057
+ className: twMerge16(
3058
+ "flex flex-wrap items-center gap-[var(--spacing-3)] py-[var(--spacing-4)]",
3059
+ className
3060
+ ),
3061
+ children: [
3062
+ /* @__PURE__ */ jsx40(H2, { children: title }),
3063
+ children && /* @__PURE__ */ jsx40("div", { className: "ml-auto flex flex-wrap items-center gap-[var(--spacing-2)]", children })
3064
+ ]
3065
+ }
3066
+ );
3067
+ }
3068
+
3069
+ // src/components/FormWizard/FormWizard.tsx
3070
+ import { createContext as createContext5, useContext as useContext5, useCallback as useCallback6, useMemo } from "react";
3071
+ import { jsx as jsx41 } from "react/jsx-runtime";
3072
+ var FormWizardContext = createContext5({
3073
+ currentStep: 0,
3074
+ totalSteps: 1,
3075
+ canGoBack: false,
3076
+ goBack: () => {
3077
+ },
3078
+ isLastStep: true
3079
+ });
3080
+ function useFormWizard() {
3081
+ return useContext5(FormWizardContext);
3082
+ }
3083
+ function FormWizard({
3084
+ currentStep,
3085
+ totalSteps,
3086
+ onStepChange,
3087
+ children
3088
+ }) {
3089
+ const canGoBack = currentStep > 0;
3090
+ const isLastStep = currentStep >= totalSteps - 1;
3091
+ const goBack = useCallback6(() => {
3092
+ if (currentStep > 0) {
3093
+ onStepChange(currentStep - 1);
3094
+ }
3095
+ }, [currentStep, onStepChange]);
3096
+ const value = useMemo(
3097
+ () => ({
3098
+ currentStep,
3099
+ totalSteps,
3100
+ canGoBack,
3101
+ goBack,
3102
+ isLastStep
3103
+ }),
3104
+ [currentStep, totalSteps, canGoBack, goBack, isLastStep]
3105
+ );
3106
+ return /* @__PURE__ */ jsx41(FormWizardContext.Provider, { value, children });
3107
+ }
3108
+
3109
+ // src/components/FormWizard/FormWizardProgress.tsx
3110
+ import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
3111
+ function CheckIcon2() {
3112
+ return /* @__PURE__ */ jsx42(
3113
+ "svg",
3114
+ {
3115
+ "aria-hidden": "true",
3116
+ className: "h-4 w-4 text-[var(--color-text-inverse)]",
3117
+ viewBox: "0 0 16 16",
3118
+ fill: "none",
3119
+ stroke: "currentColor",
3120
+ strokeWidth: "2",
3121
+ strokeLinecap: "round",
3122
+ strokeLinejoin: "round",
3123
+ children: /* @__PURE__ */ jsx42("path", { d: "M3 8.5l3.5 3.5 6.5-7" })
3124
+ }
3125
+ );
3126
+ }
3127
+ function FormWizardProgress({ labels }) {
3128
+ const { currentStep, totalSteps } = useFormWizard();
3129
+ return /* @__PURE__ */ jsx42("nav", { "aria-label": "Form progress", children: /* @__PURE__ */ jsx42("ol", { className: "flex items-start", role: "list", children: labels.map((label, index) => {
3130
+ const isCompleted = index < currentStep;
3131
+ const isCurrent = index === currentStep;
3132
+ const isFuture = index > currentStep;
3133
+ return /* @__PURE__ */ jsxs30(
3134
+ "li",
3135
+ {
3136
+ className: "flex flex-1 flex-col items-center",
3137
+ "aria-current": isCurrent ? "step" : void 0,
3138
+ children: [
3139
+ /* @__PURE__ */ jsxs30("div", { className: "flex w-full items-center", children: [
3140
+ index > 0 ? /* @__PURE__ */ jsx42(
3141
+ "div",
3142
+ {
3143
+ "aria-hidden": "true",
3144
+ className: [
3145
+ "h-0.5 flex-1",
3146
+ index <= currentStep ? "bg-[var(--color-brand-primary)]" : "bg-[var(--color-border-default)]"
3147
+ ].join(" ")
3148
+ }
3149
+ ) : /* @__PURE__ */ jsx42("div", { className: "flex-1", "aria-hidden": "true" }),
3150
+ /* @__PURE__ */ jsx42(
3151
+ "div",
3152
+ {
3153
+ className: [
3154
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-full",
3155
+ "text-[length:var(--font-size-sm)] font-[number:var(--font-weight-medium)]",
3156
+ "transition-colors",
3157
+ isCompleted ? "bg-[var(--color-brand-primary)] text-[var(--color-text-inverse)]" : "",
3158
+ isCurrent ? "border-2 border-[var(--color-brand-primary)] bg-[var(--color-surface-default)] text-[var(--color-brand-primary)]" : "",
3159
+ isFuture ? "border-2 border-[var(--color-border-default)] bg-[var(--color-surface-default)] text-[var(--color-text-tertiary)]" : ""
3160
+ ].join(" "),
3161
+ "aria-hidden": "true",
3162
+ children: isCompleted ? /* @__PURE__ */ jsx42(CheckIcon2, {}) : index + 1
3163
+ }
3164
+ ),
3165
+ index < totalSteps - 1 ? /* @__PURE__ */ jsx42(
3166
+ "div",
3167
+ {
3168
+ "aria-hidden": "true",
3169
+ className: [
3170
+ "h-0.5 flex-1",
3171
+ index < currentStep ? "bg-[var(--color-brand-primary)]" : "bg-[var(--color-border-default)]"
3172
+ ].join(" ")
3173
+ }
3174
+ ) : /* @__PURE__ */ jsx42("div", { className: "flex-1", "aria-hidden": "true" })
3175
+ ] }),
3176
+ /* @__PURE__ */ jsx42(
3177
+ "span",
3178
+ {
3179
+ className: [
3180
+ "mt-[var(--spacing-2)] text-center text-[length:var(--font-size-sm)]",
3181
+ isCurrent ? "font-[number:var(--font-weight-semibold)] text-[var(--color-text-primary)]" : "font-[number:var(--font-weight-regular)] text-[var(--color-text-secondary)]"
3182
+ ].join(" "),
3183
+ children: label
3184
+ }
3185
+ )
3186
+ ]
3187
+ },
3188
+ label
3189
+ );
3190
+ }) }) });
3191
+ }
3192
+
3193
+ // src/components/FormWizard/FormWizardNav.tsx
3194
+ import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
3195
+ function FormWizardNav({
3196
+ onNext,
3197
+ isSubmitting = false,
3198
+ submitLabel = "Submit"
3199
+ }) {
3200
+ const { canGoBack, goBack, isLastStep } = useFormWizard();
3201
+ return /* @__PURE__ */ jsxs31("div", { className: "flex items-center justify-end gap-[var(--spacing-3)]", children: [
3202
+ canGoBack && /* @__PURE__ */ jsx43(
3203
+ Button,
3204
+ {
3205
+ variant: "secondary",
3206
+ size: "lg",
3207
+ onPress: goBack,
3208
+ isDisabled: isSubmitting,
3209
+ children: "Back"
3210
+ }
3211
+ ),
3212
+ /* @__PURE__ */ jsx43(
3213
+ Button,
3214
+ {
3215
+ variant: "primary",
3216
+ size: "lg",
3217
+ onPress: onNext,
3218
+ isLoading: isSubmitting,
3219
+ children: isLastStep ? submitLabel : "Next"
3220
+ }
3221
+ )
3222
+ ] });
2688
3223
  }
2689
3224
 
2690
3225
  // src/tokens/tokens.ts
@@ -3081,6 +3616,8 @@ export {
3081
3616
  EmptyState,
3082
3617
  Field,
3083
3618
  Fieldset,
3619
+ FileCard,
3620
+ FileIcon,
3084
3621
  FontSize2xl,
3085
3622
  FontSize3xl,
3086
3623
  FontSize4xl,
@@ -3096,6 +3633,10 @@ export {
3096
3633
  FontWeightMedium,
3097
3634
  FontWeightRegular,
3098
3635
  FontWeightSemibold,
3636
+ FormWizard,
3637
+ FormWizardNav,
3638
+ FormWizardProgress,
3639
+ GroupPill,
3099
3640
  H1,
3100
3641
  H2,
3101
3642
  H3,
@@ -3114,6 +3655,7 @@ export {
3114
3655
  Link,
3115
3656
  Menu,
3116
3657
  MetricCard,
3658
+ Pill,
3117
3659
  Popover3 as Popover,
3118
3660
  PopoverContent,
3119
3661
  PopoverTrigger,
@@ -3123,6 +3665,7 @@ export {
3123
3665
  RadioGroup,
3124
3666
  RouterProvider,
3125
3667
  Row,
3668
+ SectionHeader,
3126
3669
  SegmentedControl,
3127
3670
  SegmentedControlItem,
3128
3671
  Select,
@@ -3153,6 +3696,10 @@ export {
3153
3696
  TabPanel2 as UnstyledTabPanel,
3154
3697
  Tabs2 as UnstyledTabs,
3155
3698
  createToastBridge,
3699
+ getFileIcon,
3700
+ getTypeLabel,
3701
+ pillColorFromName,
3702
+ useFormWizard,
3156
3703
  useInputGroup,
3157
3704
  useToast
3158
3705
  };