sangam-ui 1.0.0 → 1.0.1

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
@@ -1585,21 +1585,27 @@ declare const PageFooter: React.ForwardRefExoticComponent<PageFooterProps & Reac
1585
1585
  *
1586
1586
  * Logo 36×28. Text: 12px, weight 500, line-height 16px.
1587
1587
  */
1588
- interface SideMenuItem {
1588
+ /**
1589
+ * Data for one row in {@link SideMenu} `topItems` / `bottomItems`.
1590
+ * Each entry is rendered exclusively with {@link SideMenuItem} (Dashboard, Orders, Projects, Search, Settings, Profile, etc.).
1591
+ */
1592
+ interface SideMenuNavItem {
1589
1593
  id: string;
1590
1594
  label: string;
1591
1595
  /** Icon for collapsed state (and expanded when iconExpanded not provided) */
1592
1596
  icon: React.ReactNode;
1593
1597
  /** Icon for expanded state. Use when icon needs different styling on white bg (e.g. Profile/avtarimg). */
1594
1598
  iconExpanded?: React.ReactNode;
1599
+ /** When the menu is expanded, show a trailing chevron (submenu affordance). */
1600
+ hasSubmenu?: boolean;
1595
1601
  }
1596
1602
  interface SideMenuProps extends Omit<React.HTMLAttributes<HTMLElement>, "children">, VariantProps<typeof sideMenuVariants> {
1597
1603
  /** Logo element (e.g. img 36×28) */
1598
1604
  logo: React.ReactNode;
1599
1605
  /** Top nav items: Dashboard, Orders, Projects */
1600
- topItems: SideMenuItem[];
1606
+ topItems: SideMenuNavItem[];
1601
1607
  /** Bottom nav items: Search, Settings, Profile */
1602
- bottomItems: SideMenuItem[];
1608
+ bottomItems: SideMenuNavItem[];
1603
1609
  /** ID of currently selected item (controlled). Omit for uncontrolled; use defaultSelectedId for initial. */
1604
1610
  selectedId?: string;
1605
1611
  /** Initial selected ID when uncontrolled. Ignored if selectedId is provided. */
@@ -1625,6 +1631,29 @@ declare const sideMenuVariants: (props?: ({
1625
1631
  } & class_variance_authority_dist_types.ClassProp) | undefined) => string;
1626
1632
  declare const SideMenu: React.ForwardRefExoticComponent<SideMenuProps & React.RefAttributes<HTMLElement>>;
1627
1633
 
1634
+ /**
1635
+ * Single row for {@link SideMenu}: leading icon, optional label, optional submenu chevron.
1636
+ * Use inside `SideMenu` via `topItems` / `bottomItems`, or alone for layout/testing.
1637
+ */
1638
+ interface SideMenuItemProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
1639
+ /** Visible label (hidden when `iconOnly` is true). */
1640
+ label: string;
1641
+ /** Leading icon, typically from `@esds-sangam/icons`. Parent picks collapsed vs expanded asset. */
1642
+ leadingIcon: React.ReactNode;
1643
+ /** When true, only the icon is shown (collapsed rail / design “icon only”). */
1644
+ iconOnly?: boolean;
1645
+ /** When true and not `iconOnly`, shows a trailing chevron (submenu affordance). */
1646
+ hasSubmenu?: boolean;
1647
+ /** Selected / active row styling. */
1648
+ selected?: boolean;
1649
+ /**
1650
+ * Applies hover surface without a pointer (e.g. Storybook / design previews).
1651
+ * Ignored when `selected` is true.
1652
+ */
1653
+ hovered?: boolean;
1654
+ }
1655
+ declare const SideMenuItem: React.ForwardRefExoticComponent<SideMenuItemProps & React.RefAttributes<HTMLButtonElement>>;
1656
+
1628
1657
  /**
1629
1658
  * Upload Pattern – Stage 1: File uploader
1630
1659
  *
@@ -1697,4 +1726,4 @@ type Size = "sm" | "md" | "lg";
1697
1726
  type Variant = "primary" | "secondary" | "outline" | "ghost";
1698
1727
  type ColorScheme = "primary" | "secondary" | "success" | "error" | "warning" | "info";
1699
1728
 
1700
- export { Avatar, Badge, type BaseComponentProps, Button, Card, Checkbox, Chip, type ColorScheme, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerHeaderTop, DrawerSurface, DrawerTitle, DrawerTrigger, Dropdown, DropdownMulti, type DropdownMultiProps, type DropdownOption, type DropdownProps, Input, Label, Loader, Menu, MenuContent, MenuItem, MenuMenu, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, PageFooter, type PageFooterAction, type PageFooterProps, PageHeader, type PageHeaderAction, type PageHeaderProps, type PageHeaderTab, Pagination, Popup, PopupContent, PopupTrigger, ProgressBar, Radio, RadioGroup, SearchField, SideMenu, type SideMenuItem, type SideMenuProps, type Size, Skeleton, Stepper, type StepperProps, type StepperStep, type StepperStepVariant, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsRoot, TabsTrigger, type TabsTriggerOption, type TabsTriggerProps, Textarea, Toast, type ToastEntryOptions, ToastProvider, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Upload, UploadFileItem, type UploadFileItemProps, type UploadFileItemStatus, type UploadProps, type Variant, avatarVariants, badgeVariants, buttonVariants, cardVariants, checkboxRootVariants as checkboxVariants, chipVariants, dropdownContentVariants, dropdownItemVariants, dropdownTriggerVariants, inputVariants, loaderVariants, pageHeaderVariants, radioVariants, searchFieldVariants, sideMenuVariants, skeletonVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, toastVariants, toggleVariants, tooltipContentVariants, uploadBoxVariants, uploadFileItemBoxVariants, useToast };
1729
+ export { Avatar, Badge, type BaseComponentProps, Button, Card, Checkbox, Chip, type ColorScheme, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerHeaderTop, DrawerSurface, DrawerTitle, DrawerTrigger, Dropdown, DropdownMulti, type DropdownMultiProps, type DropdownOption, type DropdownProps, Input, Label, Loader, Menu, MenuContent, MenuItem, MenuMenu, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, PageFooter, type PageFooterAction, type PageFooterProps, PageHeader, type PageHeaderAction, type PageHeaderProps, type PageHeaderTab, Pagination, Popup, PopupContent, PopupTrigger, ProgressBar, Radio, RadioGroup, SearchField, SideMenu, SideMenuItem, type SideMenuItemProps, type SideMenuNavItem, type SideMenuProps, type Size, Skeleton, Stepper, type StepperProps, type StepperStep, type StepperStepVariant, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsRoot, TabsTrigger, type TabsTriggerOption, type TabsTriggerProps, Textarea, Toast, type ToastEntryOptions, ToastProvider, Toggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Upload, UploadFileItem, type UploadFileItemProps, type UploadFileItemStatus, type UploadProps, type Variant, avatarVariants, badgeVariants, buttonVariants, cardVariants, checkboxRootVariants as checkboxVariants, chipVariants, dropdownContentVariants, dropdownItemVariants, dropdownTriggerVariants, inputVariants, loaderVariants, pageHeaderVariants, radioVariants, searchFieldVariants, sideMenuVariants, skeletonVariants, tabsListVariants, tabsTriggerVariants, textareaVariants, toastVariants, toggleVariants, tooltipContentVariants, uploadBoxVariants, uploadFileItemBoxVariants, useToast };
package/dist/index.js CHANGED
@@ -3474,12 +3474,113 @@ var PageFooter = React26.forwardRef(
3474
3474
  PageFooter.displayName = "PageFooter";
3475
3475
 
3476
3476
  // src/patterns/SideMenu.tsx
3477
- import * as React27 from "react";
3477
+ import * as React28 from "react";
3478
3478
  import { cva as cva19 } from "class-variance-authority";
3479
- import { cn as cn27 } from "@esds-sangam/utils";
3479
+ import { cn as cn28 } from "@esds-sangam/utils";
3480
3480
  import * as SelectPrimitive2 from "@radix-ui/react-select";
3481
3481
  import { ChevronDown as ChevronDown3, ChevronUp as ChevronUp2, Tickmark as Tickmark4 } from "@esds-sangam/icons";
3482
- import { Fragment as Fragment4, jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
3482
+
3483
+ // src/patterns/SideMenuItem.tsx
3484
+ import * as React27 from "react";
3485
+ import { ChevronRight as ChevronRight3 } from "@esds-sangam/icons";
3486
+ import { cn as cn27 } from "@esds-sangam/utils";
3487
+ import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
3488
+ var MENU_TEXT_STYLES = "text-xs font-medium leading-4 text-semantic-text-neutral-primary";
3489
+ var SideMenuItem = React27.forwardRef(
3490
+ ({
3491
+ label,
3492
+ leadingIcon,
3493
+ iconOnly = false,
3494
+ hasSubmenu = false,
3495
+ selected = false,
3496
+ hovered = false,
3497
+ className,
3498
+ type = "button",
3499
+ ...props
3500
+ }, ref) => {
3501
+ if (iconOnly) {
3502
+ return /* @__PURE__ */ jsx27(
3503
+ "button",
3504
+ {
3505
+ ref,
3506
+ type,
3507
+ className: cn27(
3508
+ "inline-flex w-full items-center justify-center outline-none focus-visible:ring-2 focus-visible:ring-primary-600 focus-visible:ring-offset-2",
3509
+ className
3510
+ ),
3511
+ ...props,
3512
+ children: /* @__PURE__ */ jsx27(
3513
+ "span",
3514
+ {
3515
+ className: cn27(
3516
+ "flex h-9 w-9 items-center justify-center rounded-sm [&>svg]:size-5",
3517
+ selected && "border border-semantic-border-neutral-secondary bg-semantic-background-neutral-primary shadow-elevation-bottom-sm"
3518
+ ),
3519
+ children: leadingIcon
3520
+ }
3521
+ )
3522
+ }
3523
+ );
3524
+ }
3525
+ return /* @__PURE__ */ jsx27(
3526
+ "button",
3527
+ {
3528
+ ref,
3529
+ type,
3530
+ className: cn27(
3531
+ "inline-flex w-full items-center justify-start outline-none focus-visible:ring-2 focus-visible:ring-primary-600 focus-visible:ring-offset-2",
3532
+ className
3533
+ ),
3534
+ ...props,
3535
+ children: /* @__PURE__ */ jsxs21(
3536
+ "span",
3537
+ {
3538
+ className: cn27(
3539
+ "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-sm px-2",
3540
+ selected ? "mx-1 my-0.5 border border-semantic-border-neutral-secondary bg-semantic-background-neutral-primary shadow-elevation-bottom-sm" : "hover:bg-neutral-200/60",
3541
+ !selected && hovered && "bg-neutral-200/60"
3542
+ ),
3543
+ children: [
3544
+ /* @__PURE__ */ jsx27("span", { className: "shrink-0 [&>svg]:size-5", children: leadingIcon }),
3545
+ /* @__PURE__ */ jsx27("span", { className: cn27(MENU_TEXT_STYLES, "min-w-0 flex-1 truncate text-left"), children: label }),
3546
+ hasSubmenu ? /* @__PURE__ */ jsx27(
3547
+ ChevronRight3,
3548
+ {
3549
+ size: 14,
3550
+ className: "shrink-0 text-semantic-icon-neutral-tertiary",
3551
+ "aria-hidden": true
3552
+ }
3553
+ ) : null
3554
+ ]
3555
+ }
3556
+ )
3557
+ }
3558
+ );
3559
+ }
3560
+ );
3561
+ SideMenuItem.displayName = "SideMenuItem";
3562
+
3563
+ // src/patterns/SideMenu.tsx
3564
+ import { Fragment as Fragment4, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
3565
+ function SideMenuNavRow({
3566
+ item,
3567
+ isCollapsed,
3568
+ isSelected,
3569
+ onClick
3570
+ }) {
3571
+ const leadingIcon = isCollapsed && !isSelected ? item.icon : item.iconExpanded ?? item.icon;
3572
+ return /* @__PURE__ */ jsx28(
3573
+ SideMenuItem,
3574
+ {
3575
+ label: item.label,
3576
+ leadingIcon,
3577
+ iconOnly: isCollapsed,
3578
+ hasSubmenu: item.hasSubmenu ?? false,
3579
+ selected: isSelected,
3580
+ onClick
3581
+ }
3582
+ );
3583
+ }
3483
3584
  var sideMenuVariants = cva19(
3484
3585
  "flex flex-col self-start transition-[width] duration-200 ease-out",
3485
3586
  {
@@ -3496,8 +3597,7 @@ var sideMenuVariants = cva19(
3496
3597
  }
3497
3598
  }
3498
3599
  );
3499
- var MENU_TEXT_STYLES = "text-xs font-medium leading-4 text-semantic-text-neutral-primary";
3500
- var SideMenu = React27.forwardRef(
3600
+ var SideMenu = React28.forwardRef(
3501
3601
  ({
3502
3602
  className,
3503
3603
  variant = "default",
@@ -3516,17 +3616,17 @@ var SideMenu = React27.forwardRef(
3516
3616
  onMouseLeave,
3517
3617
  ...props
3518
3618
  }, ref) => {
3519
- const [internalSelected, setInternalSelected] = React27.useState(
3619
+ const [internalSelected, setInternalSelected] = React28.useState(
3520
3620
  defaultSelectedId ?? null
3521
3621
  );
3522
3622
  const selectedId = selectedIdProp !== void 0 ? selectedIdProp : internalSelected;
3523
3623
  const isControlled = selectedIdProp !== void 0;
3524
- const [hoverExpanded, setHoverExpanded] = React27.useState(false);
3624
+ const [hoverExpanded, setHoverExpanded] = React28.useState(false);
3525
3625
  const isUncontrolledDefault = variant === "default" && expandedProp === void 0;
3526
3626
  const isExpandedByHover = isUncontrolledDefault && hoverExpanded;
3527
3627
  const effectiveExpanded = variant === "hover" || variant === "selected" || variant === "sticky" || isExpandedByHover;
3528
3628
  const isCollapsed = !effectiveExpanded;
3529
- const [isProjectOpen, setIsProjectOpen] = React27.useState(false);
3629
+ const [isProjectOpen, setIsProjectOpen] = React28.useState(false);
3530
3630
  const handleMouseEnter = (e) => {
3531
3631
  if (isUncontrolledDefault) setHoverExpanded(true);
3532
3632
  onMouseEnter?.(e);
@@ -3544,7 +3644,7 @@ var SideMenu = React27.forwardRef(
3544
3644
  { value: "project-2", label: "Project 2" },
3545
3645
  { value: "project-3", label: "Project 3" }
3546
3646
  ];
3547
- const [internalProject, setInternalProject] = React27.useState(
3647
+ const [internalProject, setInternalProject] = React28.useState(
3548
3648
  defaultProject ?? projectOptions[0]?.value ?? "project-1"
3549
3649
  );
3550
3650
  const currentProject = projectProp !== void 0 ? projectProp : internalProject;
@@ -3552,18 +3652,18 @@ var SideMenu = React27.forwardRef(
3552
3652
  if (projectProp === void 0) setInternalProject(value);
3553
3653
  onProjectChange?.(value);
3554
3654
  };
3555
- return /* @__PURE__ */ jsx27(
3655
+ return /* @__PURE__ */ jsx28(
3556
3656
  "div",
3557
3657
  {
3558
- className: cn27("relative w-12 shrink-0 overflow-visible", className),
3658
+ className: cn28("relative w-12 shrink-0 overflow-visible", className),
3559
3659
  ...props,
3560
- children: /* @__PURE__ */ jsx27(
3660
+ children: /* @__PURE__ */ jsx28(
3561
3661
  "div",
3562
3662
  {
3563
3663
  className: "absolute left-0 top-0",
3564
3664
  onMouseEnter: handleMouseEnter,
3565
3665
  onMouseLeave: handleMouseLeave,
3566
- children: /* @__PURE__ */ jsxs21(
3666
+ children: /* @__PURE__ */ jsxs22(
3567
3667
  "nav",
3568
3668
  {
3569
3669
  ref,
@@ -3574,17 +3674,17 @@ var SideMenu = React27.forwardRef(
3574
3674
  variant: isExpandedByHover && selectedId ? "selected" : isExpandedByHover ? "hover" : variant
3575
3675
  }),
3576
3676
  children: [
3577
- /* @__PURE__ */ jsx27(
3677
+ /* @__PURE__ */ jsx28(
3578
3678
  "div",
3579
3679
  {
3580
- className: cn27(
3680
+ className: cn28(
3581
3681
  "mb-4 shrink-0 flex items-center",
3582
3682
  isCollapsed ? "justify-center" : "justify-start"
3583
3683
  ),
3584
3684
  children: logo
3585
3685
  }
3586
3686
  ),
3587
- /* @__PURE__ */ jsx27("div", { className: cn27("mb-4 shrink-0", isCollapsed ? "flex justify-center" : ""), children: isCollapsed ? /* @__PURE__ */ jsx27("div", { className: "flex h-9 w-9 items-center justify-center rounded-sm", children: /* @__PURE__ */ jsx27("span", { className: "inline-flex h-6 w-6 items-center justify-center rounded-[4px] bg-blue-300 text-sm font-semibold leading-6 text-blue-600", children: "P" }) }) : /* @__PURE__ */ jsx27(
3687
+ /* @__PURE__ */ jsx28("div", { className: cn28("mb-4 shrink-0", isCollapsed ? "flex justify-center" : ""), children: isCollapsed ? /* @__PURE__ */ jsx28("div", { className: "flex h-9 w-9 items-center justify-center rounded-sm", children: /* @__PURE__ */ jsx28("span", { className: "inline-flex h-6 w-6 items-center justify-center rounded-[4px] bg-blue-300 text-sm font-semibold leading-6 text-blue-600", children: "P" }) }) : /* @__PURE__ */ jsx28(
3588
3688
  SelectPrimitive2.Root,
3589
3689
  {
3590
3690
  value: currentProject,
@@ -3594,12 +3694,12 @@ var SideMenu = React27.forwardRef(
3594
3694
  setIsProjectOpen(open);
3595
3695
  if (isUncontrolledDefault && open) setHoverExpanded(true);
3596
3696
  },
3597
- children: /* @__PURE__ */ jsxs21("div", { className: "relative", children: [
3598
- /* @__PURE__ */ jsx27("span", { className: "pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 inline-flex h-6 w-6 items-center justify-center rounded-[4px] bg-blue-300 text-sm font-semibold leading-6 text-blue-600", children: "P" }),
3599
- /* @__PURE__ */ jsxs21(
3697
+ children: /* @__PURE__ */ jsxs22("div", { className: "relative", children: [
3698
+ /* @__PURE__ */ jsx28("span", { className: "pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 inline-flex h-6 w-6 items-center justify-center rounded-[4px] bg-blue-300 text-sm font-semibold leading-6 text-blue-600", children: "P" }),
3699
+ /* @__PURE__ */ jsxs22(
3600
3700
  SelectPrimitive2.Trigger,
3601
3701
  {
3602
- className: cn27(
3702
+ className: cn28(
3603
3703
  "group",
3604
3704
  dropdownTriggerVariants({ error: false }),
3605
3705
  // Make room for the P icon
@@ -3610,97 +3710,41 @@ var SideMenu = React27.forwardRef(
3610
3710
  "[&>span]:block [&>span]:min-w-0 [&>span]:truncate [&>span]:whitespace-nowrap"
3611
3711
  ),
3612
3712
  children: [
3613
- /* @__PURE__ */ jsx27(SelectPrimitive2.Value, { placeholder: "Project 1" }),
3614
- /* @__PURE__ */ jsx27(SelectPrimitive2.Icon, { asChild: true, children: /* @__PURE__ */ jsxs21(Fragment4, { children: [
3615
- /* @__PURE__ */ jsx27(ChevronDown3, { size: 14, className: "shrink-0 group-data-[state=open]:hidden" }),
3616
- /* @__PURE__ */ jsx27(ChevronUp2, { size: 14, className: "hidden shrink-0 group-data-[state=open]:block" })
3713
+ /* @__PURE__ */ jsx28(SelectPrimitive2.Value, { placeholder: "Project 1" }),
3714
+ /* @__PURE__ */ jsx28(SelectPrimitive2.Icon, { asChild: true, children: /* @__PURE__ */ jsxs22(Fragment4, { children: [
3715
+ /* @__PURE__ */ jsx28(ChevronDown3, { size: 14, className: "shrink-0 group-data-[state=open]:hidden" }),
3716
+ /* @__PURE__ */ jsx28(ChevronUp2, { size: 14, className: "hidden shrink-0 group-data-[state=open]:block" })
3617
3717
  ] }) })
3618
3718
  ]
3619
3719
  }
3620
3720
  ),
3621
- /* @__PURE__ */ jsx27(SelectPrimitive2.Portal, { children: /* @__PURE__ */ jsx27(SelectPrimitive2.Content, { className: cn27(dropdownContentVariants()), position: "popper", sideOffset: 6, children: /* @__PURE__ */ jsx27(SelectPrimitive2.Viewport, { children: projectOptions.map((opt) => /* @__PURE__ */ jsxs21(SelectPrimitive2.Item, { value: opt.value, disabled: opt.disabled, className: cn27(dropdownItemVariants()), children: [
3622
- /* @__PURE__ */ jsx27(SelectPrimitive2.ItemText, { children: opt.label }),
3623
- /* @__PURE__ */ jsx27(SelectPrimitive2.ItemIndicator, { className: "absolute right-2 inline-flex items-center justify-center", children: /* @__PURE__ */ jsx27(Tickmark4, { size: 14, "aria-hidden": "true" }) })
3721
+ /* @__PURE__ */ jsx28(SelectPrimitive2.Portal, { children: /* @__PURE__ */ jsx28(SelectPrimitive2.Content, { className: cn28(dropdownContentVariants()), position: "popper", sideOffset: 6, children: /* @__PURE__ */ jsx28(SelectPrimitive2.Viewport, { children: projectOptions.map((opt) => /* @__PURE__ */ jsxs22(SelectPrimitive2.Item, { value: opt.value, disabled: opt.disabled, className: cn28(dropdownItemVariants()), children: [
3722
+ /* @__PURE__ */ jsx28(SelectPrimitive2.ItemText, { children: opt.label }),
3723
+ /* @__PURE__ */ jsx28(SelectPrimitive2.ItemIndicator, { className: "absolute right-2 inline-flex items-center justify-center", children: /* @__PURE__ */ jsx28(Tickmark4, { size: 14, "aria-hidden": "true" }) })
3624
3724
  ] }, opt.value)) }) }) })
3625
3725
  ] })
3626
3726
  }
3627
3727
  ) }),
3628
- /* @__PURE__ */ jsx27("div", { className: "flex flex-1 flex-col gap-2", children: topItems.map((item) => {
3629
- const isSelected = selectedId === item.id;
3630
- const itemIcon = isCollapsed && !isSelected ? item.icon : item.iconExpanded ?? item.icon;
3631
- return /* @__PURE__ */ jsx27(
3632
- "button",
3633
- {
3634
- type: "button",
3635
- onClick: () => handleItemClick(item.id),
3636
- className: cn27(
3637
- "inline-flex w-full items-center outline-none focus-visible:ring-2 focus-visible:ring-primary-600 focus-visible:ring-offset-2",
3638
- isCollapsed ? "justify-center" : "justify-start"
3639
- ),
3640
- children: isCollapsed ? /* @__PURE__ */ jsx27(
3641
- "span",
3642
- {
3643
- className: cn27(
3644
- "flex h-9 w-9 items-center justify-center rounded-sm [&>svg]:size-5",
3645
- isSelected && "border border-semantic-border-neutral-secondary bg-semantic-background-neutral-primary shadow-elevation-bottom-sm"
3646
- ),
3647
- children: itemIcon
3648
- }
3649
- ) : /* @__PURE__ */ jsxs21(
3650
- "span",
3651
- {
3652
- className: cn27(
3653
- "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-sm px-2",
3654
- isSelected ? "mx-1 my-0.5 border border-semantic-border-neutral-secondary bg-semantic-background-neutral-primary shadow-elevation-bottom-sm" : "hover:bg-neutral-200/60"
3655
- ),
3656
- children: [
3657
- /* @__PURE__ */ jsx27("span", { className: "shrink-0 [&>svg]:size-5", children: itemIcon }),
3658
- /* @__PURE__ */ jsx27("span", { className: cn27(MENU_TEXT_STYLES, "truncate"), children: item.label })
3659
- ]
3660
- }
3661
- )
3662
- },
3663
- item.id
3664
- );
3665
- }) }),
3666
- /* @__PURE__ */ jsx27("div", { className: "flex flex-col gap-2 pt-4", children: bottomItems.map((item) => {
3667
- const isSelected = selectedId === item.id;
3668
- const itemIcon = isCollapsed && !isSelected ? item.icon : item.iconExpanded ?? item.icon;
3669
- return /* @__PURE__ */ jsx27(
3670
- "button",
3671
- {
3672
- type: "button",
3673
- onClick: () => handleItemClick(item.id),
3674
- className: cn27(
3675
- "inline-flex w-full items-center outline-none focus-visible:ring-2 focus-visible:ring-primary-600 focus-visible:ring-offset-2",
3676
- isCollapsed ? "justify-center" : "justify-start"
3677
- ),
3678
- children: isCollapsed ? /* @__PURE__ */ jsx27(
3679
- "span",
3680
- {
3681
- className: cn27(
3682
- "flex h-9 w-9 items-center justify-center rounded-sm [&>svg]:size-5",
3683
- isSelected && "border border-semantic-border-neutral-secondary bg-semantic-background-neutral-primary shadow-elevation-bottom-sm"
3684
- ),
3685
- children: itemIcon
3686
- }
3687
- ) : /* @__PURE__ */ jsxs21(
3688
- "span",
3689
- {
3690
- className: cn27(
3691
- "flex h-9 min-w-0 flex-1 items-center gap-2 rounded-sm px-2",
3692
- isSelected ? "mx-1 my-0.5 border border-semantic-border-neutral-secondary bg-semantic-background-neutral-primary shadow-elevation-bottom-sm" : "hover:bg-neutral-200/60"
3693
- ),
3694
- children: [
3695
- /* @__PURE__ */ jsx27("span", { className: "shrink-0 [&>svg]:size-5", children: itemIcon }),
3696
- /* @__PURE__ */ jsx27("span", { className: cn27(MENU_TEXT_STYLES, "truncate"), children: item.label })
3697
- ]
3698
- }
3699
- )
3700
- },
3701
- item.id
3702
- );
3703
- }) })
3728
+ /* @__PURE__ */ jsx28("div", { className: "flex flex-1 flex-col gap-2", children: topItems.map((item) => /* @__PURE__ */ jsx28(
3729
+ SideMenuNavRow,
3730
+ {
3731
+ item,
3732
+ isCollapsed,
3733
+ isSelected: selectedId === item.id,
3734
+ onClick: () => handleItemClick(item.id)
3735
+ },
3736
+ item.id
3737
+ )) }),
3738
+ /* @__PURE__ */ jsx28("div", { className: "flex flex-col gap-2 pt-4", children: bottomItems.map((item) => /* @__PURE__ */ jsx28(
3739
+ SideMenuNavRow,
3740
+ {
3741
+ item,
3742
+ isCollapsed,
3743
+ isSelected: selectedId === item.id,
3744
+ onClick: () => handleItemClick(item.id)
3745
+ },
3746
+ item.id
3747
+ )) })
3704
3748
  ]
3705
3749
  }
3706
3750
  )
@@ -3713,12 +3757,12 @@ var SideMenu = React27.forwardRef(
3713
3757
  SideMenu.displayName = "SideMenu";
3714
3758
 
3715
3759
  // src/patterns/Upload.tsx
3716
- import * as React28 from "react";
3760
+ import * as React29 from "react";
3717
3761
  import { cva as cva20 } from "class-variance-authority";
3718
3762
  import { colors } from "@esds-sangam/tokens";
3719
- import { cn as cn28 } from "@esds-sangam/utils";
3763
+ import { cn as cn29 } from "@esds-sangam/utils";
3720
3764
  import { CloudUpload, DocumentPdf, Close as Close11, Delete, Retry, TickmarkFilled as TickmarkFilled6 } from "@esds-sangam/icons";
3721
- import { Fragment as Fragment5, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
3765
+ import { Fragment as Fragment5, jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
3722
3766
  var uploadBoxVariants = cva20([
3723
3767
  "relative flex flex-col items-center justify-center w-full",
3724
3768
  "rounded-sm border border-dashed border-semantic-border-neutral-primary hover:border-semantic-border-neutralInverse-primary",
@@ -3733,7 +3777,7 @@ function formatFileSize(bytes) {
3733
3777
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
3734
3778
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
3735
3779
  }
3736
- var Upload = React28.forwardRef(
3780
+ var Upload = React29.forwardRef(
3737
3781
  ({
3738
3782
  className,
3739
3783
  label,
@@ -3744,9 +3788,9 @@ var Upload = React28.forwardRef(
3744
3788
  helperText = "PNG, JPG, PDF, EXCEL (max size)",
3745
3789
  ...props
3746
3790
  }, ref) => {
3747
- const inputRef = React28.useRef(null);
3748
- const [fileEntries, setFileEntries] = React28.useState([]);
3749
- const progressIntervalRef = React28.useRef(null);
3791
+ const inputRef = React29.useRef(null);
3792
+ const [fileEntries, setFileEntries] = React29.useState([]);
3793
+ const progressIntervalRef = React29.useRef(null);
3750
3794
  const handleClick = () => {
3751
3795
  inputRef.current?.click();
3752
3796
  };
@@ -3774,7 +3818,7 @@ var Upload = React28.forwardRef(
3774
3818
  )
3775
3819
  );
3776
3820
  };
3777
- React28.useEffect(() => {
3821
+ React29.useEffect(() => {
3778
3822
  const uploading = fileEntries.filter((e) => e.status === "uploading");
3779
3823
  if (uploading.length === 0) return;
3780
3824
  const steps = [10, 50, 100];
@@ -3813,18 +3857,18 @@ var Upload = React28.forwardRef(
3813
3857
  const handleDragOver = (event) => {
3814
3858
  event.preventDefault();
3815
3859
  };
3816
- return /* @__PURE__ */ jsxs22(
3860
+ return /* @__PURE__ */ jsxs23(
3817
3861
  "div",
3818
3862
  {
3819
3863
  ref,
3820
- className: cn28("flex w-full min-w-[328px] flex-col gap-2", className),
3864
+ className: cn29("flex w-full min-w-[328px] flex-col gap-2", className),
3821
3865
  ...props,
3822
3866
  children: [
3823
- /* @__PURE__ */ jsxs22("label", { className: "text-xs font-medium leading-4 text-semantic-text-neutral-primary", children: [
3867
+ /* @__PURE__ */ jsxs23("label", { className: "text-xs font-medium leading-4 text-semantic-text-neutral-primary", children: [
3824
3868
  label,
3825
- required && /* @__PURE__ */ jsx28("span", { className: "text-semantic-text-semantic-error-subtle ml-0.5", children: "*" })
3869
+ required && /* @__PURE__ */ jsx29("span", { className: "text-semantic-text-semantic-error-subtle ml-0.5", children: "*" })
3826
3870
  ] }),
3827
- /* @__PURE__ */ jsxs22(
3871
+ /* @__PURE__ */ jsxs23(
3828
3872
  "div",
3829
3873
  {
3830
3874
  role: "button",
@@ -3838,13 +3882,13 @@ var Upload = React28.forwardRef(
3838
3882
  },
3839
3883
  onDrop: handleDrop,
3840
3884
  onDragOver: handleDragOver,
3841
- className: cn28(
3885
+ className: cn29(
3842
3886
  uploadBoxVariants(),
3843
3887
  // Padding: top/bottom 20px (py-5), left/right 12px (px-3)
3844
3888
  "py-5 px-3"
3845
3889
  ),
3846
3890
  children: [
3847
- /* @__PURE__ */ jsx28(
3891
+ /* @__PURE__ */ jsx29(
3848
3892
  "input",
3849
3893
  {
3850
3894
  ref: inputRef,
@@ -3857,12 +3901,12 @@ var Upload = React28.forwardRef(
3857
3901
  "aria-hidden": "true"
3858
3902
  }
3859
3903
  ),
3860
- /* @__PURE__ */ jsxs22("div", { className: "relative z-0 flex flex-col items-center gap-2 text-center pointer-events-none", children: [
3861
- /* @__PURE__ */ jsx28("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-semantic-background-semantic-info-subtle text-semantic-icon-semantic-info-subtle", children: /* @__PURE__ */ jsx28(CloudUpload, { size: 20, color: colors.blue["600"], "aria-hidden": "true" }) }),
3862
- /* @__PURE__ */ jsxs22("div", { className: "flex flex-col gap-1", children: [
3863
- /* @__PURE__ */ jsxs22("p", { className: "text-sm leading-6 text-semantic-text-neutral-primary", children: [
3864
- /* @__PURE__ */ jsx28("span", { className: "font-normal", children: "Drop your files here or " }),
3865
- /* @__PURE__ */ jsx28(
3904
+ /* @__PURE__ */ jsxs23("div", { className: "relative z-0 flex flex-col items-center gap-2 text-center pointer-events-none", children: [
3905
+ /* @__PURE__ */ jsx29("div", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-semantic-background-semantic-info-subtle text-semantic-icon-semantic-info-subtle", children: /* @__PURE__ */ jsx29(CloudUpload, { size: 20, color: colors.blue["600"], "aria-hidden": "true" }) }),
3906
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-col gap-1", children: [
3907
+ /* @__PURE__ */ jsxs23("p", { className: "text-sm leading-6 text-semantic-text-neutral-primary", children: [
3908
+ /* @__PURE__ */ jsx29("span", { className: "font-normal", children: "Drop your files here or " }),
3909
+ /* @__PURE__ */ jsx29(
3866
3910
  Button,
3867
3911
  {
3868
3912
  type: "button",
@@ -3877,13 +3921,13 @@ var Upload = React28.forwardRef(
3877
3921
  }
3878
3922
  )
3879
3923
  ] }),
3880
- /* @__PURE__ */ jsx28("p", { className: "text-xs font-normal leading-4 text-semantic-text-neutral-tertiary", children: helperText })
3924
+ /* @__PURE__ */ jsx29("p", { className: "text-xs font-normal leading-4 text-semantic-text-neutral-tertiary", children: helperText })
3881
3925
  ] })
3882
3926
  ] })
3883
3927
  ]
3884
3928
  }
3885
3929
  ),
3886
- fileEntries.length > 0 && /* @__PURE__ */ jsx28("div", { className: "flex flex-col gap-3", children: fileEntries.map((entry) => /* @__PURE__ */ jsx28(
3930
+ fileEntries.length > 0 && /* @__PURE__ */ jsx29("div", { className: "flex flex-col gap-3", children: fileEntries.map((entry) => /* @__PURE__ */ jsx29(
3887
3931
  UploadFileItem,
3888
3932
  {
3889
3933
  status: entry.status,
@@ -3917,7 +3961,7 @@ var uploadFileItemBoxVariants = cva20(
3917
3961
  }
3918
3962
  }
3919
3963
  );
3920
- var UploadFileItem = React28.forwardRef(
3964
+ var UploadFileItem = React29.forwardRef(
3921
3965
  ({
3922
3966
  className,
3923
3967
  status = "uploading",
@@ -3931,72 +3975,72 @@ var UploadFileItem = React28.forwardRef(
3931
3975
  }, ref) => {
3932
3976
  const progressValue = Math.min(100, Math.max(0, progress));
3933
3977
  const showProgress = status !== "failed";
3934
- return /* @__PURE__ */ jsxs22(
3978
+ return /* @__PURE__ */ jsxs23(
3935
3979
  "div",
3936
3980
  {
3937
3981
  ref,
3938
3982
  role: "listitem",
3939
- className: cn28(uploadFileItemBoxVariants({ status }), className),
3983
+ className: cn29(uploadFileItemBoxVariants({ status }), className),
3940
3984
  ...props,
3941
3985
  children: [
3942
- /* @__PURE__ */ jsxs22("div", { className: "flex min-w-0 flex-1 gap-3", children: [
3943
- /* @__PURE__ */ jsxs22("div", { className: "flex flex-1 min-w-0 gap-2", children: [
3944
- /* @__PURE__ */ jsx28(DocumentPdf, { size: 24, className: "shrink-0 text-semantic-text-neutral-primary", "aria-hidden": true }),
3945
- /* @__PURE__ */ jsxs22("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
3946
- /* @__PURE__ */ jsx28("p", { className: "truncate text-sm font-medium leading-6 text-semantic-text-neutral-primary", children: fileName }),
3947
- status === "failed" ? /* @__PURE__ */ jsx28("p", { className: "text-xs font-normal leading-4 text-semantic-text-semantic-error-subtle", children: "Upload failed" }) : fileSize ? /* @__PURE__ */ jsx28("p", { className: "text-xs font-normal leading-4 text-semantic-text-neutral-tertiary", children: fileSize }) : null
3986
+ /* @__PURE__ */ jsxs23("div", { className: "flex min-w-0 flex-1 gap-3", children: [
3987
+ /* @__PURE__ */ jsxs23("div", { className: "flex flex-1 min-w-0 gap-2", children: [
3988
+ /* @__PURE__ */ jsx29(DocumentPdf, { size: 24, className: "shrink-0 text-semantic-text-neutral-primary", "aria-hidden": true }),
3989
+ /* @__PURE__ */ jsxs23("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
3990
+ /* @__PURE__ */ jsx29("p", { className: "truncate text-sm font-medium leading-6 text-semantic-text-neutral-primary", children: fileName }),
3991
+ status === "failed" ? /* @__PURE__ */ jsx29("p", { className: "text-xs font-normal leading-4 text-semantic-text-semantic-error-subtle", children: "Upload failed" }) : fileSize ? /* @__PURE__ */ jsx29("p", { className: "text-xs font-normal leading-4 text-semantic-text-neutral-tertiary", children: fileSize }) : null
3948
3992
  ] })
3949
3993
  ] }),
3950
- /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 flex-col items-end justify-center", children: [
3951
- status === "uploading" && /* @__PURE__ */ jsx28(
3994
+ /* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 flex-col items-end justify-center", children: [
3995
+ status === "uploading" && /* @__PURE__ */ jsx29(
3952
3996
  "button",
3953
3997
  {
3954
3998
  type: "button",
3955
3999
  onClick: onCancel,
3956
4000
  className: "inline-flex items-center justify-center rounded p-0 text-semantic-text-neutral-primary hover:opacity-semantic-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-neutralInverse-primary focus-visible:ring-offset-1",
3957
4001
  "aria-label": "Cancel upload",
3958
- children: /* @__PURE__ */ jsx28(Close11, { size: 20, "aria-hidden": true })
4002
+ children: /* @__PURE__ */ jsx29(Close11, { size: 20, "aria-hidden": true })
3959
4003
  }
3960
4004
  ),
3961
- status === "complete" && /* @__PURE__ */ jsx28(Fragment5, { children: /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-4", children: [
3962
- /* @__PURE__ */ jsx28(TickmarkFilled6, { size: 20, className: "!text-semantic-icon-semantic-success-subtle shrink-0", "aria-hidden": true }),
3963
- /* @__PURE__ */ jsx28(
4005
+ status === "complete" && /* @__PURE__ */ jsx29(Fragment5, { children: /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-4", children: [
4006
+ /* @__PURE__ */ jsx29(TickmarkFilled6, { size: 20, className: "!text-semantic-icon-semantic-success-subtle shrink-0", "aria-hidden": true }),
4007
+ /* @__PURE__ */ jsx29(
3964
4008
  "button",
3965
4009
  {
3966
4010
  type: "button",
3967
4011
  onClick: onDelete,
3968
4012
  className: "inline-flex items-center justify-center rounded p-0 text-semantic-text-neutral-primary hover:opacity-semantic-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-neutralInverse-primary focus-visible:ring-offset-1",
3969
4013
  "aria-label": "Delete file",
3970
- children: /* @__PURE__ */ jsx28(Delete, { size: 20, "aria-hidden": true })
4014
+ children: /* @__PURE__ */ jsx29(Delete, { size: 20, "aria-hidden": true })
3971
4015
  }
3972
4016
  )
3973
4017
  ] }) }),
3974
- status === "failed" && /* @__PURE__ */ jsxs22("div", { className: "flex items-center gap-4", children: [
3975
- /* @__PURE__ */ jsx28(
4018
+ status === "failed" && /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-4", children: [
4019
+ /* @__PURE__ */ jsx29(
3976
4020
  "button",
3977
4021
  {
3978
4022
  type: "button",
3979
4023
  onClick: onRetry,
3980
4024
  className: "inline-flex items-center justify-center rounded p-0 text-semantic-text-neutral-primary hover:opacity-semantic-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-neutralInverse-primary focus-visible:ring-offset-1",
3981
4025
  "aria-label": "Retry upload",
3982
- children: /* @__PURE__ */ jsx28(Retry, { size: 20, "aria-hidden": true })
4026
+ children: /* @__PURE__ */ jsx29(Retry, { size: 20, "aria-hidden": true })
3983
4027
  }
3984
4028
  ),
3985
- /* @__PURE__ */ jsx28(
4029
+ /* @__PURE__ */ jsx29(
3986
4030
  "button",
3987
4031
  {
3988
4032
  type: "button",
3989
4033
  onClick: onDelete,
3990
4034
  className: "inline-flex items-center justify-center rounded p-0 text-semantic-text-neutral-primary hover:opacity-semantic-hover focus:outline-none focus-visible:ring-2 focus-visible:ring-semantic-border-neutralInverse-primary focus-visible:ring-offset-1",
3991
4035
  "aria-label": "Delete file",
3992
- children: /* @__PURE__ */ jsx28(Delete, { size: 20, "aria-hidden": true })
4036
+ children: /* @__PURE__ */ jsx29(Delete, { size: 20, "aria-hidden": true })
3993
4037
  }
3994
4038
  )
3995
4039
  ] })
3996
4040
  ] })
3997
4041
  ] }),
3998
- showProgress && /* @__PURE__ */ jsxs22("div", { className: "flex w-full items-center gap-sm", children: [
3999
- /* @__PURE__ */ jsx28(
4042
+ showProgress && /* @__PURE__ */ jsxs23("div", { className: "flex w-full items-center gap-sm", children: [
4043
+ /* @__PURE__ */ jsx29(
4000
4044
  ProgressBar,
4001
4045
  {
4002
4046
  value: progressValue,
@@ -4005,7 +4049,7 @@ var UploadFileItem = React28.forwardRef(
4005
4049
  "aria-label": `Upload progress ${progressValue}%`
4006
4050
  }
4007
4051
  ),
4008
- /* @__PURE__ */ jsxs22("span", { className: "text-xs font-normal leading-4 text-semantic-text-neutral-tertiary shrink-0 text-right", children: [
4052
+ /* @__PURE__ */ jsxs23("span", { className: "text-xs font-normal leading-4 text-semantic-text-neutral-tertiary shrink-0 text-right", children: [
4009
4053
  progressValue,
4010
4054
  "%"
4011
4055
  ] })
@@ -4058,6 +4102,7 @@ export {
4058
4102
  RadioGroup,
4059
4103
  SearchField,
4060
4104
  SideMenu,
4105
+ SideMenuItem,
4061
4106
  Skeleton,
4062
4107
  Stepper,
4063
4108
  Table,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sangam-ui",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",