@bmsuisse/ui 0.12.0 → 0.13.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.d.ts CHANGED
@@ -836,6 +836,52 @@ declare function SidebarNav({ children, className, ...rest }: SidebarNavProps):
836
836
  */
837
837
  declare function useSidebarCollapsed(): boolean;
838
838
 
839
+ /** The minimal shape this component needs to render one chip in the stepper. */
840
+ interface StepperStep {
841
+ /** 1-based step number, also used as the React key and navigation target. */
842
+ n: number;
843
+ /** Visible label under the chip. */
844
+ label: string;
845
+ /** Small uppercase caption under the label (e.g. a phase/section name). */
846
+ phase: string;
847
+ }
848
+ interface StepperProps {
849
+ /** The current step number (1-based, matches a `StepperStep.n`). */
850
+ step: number;
851
+ /** Highest step number reachable so far -- steps beyond this aren't clickable. */
852
+ maxStep: number;
853
+ /** Called with a step's `n` when a navigable chip is clicked. */
854
+ onNavigate: (n: number) => void;
855
+ /** Called when the trailing "new" button is clicked. Omit to hide that button entirely. */
856
+ onNew?: () => void;
857
+ /** The steps to render, in order. */
858
+ steps: StepperStep[];
859
+ /** Accessible label for the stepper's `<nav>`. @default "Steps" */
860
+ navLabel?: string;
861
+ /** Visible text and title of the trailing `onNew` button. Only relevant when `onNew` is passed. @default "New" */
862
+ newLabel?: string;
863
+ /** `data-testid` for the horizontally-scrolling steps region. @default "stepper-scroll" */
864
+ scrollTestId?: string;
865
+ /** `data-testid` for the trailing `onNew` button, when rendered. */
866
+ newTestId?: string;
867
+ }
868
+ /**
869
+ * Numbered-chip wizard progress indicator: a horizontally-scrolling row of
870
+ * step chips (done/active/upcoming, connected by a line that fills in as
871
+ * steps complete) plus an optional trailing "start over" button. Replaces
872
+ * the same shape hand-rolled independently by more than one multi-step
873
+ * wizard.
874
+ *
875
+ * Note: the original OneSales `Stepper` this was ported from also supported
876
+ * a one-off `tinderSubStep` prop that injected a bespoke "matcher" chip
877
+ * between two specific steps for a single screen's own sub-flow. That was
878
+ * deliberately left out of this generic version -- it doesn't generalize
879
+ * meaningfully beyond that one screen. Don't re-add it here; a consumer
880
+ * that needs a one-off extra chip should compose its own around this
881
+ * component instead.
882
+ */
883
+ declare function Stepper({ step, maxStep, onNavigate, onNew, steps, navLabel, newLabel, scrollTestId, newTestId, }: StepperProps): react.JSX.Element;
884
+
839
885
  /** Merges conditional class names, then dedupes conflicting Tailwind utility classes. */
840
886
  declare function cn(...inputs: ClassValue[]): string;
841
887
 
@@ -845,4 +891,4 @@ declare function cn(...inputs: ClassValue[]): string;
845
891
  */
846
892
  declare function useMediaQuery(query: string): boolean;
847
893
 
848
- export { AlertBox, type AlertBoxProps, type AlertBoxVariant, Badge, type BadgeProps, Button, ButtonGroup, type ButtonGroupOption, type ButtonGroupProps, type ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Combobox, type GridColumn as ComboboxColumn, type ComboboxMultiProps, type ComboboxOption, type ComboboxProps, type ComboboxSingleProps, ConfirmDialog, type ConfirmDialogProps, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DonutChart, type DonutSegment, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FormField, type FormFieldProps, FormModal, type FormModalProps, Input, type InputProps, KpiCard, type KpiCardProps, Label, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, Modal, type ModalProps, NavGroup, type NavGroupProps, type NavIconProps, NavItem, type NavItemProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ResponsivePanel, type ResponsivePanelProps, type ResponsivePanelSize, ScrollArea, ScrollBar, SearchBar, type SearchBarProps, SearchPanel, type SearchPanelMode, type SearchPanelProps, SearchTrigger, type SearchTriggerProps, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarNav, type SidebarNavProps, type SidebarProps, Skeleton, Sparkline, StatusBadge, type StatusBadgeProps, type StatusTone, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagCombobox, type TagComboboxOption, type TagComboboxProps, Textarea, type TextareaProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, cn, loadingSpinnerIconVariants, sheetVariants, useMediaQuery, useSidebarCollapsed };
894
+ export { AlertBox, type AlertBoxProps, type AlertBoxVariant, Badge, type BadgeProps, Button, ButtonGroup, type ButtonGroupOption, type ButtonGroupProps, type ButtonProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, Combobox, type GridColumn as ComboboxColumn, type ComboboxMultiProps, type ComboboxOption, type ComboboxProps, type ComboboxSingleProps, ConfirmDialog, type ConfirmDialogProps, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, DonutChart, type DonutSegment, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FormField, type FormFieldProps, FormModal, type FormModalProps, Input, type InputProps, KpiCard, type KpiCardProps, Label, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, Modal, type ModalProps, NavGroup, type NavGroupProps, type NavIconProps, NavItem, type NavItemProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ResponsivePanel, type ResponsivePanelProps, type ResponsivePanelSize, ScrollArea, ScrollBar, SearchBar, type SearchBarProps, SearchPanel, type SearchPanelMode, type SearchPanelProps, SearchTrigger, type SearchTriggerProps, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, Sheet, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarNav, type SidebarNavProps, type SidebarProps, Skeleton, Sparkline, StatusBadge, type StatusBadgeProps, type StatusTone, Stepper, type StepperProps, type StepperStep, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, TagCombobox, type TagComboboxOption, type TagComboboxProps, Textarea, type TextareaProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeVariants, buttonVariants, cn, loadingSpinnerIconVariants, sheetVariants, useMediaQuery, useSidebarCollapsed };
package/dist/index.js CHANGED
@@ -2609,6 +2609,112 @@ function SidebarNav({ children, className, ...rest }) {
2609
2609
  )
