@cytario/design 1.13.0 → 1.14.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
@@ -2143,33 +2143,137 @@ function SegmentedControlItem({
2143
2143
 
2144
2144
  // src/components/StorageConnectionCard/StorageConnectionCard.tsx
2145
2145
  import { AlertCircle, Database, Info as Info2 } from "lucide-react";
2146
+ import { twMerge as twMerge9 } from "tailwind-merge";
2147
+
2148
+ // src/components/Pill/Pill.tsx
2146
2149
  import { twMerge as twMerge7 } from "tailwind-merge";
2147
- import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs20 } from "react/jsx-runtime";
2150
+ import { jsx as jsx30 } from "react/jsx-runtime";
2151
+ var HASH_PALETTE = [
2152
+ "teal",
2153
+ // sky
2154
+ "amber",
2155
+ // amber
2156
+ "green",
2157
+ // emerald
2158
+ "rose",
2159
+ // rose
2160
+ "purple",
2161
+ // violet
2162
+ "amber",
2163
+ // orange (mapped to amber -- closest warm token)
2164
+ "teal",
2165
+ // teal
2166
+ "rose"
2167
+ // fuchsia (mapped to rose -- closest pink token)
2168
+ ];
2169
+ function pillColorFromName(name) {
2170
+ let hash = 0;
2171
+ for (let i = 0; i < name.length; i++) {
2172
+ hash = name.charCodeAt(i) + ((hash << 5) - hash);
2173
+ }
2174
+ return HASH_PALETTE[Math.abs(hash) % HASH_PALETTE.length];
2175
+ }
2176
+ var colorStyles = {
2177
+ neutral: "bg-[var(--color-badge-neutral-bg)] text-[var(--color-badge-neutral-text)]",
2178
+ purple: "bg-[var(--color-badge-purple-bg)] text-[var(--color-badge-purple-text)]",
2179
+ teal: "bg-[var(--color-badge-teal-bg)] text-[var(--color-badge-teal-text)]",
2180
+ rose: "bg-[var(--color-badge-rose-bg)] text-[var(--color-badge-rose-text)]",
2181
+ slate: "bg-[var(--color-badge-slate-bg)] text-[var(--color-badge-slate-text)]",
2182
+ green: "bg-[var(--color-badge-green-bg)] text-[var(--color-badge-green-text)]",
2183
+ amber: "bg-[var(--color-badge-amber-bg)] text-[var(--color-badge-amber-text)]"
2184
+ };
2185
+ var dotColorStyles = {
2186
+ neutral: "bg-[var(--color-badge-neutral-text)]",
2187
+ purple: "bg-[var(--color-badge-purple-text)]",
2188
+ teal: "bg-[var(--color-badge-teal-text)]",
2189
+ rose: "bg-[var(--color-badge-rose-text)]",
2190
+ slate: "bg-[var(--color-badge-slate-text)]",
2191
+ green: "bg-[var(--color-badge-green-text)]",
2192
+ amber: "bg-[var(--color-badge-amber-text)]"
2193
+ };
2194
+ function resolveColor(color, name) {
2195
+ if (color && color !== "auto") return color;
2196
+ if (name) return pillColorFromName(name);
2197
+ return "neutral";
2198
+ }
2199
+ function Pill({ children, color, name, className }) {
2200
+ const resolved = resolveColor(color, name);
2201
+ return /* @__PURE__ */ jsx30(
2202
+ "span",
2203
+ {
2204
+ className: twMerge7(
2205
+ "inline-flex items-center rounded-full",
2206
+ "px-2 py-0.5",
2207
+ "text-[length:var(--font-size-xs)] font-[number:var(--font-weight-medium)] leading-[var(--line-height-tight)]",
2208
+ colorStyles[resolved],
2209
+ className
2210
+ ),
2211
+ children
2212
+ }
2213
+ );
2214
+ }
2215
+
2216
+ // src/components/Pill/GroupPill.tsx
2217
+ import { twMerge as twMerge8 } from "tailwind-merge";
2218
+ import { jsx as jsx31, jsxs as jsxs20 } from "react/jsx-runtime";
2219
+ function GroupPill({
2220
+ path,
2221
+ visibleCount = 3,
2222
+ className
2223
+ }) {
2224
+ const segments = path.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
2225
+ if (segments.length === 0) return null;
2226
+ const hiddenCount = Math.max(0, segments.length - visibleCount);
2227
+ const hiddenSegments = segments.slice(0, hiddenCount);
2228
+ const visibleSegments = segments.slice(hiddenCount);
2229
+ return /* @__PURE__ */ jsxs20(
2230
+ "span",
2231
+ {
2232
+ className: twMerge8(
2233
+ "inline-flex items-center gap-1",
2234
+ className
2235
+ ),
2236
+ "aria-label": `Group: ${segments.join(" / ")}`,
2237
+ children: [
2238
+ hiddenSegments.map((segment, index) => {
2239
+ const color = pillColorFromName(segment);
2240
+ return /* @__PURE__ */ jsx31(
2241
+ "span",
2242
+ {
2243
+ className: twMerge8(
2244
+ "inline-block size-2 shrink-0 rounded-full",
2245
+ dotColorStyles[color]
2246
+ ),
2247
+ "aria-hidden": "true",
2248
+ title: segment
2249
+ },
2250
+ `dot-${index}-${segment}`
2251
+ );
2252
+ }),
2253
+ visibleSegments.map((segment, index) => /* @__PURE__ */ jsx31(Pill, { name: segment, children: segment }, `pill-${index}-${segment}`))
2254
+ ]
2255
+ }
2256
+ );
2257
+ }
2258
+
2259
+ // src/components/StorageConnectionCard/StorageConnectionCard.tsx
2260
+ import { Fragment as Fragment8, jsx as jsx32, jsxs as jsxs21 } from "react/jsx-runtime";
2148
2261
  var statusDotStyles = {
2149
2262
  connected: "bg-[var(--color-status-success)]",
2150
2263
  error: "border-2 border-[var(--color-status-danger)] bg-transparent",
2151
2264
  loading: "bg-[var(--color-status-warning)] animate-pulse"
2152
2265
  };
2153
2266
  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)]" }
