@cytario/design 1.14.0 → 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,13 +2143,194 @@ 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";
2146
2329
  import { twMerge as twMerge9 } from "tailwind-merge";
2147
2330
 
2148
2331
  // src/components/Pill/Pill.tsx
2149
2332
  import { twMerge as twMerge7 } from "tailwind-merge";
2150
- import { jsx as jsx30 } from "react/jsx-runtime";
2333
+ import { jsx as jsx31 } from "react/jsx-runtime";
2151
2334
  var HASH_PALETTE = [
2152
2335
  "teal",
2153
2336
  // sky
@@ -2198,7 +2381,7 @@ function resolveColor(color, name) {
2198
2381
  }
2199
2382
  function Pill({ children, color, name, className }) {
2200
2383
  const resolved = resolveColor(color, name);
2201
- return /* @__PURE__ */ jsx30(
2384
+ return /* @__PURE__ */ jsx31(
2202
2385
  "span",
2203
2386
  {
2204
2387
  className: twMerge7(
@@ -2215,7 +2398,7 @@ function Pill({ children, color, name, className }) {
2215
2398
 
2216
2399
  // src/components/Pill/GroupPill.tsx
2217
2400
  import { twMerge as twMerge8 } from "tailwind-merge";
2218
- import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
2401
+ import { jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
2219
2402
  function GroupPill({
2220
2403
  path,
2221
2404
  visibleCount = 3,
@@ -2226,7 +2409,7 @@ function GroupPill({
2226
2409
  const hiddenCount = Math.max(0, segments.length - visibleCount);
2227
2410
  const hiddenSegments = segments.slice(0, hiddenCount);
2228
2411
  const visibleSegments = segments.slice(hiddenCount);
2229
- return /* @__PURE__ */ jsxs20(
2412
+ return /* @__PURE__ */ jsxs21(
2230
2413
  "span",
2231
2414
  {
2232
2415
  className: twMerge8(
@@ -2237,7 +2420,7 @@ function GroupPill({
2237
2420
  children: [
2238
2421
  hiddenSegments.map((segment, index) => {
2239
2422
  const color = pillColorFromName(segment);
2240
- return /* @__PURE__ */ jsx31(
2423
+ return /* @__PURE__ */ jsx32(
2241
2424
  "span",
2242
2425
  {
2243
2426
  className: twMerge8(
@@ -2250,14 +2433,14 @@ function GroupPill({
2250
2433
  `dot-${index}-${segment}`
2251
2434
  );
2252
2435
  }),
2253
- visibleSegments.map((segment, index) => /* @__PURE__ */ jsx31(Pill, { name: segment, children: segment }, `pill-${index}-${segment}`))
2436
+ visibleSegments.map((segment, index) => /* @__PURE__ */ jsx32(Pill, { name: segment, children: segment }, `pill-${index}-${segment}`))
2254
2437
  ]
2255
2438
  }
2256
2439
  );
2257
2440
  }
2258
2441
 
2259
2442
  // src/components/StorageConnectionCard/StorageConnectionCard.tsx
2260
- import { Fragment as Fragment8, jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
2443
+ import { Fragment as Fragment9, jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
2261
2444
  var statusDotStyles = {
2262
2445
  connected: "bg-[var(--color-status-success)]",
2263
2446
  error: "border-2 border-[var(--color-status-danger)] bg-transparent",
@@ -2273,7 +2456,7 @@ function ProviderBadge({ provider }) {
2273
2456
  const config = providerConfig[provider.toLowerCase()];
2274
2457
  const label = config?.label ?? provider;
2275
2458
  const color = config?.color ?? "neutral";
2276
- return /* @__PURE__ */ jsx32(Pill, { color, children: label });
2459
+ return /* @__PURE__ */ jsx33(Pill, { color, children: label });
2277
2460
  }
2278
2461
  function PreviewArea({
2279
2462
  status = "connected",
@@ -2281,11 +2464,11 @@ function PreviewArea({
2281
2464
  children
2282
2465
  }) {
2283
2466
  if (status === "loading") {
2284
- return /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32(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" }) });
2285
2468
  }
2286
2469
  if (status === "error") {
2287
- return /* @__PURE__ */ jsxs21("div", { className: "flex h-full flex-col items-center justify-center gap-2 bg-[var(--color-surface-danger)] px-4", children: [
2288
- /* @__PURE__ */ jsx32(
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(
2289
2472
  Icon,
2290
2473
  {
2291
2474
  icon: AlertCircle,
@@ -2293,13 +2476,13 @@ function PreviewArea({
2293
2476
  className: "text-[var(--color-text-danger)]"
2294
2477
  }
2295
2478
  ),
2296
- errorMessage && /* @__PURE__ */ jsx32("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 })
2297
2480
  ] });
2298
2481
  }
2299
2482
  if (children) {
2300
- return /* @__PURE__ */ jsx32("div", { className: "h-full w-full overflow-hidden", children });
2483
+ return /* @__PURE__ */ jsx33("div", { className: "h-full w-full overflow-hidden", children });
2301
2484
  }
2302
- return /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32(
2485
+ return /* @__PURE__ */ jsx33("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx33(
2303
2486
  Icon,
2304
2487
  {
2305
2488
  icon: Database,
@@ -2317,14 +2500,35 @@ function StorageConnectionCard({
2317
2500
  imageCount,
2318
2501
  children,
2319
2502
  href,
2503
+ onPress,
2320
2504
  onInfo,
2321
2505
  className
2322
2506
  }) {
2323
- const cardContent = /* @__PURE__ */ jsxs21(Fragment8, { children: [
2324
- /* @__PURE__ */ jsx32("div", { className: "aspect-[4/3] bg-[var(--color-neutral-900)] overflow-hidden rounded-t-[var(--border-radius-lg)]", children: /* @__PURE__ */ jsx32(PreviewArea, { status, errorMessage, children }) }),
2325
- /* @__PURE__ */ jsxs21("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: [
2326
- /* @__PURE__ */ jsxs21("div", { className: "flex items-start gap-2", children: [
2327
- status && /* @__PURE__ */ jsx32(
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(
2328
2532
  "span",
2329
2533
  {
2330
2534
  className: twMerge9(
@@ -2334,25 +2538,35 @@ function StorageConnectionCard({
2334
2538
  "aria-label": `Status: ${status}`
2335
2539
  }
2336
2540
  ),
2337
- /* @__PURE__ */ jsx32("span", { className: "min-w-0 flex-1 line-clamp-2 text-sm font-medium text-[var(--color-text-primary)]", children: name }),
2338
- onInfo && /* @__PURE__ */ jsx32(
2339
- 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",
2340
2544
  {
2341
- icon: Info2,
2342
- "aria-label": "Connection info",
2343
- variant: "ghost",
2344
- size: "sm",
2345
- className: "shrink-0 -mt-1 -mr-1",
2346
- onPress: () => {
2347
- onInfo();
2348
- }
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
+ )
2349
2563
  }
2350
2564
  )
2351
2565
  ] }),
2352
- (provider || imageCount != null && (!status || status === "connected")) && /* @__PURE__ */ jsxs21("div", { className: twMerge9("flex items-center gap-2", status && "pl-4"), children: [
2353
- provider && /* @__PURE__ */ jsx32(ProviderBadge, { provider }),
2354
- provider && region && /* @__PURE__ */ jsx32("span", { className: "shrink-0 text-xs text-[var(--color-text-secondary)]", children: region }),
2355
- imageCount != null && (!status || status === "connected") && /* @__PURE__ */ jsxs21("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: [
2356
2570
  imageCount,
2357
2571
  " ",
2358
2572
  imageCount === 1 ? "image" : "images"
@@ -2364,18 +2578,32 @@ function StorageConnectionCard({
2364
2578
  "flex flex-col overflow-hidden rounded-[var(--border-radius-lg)]",
2365
2579
  "border border-[var(--color-border-default)]",
2366
2580
  "shadow-sm transition-all",
2367
- 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",
2368
2583
  className
2369
2584
  );
2370
2585
  if (href) {
2371
- return /* @__PURE__ */ jsx32("a", { href, className: twMerge9(baseStyles, "no-underline"), children: cardContent });
2586
+ return /* @__PURE__ */ jsx33("a", { href, className: twMerge9(baseStyles, "no-underline"), children: cardContent });
2587
+ }
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
+ );
2372
2600
  }
2373
- return /* @__PURE__ */ jsx32("div", { className: baseStyles, children: cardContent });
2601
+ return /* @__PURE__ */ jsx33("div", { className: baseStyles, children: cardContent });
2374
2602
  }
2375
2603
 
2376
2604
  // src/components/Badge/Badge.tsx
2377
2605
  import { twMerge as twMerge10 } from "tailwind-merge";
2378
- import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
2606
+ import { jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
2379
2607
  var variantStyles4 = {
2380
2608
  neutral: "bg-[var(--color-badge-neutral-bg)] text-[var(--color-badge-neutral-text)]",
2381
2609
  purple: "bg-[var(--color-badge-purple-bg)] text-[var(--color-badge-purple-text)]",
@@ -2400,7 +2628,7 @@ function Badge({
2400
2628
  icon: IconComponent,
2401
2629
  className
2402
2630
  }) {
2403
- return /* @__PURE__ */ jsxs22(
2631
+ return /* @__PURE__ */ jsxs23(
2404
2632
  "span",
2405
2633
  {
2406
2634
  className: twMerge10(
@@ -2411,7 +2639,7 @@ function Badge({
2411
2639
  className
2412
2640
  ),
2413
2641
  children: [
2414
- IconComponent && /* @__PURE__ */ jsx33(IconComponent, { size: iconSizeMap4[size], "aria-hidden": "true" }),
2642
+ IconComponent && /* @__PURE__ */ jsx34(IconComponent, { size: iconSizeMap4[size], "aria-hidden": "true" }),
2415
2643
  children
2416
2644
  ]
2417
2645
  }
@@ -2419,8 +2647,9 @@ function Badge({
2419
2647
  }
2420
2648
 
2421
2649
  // src/components/Card/Card.tsx
2650
+ import { useCallback as useCallback5 } from "react";
2422
2651
  import { twMerge as twMerge11 } from "tailwind-merge";
2423
- import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
2652
+ import { Fragment as Fragment10, jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
2424
2653
  var paddingStyles = {
2425
2654
  none: "p-0",
2426
2655
  sm: "p-3",
@@ -2433,18 +2662,28 @@ function Card({
2433
2662
  footer,
2434
2663
  padding = "md",
2435
2664
  href,
2665
+ onPress,
2436
2666
  interactive = false,
2437
2667
  className
2438
2668
  }) {
2439
- const isInteractive = interactive || !!href;
2669
+ const isInteractive = interactive || !!href || !!onPress;
2440
2670
  const containerClass = twMerge11(
2441
2671
  "bg-[var(--color-surface-default)] border border-[var(--color-border-default)] rounded-[var(--border-radius-lg)] overflow-hidden shadow-sm",
2442
- isInteractive && "transition-shadow hover:shadow-md hover:border-[var(--color-border-focus)] cursor-pointer",
2443
- 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",
2444
2674
  className
2445
2675
  );
2446
- const content = /* @__PURE__ */ jsxs23(Fragment9, { children: [
2447
- header && /* @__PURE__ */ jsx34(
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(
2448
2687
  "div",
2449
2688
  {
2450
2689
  className: twMerge11(
@@ -2454,8 +2693,8 @@ function Card({
2454
2693
  children: header
2455
2694
  }
2456
2695
  ),
2457
- /* @__PURE__ */ jsx34("div", { className: paddingStyles[padding], children }),
2458
- footer && /* @__PURE__ */ jsx34(
2696
+ /* @__PURE__ */ jsx35("div", { className: paddingStyles[padding], children }),
2697
+ footer && /* @__PURE__ */ jsx35(
2459
2698
  "div",
2460
2699
  {
2461
2700
  className: twMerge11(
@@ -2467,15 +2706,28 @@ function Card({
2467
2706
  )
2468
2707
  ] });
2469
2708
  if (href) {
2470
- return /* @__PURE__ */ jsx34("a", { href, className: containerClass, children: content });
2709
+ return /* @__PURE__ */ jsx35("a", { href, className: containerClass, children: content });
2471
2710
  }
2472
- return /* @__PURE__ */ jsx34("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 });
2473
2725
  }
2474
2726
 
2475
2727
  // src/components/DeltaIndicator/DeltaIndicator.tsx
2476
2728
  import { ArrowUp, ArrowDown, Minus } from "lucide-react";
2477
2729
  import { twMerge as twMerge12 } from "tailwind-merge";
2478
- import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
2730
+ import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
2479
2731
  function getDirection(current, previous) {
2480
2732
  const diff = current - previous;
2481
2733
  if (diff > 0) return "increase";
@@ -2528,7 +2780,7 @@ function DeltaIndicator({
2528
2780
  className
2529
2781
  }) {
2530
2782
  if (unavailable) {
2531
- return /* @__PURE__ */ jsxs24(
2783
+ return /* @__PURE__ */ jsxs25(
2532
2784
  "span",
2533
2785
  {
2534
2786
  className: twMerge12(
@@ -2537,7 +2789,7 @@ function DeltaIndicator({
2537
2789
  className
2538
2790
  ),
2539
2791
  children: [
2540
- label && /* @__PURE__ */ jsx35("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 }),
2541
2793
  unavailableText
2542
2794
  ]
2543
2795
  }
@@ -2567,7 +2819,7 @@ function DeltaIndicator({
2567
2819
  }
2568
2820
  }
2569
2821
  const isPill = mode === "pill";
2570
- return /* @__PURE__ */ jsxs24(
2822
+ return /* @__PURE__ */ jsxs25(
2571
2823
  "span",
2572
2824
  {
2573
2825
  className: twMerge12(
@@ -2581,8 +2833,8 @@ function DeltaIndicator({
2581
2833
  className
2582
2834
  ),
2583
2835
  children: [
2584
- label && /* @__PURE__ */ jsx35("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2585
- /* @__PURE__ */ jsx35(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 }),
2586
2838
  valueText
2587
2839
  ]
2588
2840
  }
@@ -2591,7 +2843,7 @@ function DeltaIndicator({
2591
2843
 
2592
2844
  // src/components/ProgressBar/ProgressBar.tsx
2593
2845
  import { twMerge as twMerge13 } from "tailwind-merge";
2594
- import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
2846
+ import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2595
2847
  var fillStyles = {
2596
2848
  brand: "bg-[var(--color-progress-fill)]",
2597
2849
  success: "bg-[var(--color-progress-fill-success)]",
@@ -2614,12 +2866,12 @@ function ProgressBar({
2614
2866
  className
2615
2867
  }) {
2616
2868
  const clampedValue = Math.min(100, Math.max(0, value));
2617
- return /* @__PURE__ */ jsxs25("div", { className: twMerge13("w-full", className), children: [
2618
- (label || description || showValue) && /* @__PURE__ */ jsxs25("div", { className: "flex items-center justify-between mb-2", children: [
2619
- /* @__PURE__ */ jsx36("span", { className: "text-[length:var(--font-size-sm)] font-[number:var(--font-weight-medium)] text-[var(--color-text-primary)]", children: label }),
2620
- /* @__PURE__ */ jsx36("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) })
2621
2873
  ] }),
2622
- /* @__PURE__ */ jsx36(
2874
+ /* @__PURE__ */ jsx37(
2623
2875
  "div",
2624
2876
  {
2625
2877
  role: "progressbar",
@@ -2631,7 +2883,7 @@ function ProgressBar({
2631
2883
  "w-full rounded-[var(--border-radius-full)] bg-[var(--color-progress-track)]",
2632
2884
  sizeStyles8[size]
2633
2885
  ),
2634
- children: /* @__PURE__ */ jsx36(
2886
+ children: /* @__PURE__ */ jsx37(
2635
2887
  "div",
2636
2888
  {
2637
2889
  className: twMerge13(
@@ -2649,17 +2901,17 @@ function ProgressBar({
2649
2901
  // src/components/Banner/Banner.tsx
2650
2902
  import { useState as useState3 } from "react";
2651
2903
  import {
2652
- Info as Info3,
2904
+ Info as Info4,
2653
2905
  AlertTriangle,
2654
2906
  AlertCircle as AlertCircle2,
2655
2907
  CheckCircle2,
2656
2908
  X as X3
2657
2909
  } from "lucide-react";
2658
2910
  import { twMerge as twMerge14 } from "tailwind-merge";
2659
- import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2911
+ import { jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
2660
2912
  var variantConfig2 = {
2661
2913
  info: {
2662
- icon: Info3,
2914
+ icon: Info4,
2663
2915
  containerClass: "bg-[var(--color-banner-info-bg)] border-[var(--color-banner-info-border)] text-[var(--color-banner-info-text)]",
2664
2916
  iconClass: "text-[var(--color-banner-info-icon)]",
2665
2917
  role: "status"
@@ -2700,7 +2952,7 @@ function Banner({
2700
2952
  setDismissed(true);
2701
2953
  onDismiss?.();
2702
2954
  };
2703
- return /* @__PURE__ */ jsxs26(
2955
+ return /* @__PURE__ */ jsxs27(
2704
2956
  "div",
2705
2957
  {
2706
2958
  role: config.role,
@@ -2711,7 +2963,7 @@ function Banner({
2711
2963
  className
2712
2964
  ),
2713
2965
  children: [
2714
- /* @__PURE__ */ jsx37(
2966
+ /* @__PURE__ */ jsx38(
2715
2967
  IconComponent,
2716
2968
  {
2717
2969
  size: 20,
@@ -2719,21 +2971,21 @@ function Banner({
2719
2971
  "aria-hidden": "true"
2720
2972
  }
2721
2973
  ),
2722
- /* @__PURE__ */ jsxs26("div", { className: "flex-1", children: [
2723
- title && /* @__PURE__ */ jsxs26("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: [
2724
2976
  title,
2725
2977
  " \u2014 "
2726
2978
  ] }),
2727
2979
  children
2728
2980
  ] }),
2729
- dismissible && /* @__PURE__ */ jsx37(
2981
+ dismissible && /* @__PURE__ */ jsx38(
2730
2982
  "button",
2731
2983
  {
2732
2984
  type: "button",
2733
2985
  onClick: handleDismiss,
2734
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",
2735
2987
  "aria-label": "Dismiss",
2736
- children: /* @__PURE__ */ jsx37(X3, { size: 16, "aria-hidden": "true" })
2988
+ children: /* @__PURE__ */ jsx38(X3, { size: 16, "aria-hidden": "true" })
2737
2989
  }
2738
2990
  )
2739
2991
  ]
@@ -2743,7 +2995,7 @@ function Banner({
2743
2995
 
2744
2996
  // src/components/MetricCard/MetricCard.tsx
2745
2997
  import { twMerge as twMerge15 } from "tailwind-merge";
2746
- import { Fragment as Fragment10, jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
2998
+ import { Fragment as Fragment11, jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
2747
2999
  var sizeConfig = {
2748
3000
  sm: {
2749
3001
  padding: "p-3",
@@ -2771,9 +3023,9 @@ function MetricCard({
2771
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",
2772
3024
  className
2773
3025
  );
2774
- const content = /* @__PURE__ */ jsxs27(Fragment10, { children: [
2775
- /* @__PURE__ */ jsx38("div", { className: twMerge15(config.labelClass, "text-[var(--color-text-secondary)]"), children: label }),
2776
- /* @__PURE__ */ jsx38(
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(
2777
3029
  "div",
2778
3030
  {
2779
3031
  className: twMerge15(
@@ -2783,23 +3035,23 @@ function MetricCard({
2783
3035
  children: value
2784
3036
  }
2785
3037
  ),
2786
- secondary && /* @__PURE__ */ jsx38("div", { className: "mt-1 text-sm", children: secondary })
3038
+ secondary && /* @__PURE__ */ jsx39("div", { className: "mt-1 text-sm", children: secondary })
2787
3039
  ] });
2788
3040
  if (href) {
2789
- return /* @__PURE__ */ jsx38("a", { href, className: containerClass, children: content });
3041
+ return /* @__PURE__ */ jsx39("a", { href, className: containerClass, children: content });
2790
3042
  }
2791
- return /* @__PURE__ */ jsx38("div", { className: containerClass, children: content });
3043
+ return /* @__PURE__ */ jsx39("div", { className: containerClass, children: content });
2792
3044
  }
2793
3045
 
2794
3046
  // src/components/SectionHeader/SectionHeader.tsx
2795
3047
  import { twMerge as twMerge16 } from "tailwind-merge";
2796
- import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
3048
+ import { jsx as jsx40, jsxs as jsxs29 } from "react/jsx-runtime";
2797
3049
  function SectionHeader({
2798
3050
  title,
2799
3051
  children,
2800
3052
  className
2801
3053
  }) {
2802
- return /* @__PURE__ */ jsxs28(
3054
+ return /* @__PURE__ */ jsxs29(
2803
3055
  "div",
2804
3056
  {
2805
3057
  className: twMerge16(
@@ -2807,16 +3059,16 @@ function SectionHeader({
2807
3059
  className
2808
3060
  ),
2809
3061
  children: [
2810
- /* @__PURE__ */ jsx39(H2, { children: title }),
2811
- children && /* @__PURE__ */ jsx39("div", { className: "ml-auto flex flex-wrap items-center gap-[var(--spacing-2)]", 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 })
2812
3064
  ]
2813
3065
  }
2814
3066
  );
2815
3067
  }
2816
3068
 
2817
3069
  // src/components/FormWizard/FormWizard.tsx
2818
- import { createContext as createContext5, useContext as useContext5, useCallback as useCallback3, useMemo } from "react";
2819
- import { jsx as jsx40 } from "react/jsx-runtime";
3070
+ import { createContext as createContext5, useContext as useContext5, useCallback as useCallback6, useMemo } from "react";
3071
+ import { jsx as jsx41 } from "react/jsx-runtime";
2820
3072
  var FormWizardContext = createContext5({
2821
3073
  currentStep: 0,
2822
3074
  totalSteps: 1,
@@ -2836,7 +3088,7 @@ function FormWizard({
2836
3088
  }) {
2837
3089
  const canGoBack = currentStep > 0;
2838
3090
  const isLastStep = currentStep >= totalSteps - 1;
2839
- const goBack = useCallback3(() => {
3091
+ const goBack = useCallback6(() => {
2840
3092
  if (currentStep > 0) {
2841
3093
  onStepChange(currentStep - 1);
2842
3094
  }
@@ -2851,13 +3103,13 @@ function FormWizard({
2851
3103
  }),
2852
3104
  [currentStep, totalSteps, canGoBack, goBack, isLastStep]
2853
3105
  );
2854
- return /* @__PURE__ */ jsx40(FormWizardContext.Provider, { value, children });
3106
+ return /* @__PURE__ */ jsx41(FormWizardContext.Provider, { value, children });
2855
3107
  }
2856
3108
 
2857
3109
  // src/components/FormWizard/FormWizardProgress.tsx
2858
- import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
3110
+ import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
2859
3111
  function CheckIcon2() {
2860
- return /* @__PURE__ */ jsx41(
3112
+ return /* @__PURE__ */ jsx42(
2861
3113
  "svg",
2862
3114
  {
2863
3115
  "aria-hidden": "true",
@@ -2868,24 +3120,24 @@ function CheckIcon2() {
2868
3120
  strokeWidth: "2",
2869
3121
  strokeLinecap: "round",
2870
3122
  strokeLinejoin: "round",
2871
- children: /* @__PURE__ */ jsx41("path", { d: "M3 8.5l3.5 3.5 6.5-7" })
3123
+ children: /* @__PURE__ */ jsx42("path", { d: "M3 8.5l3.5 3.5 6.5-7" })
2872
3124
  }
2873
3125
  );
2874
3126
  }
2875
3127
  function FormWizardProgress({ labels }) {
2876
3128
  const { currentStep, totalSteps } = useFormWizard();
2877
- return /* @__PURE__ */ jsx41("nav", { "aria-label": "Form progress", children: /* @__PURE__ */ jsx41("ol", { className: "flex items-start", role: "list", children: labels.map((label, index) => {
3129
+ return /* @__PURE__ */ jsx42("nav", { "aria-label": "Form progress", children: /* @__PURE__ */ jsx42("ol", { className: "flex items-start", role: "list", children: labels.map((label, index) => {
2878
3130
  const isCompleted = index < currentStep;
2879
3131
  const isCurrent = index === currentStep;
2880
3132
  const isFuture = index > currentStep;
2881
- return /* @__PURE__ */ jsxs29(
3133
+ return /* @__PURE__ */ jsxs30(
2882
3134
  "li",
2883
3135
  {
2884
3136
  className: "flex flex-1 flex-col items-center",
2885
3137
  "aria-current": isCurrent ? "step" : void 0,
2886
3138
  children: [
2887
- /* @__PURE__ */ jsxs29("div", { className: "flex w-full items-center", children: [
2888
- index > 0 ? /* @__PURE__ */ jsx41(
3139
+ /* @__PURE__ */ jsxs30("div", { className: "flex w-full items-center", children: [
3140
+ index > 0 ? /* @__PURE__ */ jsx42(
2889
3141
  "div",
2890
3142
  {
2891
3143
  "aria-hidden": "true",
@@ -2894,8 +3146,8 @@ function FormWizardProgress({ labels }) {
2894
3146
  index <= currentStep ? "bg-[var(--color-brand-primary)]" : "bg-[var(--color-border-default)]"
2895
3147
  ].join(" ")
2896
3148
  }
2897
- ) : /* @__PURE__ */ jsx41("div", { className: "flex-1", "aria-hidden": "true" }),
2898
- /* @__PURE__ */ jsx41(
3149
+ ) : /* @__PURE__ */ jsx42("div", { className: "flex-1", "aria-hidden": "true" }),
3150
+ /* @__PURE__ */ jsx42(
2899
3151
  "div",
2900
3152
  {
2901
3153
  className: [
@@ -2907,10 +3159,10 @@ function FormWizardProgress({ labels }) {
2907
3159
  isFuture ? "border-2 border-[var(--color-border-default)] bg-[var(--color-surface-default)] text-[var(--color-text-tertiary)]" : ""
2908
3160
  ].join(" "),
2909
3161
  "aria-hidden": "true",
2910
- children: isCompleted ? /* @__PURE__ */ jsx41(CheckIcon2, {}) : index + 1
3162
+ children: isCompleted ? /* @__PURE__ */ jsx42(CheckIcon2, {}) : index + 1
2911
3163
  }
2912
3164
  ),
2913
- index < totalSteps - 1 ? /* @__PURE__ */ jsx41(
3165
+ index < totalSteps - 1 ? /* @__PURE__ */ jsx42(
2914
3166
  "div",
2915
3167
  {
2916
3168
  "aria-hidden": "true",
@@ -2919,9 +3171,9 @@ function FormWizardProgress({ labels }) {
2919
3171
  index < currentStep ? "bg-[var(--color-brand-primary)]" : "bg-[var(--color-border-default)]"
2920
3172
  ].join(" ")
2921
3173
  }
2922
- ) : /* @__PURE__ */ jsx41("div", { className: "flex-1", "aria-hidden": "true" })
3174
+ ) : /* @__PURE__ */ jsx42("div", { className: "flex-1", "aria-hidden": "true" })
2923
3175
  ] }),
2924
- /* @__PURE__ */ jsx41(
3176
+ /* @__PURE__ */ jsx42(
2925
3177
  "span",
2926
3178
  {
2927
3179
  className: [
@@ -2939,15 +3191,15 @@ function FormWizardProgress({ labels }) {
2939
3191
  }
2940
3192
 
2941
3193
  // src/components/FormWizard/FormWizardNav.tsx
2942
- import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
3194
+ import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
2943
3195
  function FormWizardNav({
2944
3196
  onNext,
2945
3197
  isSubmitting = false,
2946
3198
  submitLabel = "Submit"
2947
3199
  }) {
2948
3200
  const { canGoBack, goBack, isLastStep } = useFormWizard();
2949
- return /* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-end gap-[var(--spacing-3)]", children: [
2950
- canGoBack && /* @__PURE__ */ jsx42(
3201
+ return /* @__PURE__ */ jsxs31("div", { className: "flex items-center justify-end gap-[var(--spacing-3)]", children: [
3202
+ canGoBack && /* @__PURE__ */ jsx43(
2951
3203
  Button,
2952
3204
  {
2953
3205
  variant: "secondary",
@@ -2957,7 +3209,7 @@ function FormWizardNav({
2957
3209
  children: "Back"
2958
3210
  }
2959
3211
  ),
2960
- /* @__PURE__ */ jsx42(
3212
+ /* @__PURE__ */ jsx43(
2961
3213
  Button,
2962
3214
  {
2963
3215
  variant: "primary",
@@ -3364,6 +3616,8 @@ export {
3364
3616
  EmptyState,
3365
3617
  Field,
3366
3618
  Fieldset,
3619
+ FileCard,
3620
+ FileIcon,
3367
3621
  FontSize2xl,
3368
3622
  FontSize3xl,
3369
3623
  FontSize4xl,
@@ -3442,6 +3696,8 @@ export {
3442
3696
  TabPanel2 as UnstyledTabPanel,
3443
3697
  Tabs2 as UnstyledTabs,
3444
3698
  createToastBridge,
3699
+ getFileIcon,
3700
+ getTypeLabel,
3445
3701
  pillColorFromName,
3446
3702
  useFormWizard,
3447
3703
  useInputGroup,