2610
2610
  ] });
2611
2611
  }
2612
+
2613
+ // src/patterns/stepper/Stepper.tsx
2614
+ import { useEffect as useEffect6, useRef as useRef6 } from "react";
2615
+ import { Check as Check5, Plus } from "lucide-react";
2616
+ import { jsx as jsx39, jsxs as jsxs23 } from "react/jsx-runtime";
2617
+ function Stepper({
2618
+ step,
2619
+ maxStep,
2620
+ onNavigate,
2621
+ onNew,
2622
+ steps,
2623
+ navLabel = "Steps",
2624
+ newLabel = "New",
2625
+ scrollTestId = "stepper-scroll",
2626
+ newTestId
2627
+ }) {
2628
+ const stepRefs = useRef6(/* @__PURE__ */ new Map());
2629
+ useEffect6(() => {
2630
+ const activeStep = stepRefs.current.get(step);
2631
+ activeStep?.scrollIntoView({ block: "nearest", inline: "center" });
2632
+ }, [step]);
2633
+ return (
2634
+ // onNew is pinned outside the horizontally-scrolling region below (a sibling of
2635
+ // it, not a child) so its own edge never scrolls off-screen along with the
2636
+ // later steps once the scroller's min-width doesn't fit the viewport.
2637
+ /* @__PURE__ */ jsxs23("div", { className: "flex w-full shrink-0 items-center gap-2", children: [
2638
+ /* @__PURE__ */ jsx39("nav", { "aria-label": navLabel, className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx39(
2639
+ "div",
2640
+ {
2641
+ "data-testid": scrollTestId,
2642
+ className: "flex w-full items-center gap-0 overflow-x-auto px-2 py-1",
2643
+ children: /* @__PURE__ */ jsx39("ol", { className: "flex min-w-[700px] flex-1 items-start", children: steps.map(({ n, label, phase }, i) => {
2644
+ const done = step > n;
2645
+ const active = step === n;
2646
+ const navigable = n <= maxStep && n !== step;
2647
+ const last = i === steps.length - 1;
2648
+ return /* @__PURE__ */ jsxs23("li", { className: cn("flex items-start", !last && "flex-1"), children: [
2649
+ /* @__PURE__ */ jsxs23(
2650
+ "button",
2651
+ {
2652
+ ref: (element) => {
2653
+ if (element) stepRefs.current.set(n, element);
2654
+ else stepRefs.current.delete(n);
2655
+ },
2656
+ "data-testid": `step-${n}`,
2657
+ "aria-disabled": !navigable,
2658
+ "aria-current": active ? "step" : void 0,
2659
+ onClick: () => navigable && onNavigate(n),
2660
+ className: cn(
2661
+ "flex min-w-[68px] flex-col items-center gap-0.5 transition-opacity",
2662
+ navigable ? "cursor-pointer hover:opacity-80" : "cursor-default"
2663
+ ),
2664
+ children: [
2665
+ /* @__PURE__ */ jsx39(
2666
+ "div",
2667
+ {
2668
+ className: cn(
2669
+ "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold transition-colors",
2670
+ done ? "bg-primary/15 text-primary" : active ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground"
2671
+ ),
2672
+ children: done ? /* @__PURE__ */ jsx39(Check5, { className: "h-3 w-3" }) : n
2673
+ }
2674
+ ),
2675
+ /* @__PURE__ */ jsx39(
2676
+ "span",
2677
+ {
2678
+ className: cn(
2679
+ "text-center whitespace-nowrap transition-colors",
2680
+ active ? "text-[12px] font-semibold text-foreground" : done ? "text-[12px] font-medium text-primary" : "text-[12px] font-medium text-muted-foreground"
2681
+ ),
2682
+ children: label
2683
+ }
2684
+ ),
2685
+ /* @__PURE__ */ jsx39("span", { className: "text-[9px] tracking-[0.5px] text-muted-foreground/50 uppercase", children: phase })
2686
+ ]
2687
+ }
2688
+ ),
2689
+ !last && /* @__PURE__ */ jsx39(
2690
+ "div",
2691
+ {
2692
+ className: cn(
2693
+ "mx-1.5 mt-3.5 h-px flex-1 transition-colors",
2694
+ done ? "bg-primary" : "bg-border"
2695
+ )
2696
+ }
2697
+ )
2698
+ ] }, n);
2699
+ }) })
2700
+ }
2701
+ ) }),
2702
+ onNew && /* @__PURE__ */ jsxs23(
2703
+ "button",
2704
+ {
2705
+ "data-testid": newTestId,
2706
+ onClick: onNew,
2707
+ title: newLabel,
2708
+ className: "flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-1.5 text-[12px] font-semibold text-foreground transition-colors hover:bg-muted/50",
2709
+ children: [
2710
+ /* @__PURE__ */ jsx39(Plus, { className: "h-3.5 w-3.5" }),
2711
+ newLabel
2712
+ ]
2713
+ }
2714
+ )
2715
+ ] })
2716
+ );
2717
+ }
2612
2718
  export {
2613
2719
  AlertBox,
2614
2720
  Badge,
@@ -2687,6 +2793,7 @@ export {
2687
2793
  Skeleton,
2688
2794
  Sparkline,
2689
2795
  StatusBadge,
2796
+ Stepper,
2690
2797
  Switch,
2691
2798
  Table,
2692
2799
  TableBody,