2267
+ aws: { label: "AWS", color: "purple" },
2268
+ azure: { label: "Azure", color: "teal" },
2269
+ gcp: { label: "GCP", color: "slate" },
2270
+ minio: { label: "MinIO", color: "rose" }
2158
2271
  };
2159
2272
  function ProviderBadge({ provider }) {
2160
2273
  const config = providerConfig[provider.toLowerCase()];
2161
2274
  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
- );
2275
+ const color = config?.color ?? "neutral";
2276
+ return /* @__PURE__ */ jsx32(Pill, { color, children: label });
2173
2277
  }
2174
2278
  function PreviewArea({
2175
2279
  status = "connected",
@@ -2177,11 +2281,11 @@ function PreviewArea({
2177
2281
  children
2178
2282
  }) {
2179
2283
  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" }) });
2284
+ return /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32(Spinner, { size: "lg", "aria-label": "Loading connection" }) });
2181
2285
  }
2182
2286
  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(
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(
2185
2289
  Icon,
2186
2290
  {
2187
2291
  icon: AlertCircle,
@@ -2189,13 +2293,13 @@ function PreviewArea({
2189
2293
  className: "text-[var(--color-text-danger)]"
2190
2294
  }
2191
2295
  ),
2192
- errorMessage && /* @__PURE__ */ jsx30("p", { className: "text-center text-xs text-[var(--color-text-danger)]", children: errorMessage })
2296
+ errorMessage && /* @__PURE__ */ jsx32("p", { className: "text-center text-xs text-[var(--color-text-danger)]", children: errorMessage })
2193
2297
  ] });
2194
2298
  }
2195
2299
  if (children) {
2196
- return /* @__PURE__ */ jsx30("div", { className: "h-full w-full overflow-hidden", children });
2300
+ return /* @__PURE__ */ jsx32("div", { className: "h-full w-full overflow-hidden", children });
2197
2301
  }
