@usefidel/design-system 0.25.1 → 0.26.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
@@ -950,12 +950,23 @@ function Badge({ tone = "neutral", icon, className, children, ...rest }) {
950
950
  }
951
951
 
952
952
  // src/components/Tag/Tag.tsx
953
+ import { X } from "lucide-react";
953
954
  import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
954
- function Tag({ dot, icon, className, children, ...rest }) {
955
+ function Tag({ dot, icon, onRemove, removeLabel, className, children, ...rest }) {
955
956
  return /* @__PURE__ */ jsxs14("span", { className: ["fds-tag", className].filter(Boolean).join(" "), ...rest, children: [
956
957
  dot && /* @__PURE__ */ jsx16("span", { className: `fds-dot fds-dot--${dot}`, "aria-hidden": "true" }),
957
958
  icon != null && /* @__PURE__ */ jsx16("span", { className: "fds-tag__icon", "aria-hidden": "true", children: icon }),
958
- children
959
+ children,
960
+ onRemove && /* @__PURE__ */ jsx16(
961
+ "button",
962
+ {
963
+ type: "button",
964
+ className: "fds-tag__remove",
965
+ "aria-label": `Remove ${removeLabel ?? (typeof children === "string" ? children : "")}`.trim(),
966
+ onClick: onRemove,
967
+ children: /* @__PURE__ */ jsx16(X, { "aria-hidden": "true" })
968
+ }
969
+ )
959
970
  ] });
960
971
  }
961
972
 
@@ -2304,7 +2315,7 @@ function PageHeader({ title, description, breadcrumb, actions, className, childr
2304
2315
 
2305
2316
  // src/components/Toast/Toast.tsx
2306
2317
  import { useEffect as useEffect9 } from "react";
2307
- import { X } from "lucide-react";
2318
+ import { X as X2 } from "lucide-react";
2308
2319
  import { jsx as jsx48, jsxs as jsxs39 } from "react/jsx-runtime";
2309
2320
  function ToastRegion({ className, children, ...rest }) {
2310
2321
  return /* @__PURE__ */ jsx48("div", { className: ["fds-toast-region", className].filter(Boolean).join(" "), "aria-live": "polite", ...rest, children });
@@ -2318,9 +2329,254 @@ function Toast({ children, action, onDismiss, duration, className, ...rest }) {
2318
2329
  return /* @__PURE__ */ jsxs39("div", { role: "status", className: ["fds-toast", className].filter(Boolean).join(" "), ...rest, children: [
2319
2330
  /* @__PURE__ */ jsx48("span", { className: "fds-toast__message", children }),
2320
2331
  action && /* @__PURE__ */ jsx48("button", { type: "button", className: "fds-toast__action", onClick: action.onClick, children: action.label }),
2321
- onDismiss && /* @__PURE__ */ jsx48("button", { type: "button", className: "fds-toast__close", "aria-label": "Dismiss", onClick: onDismiss, children: /* @__PURE__ */ jsx48(X, { "aria-hidden": "true" }) })
2332
+ onDismiss && /* @__PURE__ */ jsx48("button", { type: "button", className: "fds-toast__close", "aria-label": "Dismiss", onClick: onDismiss, children: /* @__PURE__ */ jsx48(X2, { "aria-hidden": "true" }) })
2333
+ ] });
2334
+ }
2335
+
2336
+ // src/components/Stepper/Stepper.tsx
2337
+ import { Children, isValidElement } from "react";
2338
+ import { Check as Check2 } from "lucide-react";
2339
+ import { jsx as jsx49, jsxs as jsxs40 } from "react/jsx-runtime";
2340
+ function StepperStep(_) {
2341
+ return null;
2342
+ }
2343
+ function StepperRoot({ className, children, ...rest }) {
2344
+ const steps = Children.toArray(children).filter(isValidElement);
2345
+ return /* @__PURE__ */ jsx49("ol", { className: ["fds-stepper", className].filter(Boolean).join(" "), ...rest, children: steps.map((step, i) => {
2346
+ const { status, children: label } = step.props;
2347
+ return /* @__PURE__ */ jsxs40(
2348
+ "li",
2349
+ {
2350
+ className: `fds-stepper__step fds-stepper__step--${status}`,
2351
+ "aria-current": status === "current" ? "step" : void 0,
2352
+ children: [
2353
+ /* @__PURE__ */ jsx49("span", { className: "fds-stepper__marker", "aria-hidden": "true", children: status === "done" ? /* @__PURE__ */ jsx49(Check2, {}) : i + 1 }),
2354
+ /* @__PURE__ */ jsx49("span", { className: "fds-stepper__label", children: label })
2355
+ ]
2356
+ },
2357
+ i
2358
+ );
2359
+ }) });
2360
+ }
2361
+ var Stepper = Object.assign(StepperRoot, { Step: StepperStep });
2362
+
2363
+ // src/components/NumberedSteps/NumberedSteps.tsx
2364
+ import { Children as Children2 } from "react";
2365
+ import { jsx as jsx50, jsxs as jsxs41 } from "react/jsx-runtime";
2366
+ function NumberedStepsRoot({ className, children, ...rest }) {
2367
+ return /* @__PURE__ */ jsx50("ol", { className: ["fds-numbered-steps", className].filter(Boolean).join(" "), ...rest, children: Children2.toArray(children) });
2368
+ }
2369
+ function NumberedStepsItem({ className, children, ...rest }) {
2370
+ return /* @__PURE__ */ jsxs41("li", { className: ["fds-numbered-steps__item", className].filter(Boolean).join(" "), ...rest, children: [
2371
+ /* @__PURE__ */ jsx50("span", { className: "fds-numbered-steps__marker", "aria-hidden": "true" }),
2372
+ /* @__PURE__ */ jsx50("div", { className: "fds-numbered-steps__body", children })
2373
+ ] });
2374
+ }
2375
+ var NumberedSteps = Object.assign(NumberedStepsRoot, { Item: NumberedStepsItem });
2376
+
2377
+ // src/components/OptionList/OptionList.tsx
2378
+ import { jsx as jsx51, jsxs as jsxs42 } from "react/jsx-runtime";
2379
+ function OptionListRoot({ className, children, ...rest }) {
2380
+ return /* @__PURE__ */ jsx51("div", { className: ["fds-option-list", className].filter(Boolean).join(" "), ...rest, children });
2381
+ }
2382
+ function OptionListLabel({ className, children, ...rest }) {
2383
+ return /* @__PURE__ */ jsx51("div", { className: ["fds-option-list__label", className].filter(Boolean).join(" "), ...rest, children });
2384
+ }
2385
+ function OptionRow({ control = "radio", title, description, meta, className, checked, disabled, ...rest }) {
2386
+ const Control = control === "checkbox" ? Checkbox : Radio;
2387
+ return /* @__PURE__ */ jsxs42(
2388
+ "div",
2389
+ {
2390
+ className: ["fds-option-row", checked ? "fds-option-row--checked" : "", className].filter(Boolean).join(" "),
2391
+ "data-disabled": disabled ? "" : void 0,
2392
+ children: [
2393
+ /* @__PURE__ */ jsx51(Control, { label: title, description, checked, disabled, ...rest }),
2394
+ meta != null && /* @__PURE__ */ jsx51("span", { className: "fds-option-row__meta", children: meta })
2395
+ ]
2396
+ }
2397
+ );
2398
+ }
2399
+ var OptionList = Object.assign(OptionListRoot, { Label: OptionListLabel, Row: OptionRow });
2400
+
2401
+ // src/components/Checklist/Checklist.tsx
2402
+ import { Check as Check3 } from "lucide-react";
2403
+ import { jsx as jsx52, jsxs as jsxs43 } from "react/jsx-runtime";
2404
+ function ChecklistRoot({ title, className, children, ...rest }) {
2405
+ return /* @__PURE__ */ jsxs43("section", { className: ["fds-checklist", className].filter(Boolean).join(" "), ...rest, children: [
2406
+ title != null && /* @__PURE__ */ jsx52("h3", { className: "fds-checklist__title", children: title }),
2407
+ /* @__PURE__ */ jsx52("ul", { className: "fds-checklist__items", children })
2408
+ ] });
2409
+ }
2410
+ function ChecklistItem({ done, label, value }) {
2411
+ return /* @__PURE__ */ jsxs43("li", { className: ["fds-checklist__item", done ? "fds-checklist__item--done" : ""].filter(Boolean).join(" "), children: [
2412
+ /* @__PURE__ */ jsx52("span", { className: "fds-checklist__mark", "aria-hidden": "true", children: done && /* @__PURE__ */ jsx52(Check3, {}) }),
2413
+ /* @__PURE__ */ jsxs43("span", { className: "fds-checklist__text", children: [
2414
+ /* @__PURE__ */ jsx52("span", { className: "fds-checklist__label", children: label }),
2415
+ /* @__PURE__ */ jsx52("span", { className: "fds-checklist__value", children: value })
2416
+ ] })
2417
+ ] });
2418
+ }
2419
+ var Checklist = Object.assign(ChecklistRoot, { Item: ChecklistItem });
2420
+
2421
+ // src/components/Drawer/Drawer.tsx
2422
+ import { useEffect as useEffect10, useId as useId14, useRef as useRef10 } from "react";
2423
+ import { createPortal as createPortal3 } from "react-dom";
2424
+ import { X as X3 } from "lucide-react";
2425
+ import { jsx as jsx53, jsxs as jsxs44 } from "react/jsx-runtime";
2426
+ var FOCUSABLE2 = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
2427
+ function Drawer({ open, onClose, title, description, children, footer, dismissible = true }) {
2428
+ const titleId = useId14();
2429
+ const descriptionId = useId14();
2430
+ const panelRef = useRef10(null);
2431
+ const onCloseRef = useRef10(onClose);
2432
+ onCloseRef.current = onClose;
2433
+ const dismissibleRef = useRef10(dismissible);
2434
+ dismissibleRef.current = dismissible;
2435
+ useEffect10(() => {
2436
+ if (!open) return;
2437
+ const panel = panelRef.current;
2438
+ const previouslyFocused = document.activeElement;
2439
+ (panel?.querySelector("[data-autofocus]") ?? panel?.querySelector(`.fds-drawer__body ${FOCUSABLE2}`) ?? panel)?.focus();
2440
+ const previousOverflow = document.body.style.overflow;
2441
+ document.body.style.overflow = "hidden";
2442
+ const onKey = (e) => {
2443
+ if (e.key === "Escape" && dismissibleRef.current) {
2444
+ e.preventDefault();
2445
+ onCloseRef.current();
2446
+ return;
2447
+ }
2448
+ if (e.key === "Tab" && panel) {
2449
+ const focusable = Array.from(panel.querySelectorAll(FOCUSABLE2));
2450
+ if (focusable.length === 0) return;
2451
+ const first = focusable[0];
2452
+ const last = focusable[focusable.length - 1];
2453
+ if (e.shiftKey && (document.activeElement === first || document.activeElement === panel)) {
2454
+ e.preventDefault();
2455
+ last.focus();
2456
+ } else if (!e.shiftKey && document.activeElement === last) {
2457
+ e.preventDefault();
2458
+ first.focus();
2459
+ }
2460
+ }
2461
+ };
2462
+ window.addEventListener("keydown", onKey);
2463
+ return () => {
2464
+ window.removeEventListener("keydown", onKey);
2465
+ document.body.style.overflow = previousOverflow;
2466
+ previouslyFocused?.focus?.();
2467
+ };
2468
+ }, [open]);
2469
+ if (!open || typeof document === "undefined") return null;
2470
+ return createPortal3(
2471
+ /* @__PURE__ */ jsx53(
2472
+ "div",
2473
+ {
2474
+ className: "fds-drawer__scrim",
2475
+ onMouseDown: (e) => {
2476
+ if (e.target === e.currentTarget && dismissible) onClose();
2477
+ },
2478
+ children: /* @__PURE__ */ jsxs44(
2479
+ "div",
2480
+ {
2481
+ ref: panelRef,
2482
+ className: "fds-drawer",
2483
+ role: "dialog",
2484
+ "aria-modal": "true",
2485
+ "aria-labelledby": titleId,
2486
+ "aria-describedby": description != null ? descriptionId : void 0,
2487
+ tabIndex: -1,
2488
+ children: [
2489
+ /* @__PURE__ */ jsxs44("header", { className: "fds-drawer__header", children: [
2490
+ /* @__PURE__ */ jsxs44("div", { className: "fds-drawer__heading", children: [
2491
+ /* @__PURE__ */ jsx53("h2", { id: titleId, className: "fds-drawer__title", children: title }),
2492
+ description != null && /* @__PURE__ */ jsx53("p", { id: descriptionId, className: "fds-drawer__description", children: description })
2493
+ ] }),
2494
+ /* @__PURE__ */ jsx53("button", { type: "button", className: "fds-drawer__close", onClick: onClose, disabled: !dismissible, "aria-label": "Close", children: /* @__PURE__ */ jsx53(X3, { "aria-hidden": "true" }) })
2495
+ ] }),
2496
+ /* @__PURE__ */ jsx53("div", { className: "fds-drawer__body", children }),
2497
+ footer != null && /* @__PURE__ */ jsx53("footer", { className: "fds-drawer__footer", children: footer })
2498
+ ]
2499
+ }
2500
+ )
2501
+ }
2502
+ ),
2503
+ document.body
2504
+ );
2505
+ }
2506
+
2507
+ // src/components/ResourceCard/ResourceCard.tsx
2508
+ import { jsx as jsx54, jsxs as jsxs45 } from "react/jsx-runtime";
2509
+ function ResourceCard({ icon, title, badge, meta, stats, action, variant = "default", className, ...rest }) {
2510
+ return /* @__PURE__ */ jsxs45("div", { className: ["fds-resource-card", `fds-resource-card--${variant}`, className].filter(Boolean).join(" "), ...rest, children: [
2511
+ /* @__PURE__ */ jsxs45("div", { className: "fds-resource-card__main", children: [
2512
+ /* @__PURE__ */ jsxs45("div", { className: "fds-resource-card__title", children: [
2513
+ icon != null && /* @__PURE__ */ jsx54("span", { className: "fds-resource-card__icon", "aria-hidden": "true", children: icon }),
2514
+ /* @__PURE__ */ jsx54("span", { children: title }),
2515
+ badge
2516
+ ] }),
2517
+ meta?.map((line, i) => /* @__PURE__ */ jsx54("div", { className: "fds-resource-card__meta", children: line }, i))
2518
+ ] }),
2519
+ stats && stats.length > 0 && /* @__PURE__ */ jsx54("dl", { className: "fds-resource-card__stats", children: stats.map((s, i) => /* @__PURE__ */ jsxs45("div", { className: "fds-resource-card__stat", children: [
2520
+ /* @__PURE__ */ jsx54("dt", { children: s.label }),
2521
+ /* @__PURE__ */ jsx54("dd", { children: s.value })
2522
+ ] }, i)) }),
2523
+ action != null && /* @__PURE__ */ jsx54("div", { className: "fds-resource-card__action", children: action })
2322
2524
  ] });
2323
2525
  }
2526
+
2527
+ // src/components/PageSkeleton/PageSkeleton.tsx
2528
+ import { jsx as jsx55, jsxs as jsxs46 } from "react/jsx-runtime";
2529
+ function PageSkeletonRoot({ label = "Loading", children }) {
2530
+ return /* @__PURE__ */ jsx55(SkeletonGroup, { label, className: "fds-page-skeleton", children });
2531
+ }
2532
+ function PageSkeletonHeader({ title, description, breadcrumb, action, tabs = 0 }) {
2533
+ return /* @__PURE__ */ jsx55(
2534
+ PageHeader,
2535
+ {
2536
+ breadcrumb: breadcrumb ? /* @__PURE__ */ jsx55(Skeleton, { shape: "text", width: 140 }) : void 0,
2537
+ title: title ?? /* @__PURE__ */ jsx55(Skeleton, { width: 220, height: 28 }),
2538
+ description: description === true ? /* @__PURE__ */ jsx55(Skeleton, { shape: "text", width: 320 }) : description || void 0,
2539
+ actions: action ? /* @__PURE__ */ jsx55(Skeleton, { width: 128, height: 36 }) : void 0,
2540
+ children: tabs > 0 && /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__tabs", children: Array.from({ length: tabs }, (_, i) => /* @__PURE__ */ jsx55(Skeleton, { shape: "text", width: 80 }, i)) })
2541
+ }
2542
+ );
2543
+ }
2544
+ function PageSkeletonToolbar({ filters = 2 }) {
2545
+ return /* @__PURE__ */ jsxs46("div", { className: "fds-page-skeleton__toolbar", children: [
2546
+ /* @__PURE__ */ jsx55(Skeleton, { width: 280, height: 36 }),
2547
+ Array.from({ length: filters }, (_, i) => /* @__PURE__ */ jsx55(Skeleton, { width: 140, height: 36 }, i))
2548
+ ] });
2549
+ }
2550
+ function PageSkeletonTable({ rows = 5, columns = 5 }) {
2551
+ const cells = (key, width) => Array.from({ length: columns }, (_, c) => /* @__PURE__ */ jsx55(Skeleton, { shape: "text", width: c === 0 ? "60%" : width }, `${key}-${c}`));
2552
+ return /* @__PURE__ */ jsxs46("div", { className: "fds-page-skeleton__table", style: { ["--fds-page-skeleton-columns"]: columns }, children: [
2553
+ /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__row fds-page-skeleton__row--head", children: cells("h", "40%") }),
2554
+ Array.from({ length: rows }, (_, r) => /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__row", children: cells(`r${r}`, "50%") }, r))
2555
+ ] });
2556
+ }
2557
+ function PageSkeletonCards({ count = 3, height = 120, columns = 3 }) {
2558
+ return /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__cards", style: { ["--fds-page-skeleton-columns"]: columns }, children: Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx55(Skeleton, { height, className: "fds-page-skeleton__card" }, i)) });
2559
+ }
2560
+ function PageSkeletonForm({ fields = 3 }) {
2561
+ return /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__form", children: Array.from({ length: fields }, (_, i) => /* @__PURE__ */ jsxs46("div", { className: "fds-page-skeleton__field", children: [
2562
+ /* @__PURE__ */ jsx55(Skeleton, { shape: "text", width: 120 }),
2563
+ /* @__PURE__ */ jsx55(Skeleton, { height: 36 })
2564
+ ] }, i)) });
2565
+ }
2566
+ function PageSkeletonSplit({ children, aside }) {
2567
+ return /* @__PURE__ */ jsxs46("div", { className: "fds-page-skeleton__split", children: [
2568
+ /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__main", children }),
2569
+ /* @__PURE__ */ jsx55("div", { className: "fds-page-skeleton__aside", children: aside })
2570
+ ] });
2571
+ }
2572
+ var PageSkeleton = Object.assign(PageSkeletonRoot, {
2573
+ Header: PageSkeletonHeader,
2574
+ Toolbar: PageSkeletonToolbar,
2575
+ Table: PageSkeletonTable,
2576
+ Cards: PageSkeletonCards,
2577
+ Form: PageSkeletonForm,
2578
+ Split: PageSkeletonSplit
2579
+ });
2324
2580
  export {
2325
2581
  Accordion,
2326
2582
  AppLayout,
@@ -2334,9 +2590,11 @@ export {
2334
2590
  Callout,
2335
2591
  Card,
2336
2592
  Checkbox,
2593
+ Checklist,
2337
2594
  DiffPropertyList,
2338
2595
  DiffSection,
2339
2596
  Divider,
2597
+ Drawer,
2340
2598
  EmptyState,
2341
2599
  IconButton,
2342
2600
  Input,
@@ -2345,11 +2603,16 @@ export {
2345
2603
  MismatchCard,
2346
2604
  Modal,
2347
2605
  MultiSelect,
2606
+ NumberedSteps,
2607
+ OptionList,
2608
+ OptionRow,
2348
2609
  PageHeader,
2610
+ PageSkeleton,
2349
2611
  Pagination,
2350
2612
  PricingCard,
2351
2613
  Radio,
2352
2614
  RadioCard,
2615
+ ResourceCard,
2353
2616
  SearchInput,
2354
2617
  SectionHeader,
2355
2618
  SegmentedControl,
@@ -2365,6 +2628,7 @@ export {
2365
2628
  Stat,
2366
2629
  StatusDot,
2367
2630
  StepList,
2631
+ Stepper,
2368
2632
  Swatch,
2369
2633
  TabNav,
2370
2634
  Table,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefidel/design-system",
3
- "version": "0.25.1",
3
+ "version": "0.26.0",
4
4
  "description": "Fidel brand design tokens + React component library — DTCG token source of truth, generated per-surface CSS + Tailwind-v4 parser-compatibility output, and on-brand React components (Button, MismatchCard, DiffSection).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",