2198
- return /* @__PURE__ */ jsx30("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx30(
2302
+ return /* @__PURE__ */ jsx32("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsx32(
2199
2303
  Icon,
2200
2304
  {
2201
2305
  icon: Database,
@@ -2216,22 +2320,22 @@ function StorageConnectionCard({
2216
2320
  onInfo,
2217
2321
  className
2218
2322
  }) {
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(
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(
2224
2328
  "span",
2225
2329
  {
2226
- className: twMerge7(
2330
+ className: twMerge9(
2227
2331
  "mt-1.5 h-2 w-2 shrink-0 rounded-full",
2228
2332
  statusDotStyles[status]
2229
2333
  ),
2230
2334
  "aria-label": `Status: ${status}`
2231
2335
  }
2232
2336
  ),
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(
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(
2235
2339
  IconButton,
2236
2340
  {
2237
2341
  icon: Info2,
@@ -2245,10 +2349,10 @@ function StorageConnectionCard({
2245
2349
  }
2246
2350
  )
2247
2351
  ] }),
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: [
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: [
2252
2356
  imageCount,
2253
2357
  " ",
2254
2358
  imageCount === 1 ? "image" : "images"
@@ -2256,7 +2360,7 @@ function StorageConnectionCard({
2256
2360
  ] })
2257
2361
  ] })
2258
2362
  ] });
2259
- const baseStyles = twMerge7(
2363
+ const baseStyles = twMerge9(
2260
2364
  "flex flex-col overflow-hidden rounded-[var(--border-radius-lg)]",
2261
2365
  "border border-[var(--color-border-default)]",
2262
2366
  "shadow-sm transition-all",
@@ -2264,14 +2368,14 @@ function StorageConnectionCard({
2264
2368
  className
2265
2369
  );
2266
2370
  if (href) {
2267
- return /* @__PURE__ */ jsx30("a", { href, className: twMerge7(baseStyles, "no-underline"), children: cardContent });
2371
+ return /* @__PURE__ */ jsx32("a", { href, className: twMerge9(baseStyles, "no-underline"), children: cardContent });
2268
2372
  }
2269
- return /* @__PURE__ */ jsx30("div", { className: baseStyles, children: cardContent });
2373
+ return /* @__PURE__ */ jsx32("div", { className: baseStyles, children: cardContent });
2270
2374
  }
2271
2375
 
2272
2376
  // 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";
2377
+ import { twMerge as twMerge10 } from "tailwind-merge";
2378
+ import { jsx as jsx33, jsxs as jsxs22 } from "react/jsx-runtime";
2275
2379
  var variantStyles4 = {
2276
2380
  neutral: "bg-[var(--color-badge-neutral-bg)] text-[var(--color-badge-neutral-text)]",
2277
2381
  purple: "bg-[var(--color-badge-purple-bg)] text-[var(--color-badge-purple-text)]",
@@ -2296,10 +2400,10 @@ function Badge({
2296
2400
  icon: IconComponent,
2297
2401
  className
2298
2402
  }) {
2299
- return /* @__PURE__ */ jsxs21(
2403
+ return /* @__PURE__ */ jsxs22(
2300
2404
  "span",
2301
2405
  {
2302
- className: twMerge8(
2406
+ className: twMerge10(
2303
2407
  "inline-flex items-center gap-1 rounded-[var(--border-radius-full)]",
2304
2408
  "text-[length:var(--font-size-xs)] font-[number:var(--font-weight-medium)] leading-[var(--line-height-tight)]",
2305
2409
  variantStyles4[variant],
@@ -2307,7 +2411,7 @@ function Badge({
2307
2411
  className
2308
2412
  ),
2309
2413
  children: [
2310
- IconComponent && /* @__PURE__ */ jsx31(IconComponent, { size: iconSizeMap4[size], "aria-hidden": "true" }),
2414
+ IconComponent && /* @__PURE__ */ jsx33(IconComponent, { size: iconSizeMap4[size], "aria-hidden": "true" }),
2311
2415
  children
2312
2416
  ]
2313
2417
  }
@@ -2315,8 +2419,8 @@ function Badge({
2315
2419
  }
2316
2420
 
2317
2421
  // 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";
2422
+ import { twMerge as twMerge11 } from "tailwind-merge";
2423
+ import { Fragment as Fragment9, jsx as jsx34, jsxs as jsxs23 } from "react/jsx-runtime";
2320
2424
  var paddingStyles = {
2321
2425
  none: "p-0",
2322
2426
  sm: "p-3",
@@ -2333,28 +2437,28 @@ function Card({
2333
2437
  className
2334
2438
  }) {
2335
2439
  const isInteractive = interactive || !!href;
2336
- const containerClass = twMerge9(
2440
+ const containerClass = twMerge11(
2337
2441
  "bg-[var(--color-surface-default)] border border-[var(--color-border-default)] rounded-[var(--border-radius-lg)] overflow-hidden shadow-sm",
2338
2442
  isInteractive && "transition-shadow hover:shadow-md hover:border-[var(--color-border-focus)] cursor-pointer",
2339
2443
  href && "block focus-visible:ring-2 focus-visible:ring-[var(--color-border-focus)] focus-visible:ring-offset-2 outline-none",
2340
2444
  className
2341
2445
  );
2342
- const content = /* @__PURE__ */ jsxs22(Fragment9, { children: [
2343
- header && /* @__PURE__ */ jsx32(
2446
+ const content = /* @__PURE__ */ jsxs23(Fragment9, { children: [
2447
+ header && /* @__PURE__ */ jsx34(
2344
2448
  "div",
2345
2449
  {
2346
- className: twMerge9(
2450
+ className: twMerge11(
2347
2451
  "border-b border-[var(--color-border-default)]",
2348
2452
  paddingStyles[padding]
2349
2453
  ),
2350
2454
  children: header
2351
2455
  }
2352
2456
  ),
2353
- /* @__PURE__ */ jsx32("div", { className: paddingStyles[padding], children }),
2354
- footer && /* @__PURE__ */ jsx32(
2457
+ /* @__PURE__ */ jsx34("div", { className: paddingStyles[padding], children }),
2458
+ footer && /* @__PURE__ */ jsx34(
2355
2459
  "div",
2356
2460
  {
2357
- className: twMerge9(
2461
+ className: twMerge11(
2358
2462
  "border-t border-[var(--color-border-default)]",
2359
2463
  paddingStyles[padding]
2360
2464
  ),
@@ -2363,15 +2467,15 @@ function Card({
2363
2467
  )
2364
2468
  ] });
2365
2469
  if (href) {
2366
- return /* @__PURE__ */ jsx32("a", { href, className: containerClass, children: content });
2470
+ return /* @__PURE__ */ jsx34("a", { href, className: containerClass, children: content });
2367
2471
  }
2368
- return /* @__PURE__ */ jsx32("div", { className: containerClass, children: content });
2472
+ return /* @__PURE__ */ jsx34("div", { className: containerClass, children: content });
2369
2473
  }
2370
2474
 
2371
2475
  // src/components/DeltaIndicator/DeltaIndicator.tsx
2372
2476
  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";
2477
+ import { twMerge as twMerge12 } from "tailwind-merge";
2478
+ import { jsx as jsx35, jsxs as jsxs24 } from "react/jsx-runtime";
2375
2479
  function getDirection(current, previous) {
2376
2480
  const diff = current - previous;
2377
2481
  if (diff > 0) return "increase";
@@ -2424,16 +2528,16 @@ function DeltaIndicator({
2424
2528
  className
2425
2529
  }) {
2426
2530
  if (unavailable) {
2427
- return /* @__PURE__ */ jsxs23(
2531
+ return /* @__PURE__ */ jsxs24(
2428
2532
  "span",
2429
2533
  {
2430
- className: twMerge10(
2534
+ className: twMerge12(
2431
2535
  "inline-flex items-center gap-1 font-[number:var(--font-weight-medium)]",
2432
2536
  "text-[var(--color-text-tertiary)]",
2433
2537
  className
2434
2538
  ),
2435
2539
  children: [
2436
- label && /* @__PURE__ */ jsx33("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2540
+ label && /* @__PURE__ */ jsx35("span", { className: "text-[length:var(--font-size-sm)] text-[var(--color-text-secondary)] mr-1", children: label }),
2437
2541
  unavailableText
2438
2542
  ]
2439
2543
  }
@@ -2441,7 +2545,7 @@ function DeltaIndicator({
2441
2545
  }
2442
2546
  const diff = current - previous;
2443
2547
  const direction = getDirection(current, previous);
2444
- const colorStyles = reverseColor ? reverseDirectionColors[direction] : directionColors[direction];
2548
+ const colorStyles2 = reverseColor ? reverseDirectionColors[direction] : directionColors[direction];
2445
2549
  const IconComponent = directionIcons[direction];
2446
2550
  const isNew = previous === 0 && current > 0;
2447
2551
  let valueText;
@@ -2463,12 +2567,12 @@ function DeltaIndicator({
2463
2567
  }
2464
2568
  }
2465
2569
  const isPill = mode === "pill";
2466
- return /* @__PURE__ */ jsxs23(
2570
+ return /* @__PURE__ */ jsxs24(
2467
2571
  "span",
2468
2572
  {
2469
- className: twMerge10(
2573
+ className: twMerge12(
2470
2574
  "inline-flex items-center gap-1 font-[number:var(--font-weight-medium)]",
2471
- colorStyles,
2575
+ colorStyles2,
2472
2576
  isPill && [
2473
2577
  "rounded-[var(--border-radius-full)] px-2 py-0.5",
2474
2578
  "text-[length:var(--font-size-xs)]",
@@ -2477,8 +2581,8 @@ function DeltaIndicator({
2477
2581
  className
2478
2582
  ),
2479
2583
  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 }),
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 }),
2482
2586
  valueText
2483
2587
  ]
2484
2588
  }
@@ -2486,8 +2590,8 @@ function DeltaIndicator({
2486
2590
  }
2487
2591
 
2488
2592
  // 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";
2593
+ import { twMerge as twMerge13 } from "tailwind-merge";
2594
+ import { jsx as jsx36, jsxs as jsxs25 } from "react/jsx-runtime";
2491
2595
  var fillStyles = {
2492
2596
  brand: "bg-[var(--color-progress-fill)]",
2493
2597
  success: "bg-[var(--color-progress-fill-success)]",
@@ -2510,12 +2614,12 @@ function ProgressBar({
2510
2614
  className
2511
2615
  }) {
2512
2616
  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) })
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) })
2517
2621
  ] }),
2518
- /* @__PURE__ */ jsx34(
2622
+ /* @__PURE__ */ jsx36(
2519
2623
  "div",
2520
2624
  {
2521
2625
  role: "progressbar",
@@ -2523,14 +2627,14 @@ function ProgressBar({
2523
2627
  "aria-valuemin": 0,
2524
2628
  "aria-valuemax": 100,
2525
2629
  "aria-label": label ?? "Progress",
2526
- className: twMerge11(
2630
+ className: twMerge13(
2527
2631
  "w-full rounded-[var(--border-radius-full)] bg-[var(--color-progress-track)]",
2528
2632
  sizeStyles8[size]
2529
2633
  ),
2530
- children: /* @__PURE__ */ jsx34(
2634
+ children: /* @__PURE__ */ jsx36(
2531
2635
  "div",
2532
2636
  {
2533
- className: twMerge11(
2637
+ className: twMerge13(
2534
2638
  "h-full rounded-[var(--border-radius-full)] transition-all duration-300",
2535
2639
  fillStyles[variant]
2536
2640
  ),
@@ -2551,8 +2655,8 @@ import {
2551
2655
  CheckCircle2,
2552
2656
  X as X3
2553
2657
  } from "lucide-react";
2554
- import { twMerge as twMerge12 } from "tailwind-merge";
2555
- import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
2658
+ import { twMerge as twMerge14 } from "tailwind-merge";
2659
+ import { jsx as jsx37, jsxs as jsxs26 } from "react/jsx-runtime";
2556
2660
  var variantConfig2 = {
2557
2661
  info: {
2558
2662
  icon: Info3,
@@ -2596,40 +2700,40 @@ function Banner({
2596
2700
  setDismissed(true);
2597
2701
  onDismiss?.();
2598
2702
  };
2599
- return /* @__PURE__ */ jsxs25(
2703
+ return /* @__PURE__ */ jsxs26(
2600
2704
  "div",
2601
2705
  {
2602
2706
  role: config.role,
2603
- className: twMerge12(
2707
+ className: twMerge14(
2604
2708
  "flex items-start gap-[var(--spacing-3)] rounded-[var(--border-radius-lg)] border px-[var(--spacing-4)] py-[var(--spacing-3)]",
2605
2709
  "text-[length:var(--font-size-sm)]",
2606
2710
  config.containerClass,
2607
2711
  className
2608
2712
  ),
2609
2713
  children: [
2610
- /* @__PURE__ */ jsx35(
2714
+ /* @__PURE__ */ jsx37(
2611
2715
  IconComponent,
2612
2716
  {
2613
2717
  size: 20,
2614
- className: twMerge12("shrink-0 mt-0.5", config.iconClass),
2718
+ className: twMerge14("shrink-0 mt-0.5", config.iconClass),
2615
2719
  "aria-hidden": "true"
2616
2720
  }
2617
2721
  ),
2618
- /* @__PURE__ */ jsxs25("div", { className: "flex-1", children: [
2619
- title && /* @__PURE__ */ jsxs25("span", { className: "font-[number:var(--font-weight-medium)]", children: [
2722
+ /* @__PURE__ */ jsxs26("div", { className: "flex-1", children: [
2723
+ title && /* @__PURE__ */ jsxs26("span", { className: "font-[number:var(--font-weight-medium)]", children: [
2620
2724
  title,
2621
2725
  " \u2014 "
2622
2726
  ] }),
2623
2727
  children
2624
2728
  ] }),
2625
- dismissible && /* @__PURE__ */ jsx35(
2729
+ dismissible && /* @__PURE__ */ jsx37(
2626
2730
  "button",
2627
2731
  {
2628
2732
  type: "button",
2629
2733
  onClick: handleDismiss,
2630
2734
  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
2735
  "aria-label": "Dismiss",
2632
- children: /* @__PURE__ */ jsx35(X3, { size: 16, "aria-hidden": "true" })
2736
+ children: /* @__PURE__ */ jsx37(X3, { size: 16, "aria-hidden": "true" })
2633
2737
  }
2634
2738
  )
2635
2739
  ]
@@ -2638,8 +2742,8 @@ function Banner({
2638
2742
  }
2639
2743
 
2640
2744
  // 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";
2745
+ import { twMerge as twMerge15 } from "tailwind-merge";
2746
+ import { Fragment as Fragment10, jsx as jsx38, jsxs as jsxs27 } from "react/jsx-runtime";
2643
2747
  var sizeConfig = {
2644
2748
  sm: {
2645
2749
  padding: "p-3",
@@ -2661,30 +2765,209 @@ function MetricCard({
2661
2765
  className
2662
2766
  }) {
2663
2767
  const config = sizeConfig[size];
2664
- const containerClass = twMerge13(
2768
+ const containerClass = twMerge15(
2665
2769
  "bg-[var(--color-surface-default)] border border-[var(--color-border-default)] rounded-[var(--border-radius-lg)] shadow-sm",
2666
2770
  config.padding,
2667
2771
  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
2772
  className
2669
2773
  );
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(
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(
2673
2777
  "div",
2674
2778
  {
2675
- className: twMerge13(
2779
+ className: twMerge15(
2676
2780
  config.valueClass,
2677
2781
  "font-[number:var(--font-weight-semibold)] text-[var(--color-text-primary)] mt-1 tabular-nums"
2678
2782
  ),
2679
2783
  children: value
2680
2784
  }
2681
2785
  ),
2682
- secondary && /* @__PURE__ */ jsx36("div", { className: "mt-1 text-sm", children: secondary })
2786
+ secondary && /* @__PURE__ */ jsx38("div", { className: "mt-1 text-sm", children: secondary })
2683
2787
  ] });
2684
2788
  if (href) {
2685
- return /* @__PURE__ */ jsx36("a", { href, className: containerClass, children: content });
2789
+ return /* @__PURE__ */ jsx38("a", { href, className: containerClass, children: content });
2686
2790
  }
2687
- return /* @__PURE__ */ jsx36("div", { className: containerClass, children: content });
2791
+ return /* @__PURE__ */ jsx38("div", { className: containerClass, children: content });
2792
+ }
2793
+
2794
+ // src/components/SectionHeader/SectionHeader.tsx
2795
+ import { twMerge as twMerge16 } from "tailwind-merge";
2796
+ import { jsx as jsx39, jsxs as jsxs28 } from "react/jsx-runtime";
2797
+ function SectionHeader({
2798
+ title,
2799
+ children,
2800
+ className
2801
+ }) {
2802
+ return /* @__PURE__ */ jsxs28(
2803
+ "div",
2804
+ {
2805
+ className: twMerge16(
2806
+ "flex flex-wrap items-center gap-[var(--spacing-3)] py-[var(--spacing-4)]",
2807
+ className
2808
+ ),
2809
+ 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 })
2812
+ ]
2813
+ }
2814
+ );
2815
+ }
2816
+
2817
+ // 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";
2820
+ var FormWizardContext = createContext5({
2821
+ currentStep: 0,
2822
+ totalSteps: 1,
2823
+ canGoBack: false,
2824
+ goBack: () => {
2825
+ },
2826
+ isLastStep: true
2827
+ });
2828
+ function useFormWizard() {
2829
+ return useContext5(FormWizardContext);
2830
+ }
2831
+ function FormWizard({
2832
+ currentStep,
2833
+ totalSteps,
2834
+ onStepChange,
2835
+ children
2836
+ }) {
2837
+ const canGoBack = currentStep > 0;
2838
+ const isLastStep = currentStep >= totalSteps - 1;
2839
+ const goBack = useCallback3(() => {
2840
+ if (currentStep > 0) {
2841
+ onStepChange(currentStep - 1);
2842
+ }
2843
+ }, [currentStep, onStepChange]);
2844
+ const value = useMemo(
2845
+ () => ({
2846
+ currentStep,
2847
+ totalSteps,
2848
+ canGoBack,
2849
+ goBack,
2850
+ isLastStep
2851
+ }),
2852
+ [currentStep, totalSteps, canGoBack, goBack, isLastStep]
2853
+ );
2854
+ return /* @__PURE__ */ jsx40(FormWizardContext.Provider, { value, children });
2855
+ }
2856
+
2857
+ // src/components/FormWizard/FormWizardProgress.tsx
2858
+ import { jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
2859
+ function CheckIcon2() {
2860
+ return /* @__PURE__ */ jsx41(
2861
+ "svg",
2862
+ {
2863
+ "aria-hidden": "true",
2864
+ className: "h-4 w-4 text-[var(--color-text-inverse)]",
2865
+ viewBox: "0 0 16 16",
2866
+ fill: "none",
2867
+ stroke: "currentColor",
2868
+ strokeWidth: "2",
2869
+ strokeLinecap: "round",
2870
+ strokeLinejoin: "round",
2871
+ children: /* @__PURE__ */ jsx41("path", { d: "M3 8.5l3.5 3.5 6.5-7" })
2872
+ }
2873
+ );
2874
+ }
2875
+ function FormWizardProgress({ labels }) {
2876
+ 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) => {
2878
+ const isCompleted = index < currentStep;
2879
+ const isCurrent = index === currentStep;
2880
+ const isFuture = index > currentStep;
2881
+ return /* @__PURE__ */ jsxs29(
2882
+ "li",
2883
+ {
2884
+ className: "flex flex-1 flex-col items-center",
2885
+ "aria-current": isCurrent ? "step" : void 0,
2886
+ children: [
2887
+ /* @__PURE__ */ jsxs29("div", { className: "flex w-full items-center", children: [
2888
+ index > 0 ? /* @__PURE__ */ jsx41(
2889
+ "div",
2890
+ {
2891
+ "aria-hidden": "true",
2892
+ className: [
2893
+ "h-0.5 flex-1",
2894
+ index <= currentStep ? "bg-[var(--color-brand-primary)]" : "bg-[var(--color-border-default)]"
2895
+ ].join(" ")
2896
+ }
2897
+ ) : /* @__PURE__ */ jsx41("div", { className: "flex-1", "aria-hidden": "true" }),
2898
+ /* @__PURE__ */ jsx41(
2899
+ "div",
2900
+ {
2901
+ className: [
2902
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-full",
2903
+ "text-[length:var(--font-size-sm)] font-[number:var(--font-weight-medium)]",
2904
+ "transition-colors",
2905
+ isCompleted ? "bg-[var(--color-brand-primary)] text-[var(--color-text-inverse)]" : "",
2906
+ isCurrent ? "border-2 border-[var(--color-brand-primary)] bg-[var(--color-surface-default)] text-[var(--color-brand-primary)]" : "",
2907
+ isFuture ? "border-2 border-[var(--color-border-default)] bg-[var(--color-surface-default)] text-[var(--color-text-tertiary)]" : ""
2908
+ ].join(" "),
2909
+ "aria-hidden": "true",
2910
+ children: isCompleted ? /* @__PURE__ */ jsx41(CheckIcon2, {}) : index + 1
2911
+ }
2912
+ ),
2913
+ index < totalSteps - 1 ? /* @__PURE__ */ jsx41(
2914
+ "div",
2915
+ {
2916
+ "aria-hidden": "true",
2917
+ className: [
2918
+ "h-0.5 flex-1",
2919
+ index < currentStep ? "bg-[var(--color-brand-primary)]" : "bg-[var(--color-border-default)]"
2920
+ ].join(" ")
2921
+ }
2922
+ ) : /* @__PURE__ */ jsx41("div", { className: "flex-1", "aria-hidden": "true" })
2923
+ ] }),
2924
+ /* @__PURE__ */ jsx41(
2925
+ "span",
2926
+ {
2927
+ className: [
2928
+ "mt-[var(--spacing-2)] text-center text-[length:var(--font-size-sm)]",
2929
+ isCurrent ? "font-[number:var(--font-weight-semibold)] text-[var(--color-text-primary)]" : "font-[number:var(--font-weight-regular)] text-[var(--color-text-secondary)]"
2930
+ ].join(" "),
2931
+ children: label
2932
+ }
2933
+ )
2934
+ ]
2935
+ },
2936
+ label
2937
+ );
2938
+ }) }) });
2939
+ }
2940
+
2941
+ // src/components/FormWizard/FormWizardNav.tsx
2942
+ import { jsx as jsx42, jsxs as jsxs30 } from "react/jsx-runtime";
2943
+ function FormWizardNav({
2944
+ onNext,
2945
+ isSubmitting = false,
2946
+ submitLabel = "Submit"
2947
+ }) {
2948
+ 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(
2951
+ Button,
2952
+ {
2953
+ variant: "secondary",
2954
+ size: "lg",
2955
+ onPress: goBack,
2956
+ isDisabled: isSubmitting,
2957
+ children: "Back"
2958
+ }
2959
+ ),
2960
+ /* @__PURE__ */ jsx42(
2961
+ Button,
2962
+ {
2963
+ variant: "primary",
2964
+ size: "lg",
2965
+ onPress: onNext,
2966
+ isLoading: isSubmitting,
2967
+ children: isLastStep ? submitLabel : "Next"
2968
+ }
2969
+ )
2970
+ ] });
2688
2971
  }
2689
2972
 
2690
2973
  // src/tokens/tokens.ts
@@ -3096,6 +3379,10 @@ export {
3096
3379
  FontWeightMedium,
3097
3380
  FontWeightRegular,
3098
3381
  FontWeightSemibold,
3382
+ FormWizard,
3383
+ FormWizardNav,
3384
+ FormWizardProgress,
3385
+ GroupPill,
3099
3386
  H1,
3100
3387
  H2,
3101
3388
  H3,
@@ -3114,6 +3401,7 @@ export {
3114
3401
  Link,
3115
3402
  Menu,
3116
3403
  MetricCard,
3404
+ Pill,
3117
3405
  Popover3 as Popover,
3118
3406
  PopoverContent,
3119
3407
  PopoverTrigger,
@@ -3123,6 +3411,7 @@ export {
3123
3411
  RadioGroup,
3124
3412
  RouterProvider,
3125
3413
  Row,
3414
+ SectionHeader,
3126
3415
  SegmentedControl,
3127
3416
  SegmentedControlItem,
3128
3417
  Select,
@@ -3153,6 +3442,8 @@ export {
3153
3442
  TabPanel2 as UnstyledTabPanel,
3154
3443
  Tabs2 as UnstyledTabs,
3155
3444
  createToastBridge,
3445
+ pillColorFromName,
3446
+ useFormWizard,
3156
3447
  useInputGroup,
3157
3448
  useToast
3158
3449
  };