@herca/r-kit 0.0.69 → 0.0.71

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/clients.cjs CHANGED
@@ -142,7 +142,9 @@ __export(clients_exports, {
142
142
  toDateOnly: () => toDateOnly,
143
143
  useCopy: () => useCopy,
144
144
  useIsMobile: () => useIsMobile,
145
+ useSheetHref: () => useSheetHref,
145
146
  useSidebar: () => useSidebar,
147
+ useTabHref: () => useTabHref,
146
148
  useToast: () => useToast
147
149
  });
148
150
  module.exports = __toCommonJS(clients_exports);
@@ -11273,7 +11275,7 @@ var Icon = ({
11273
11275
  var Icon_default = Icon;
11274
11276
 
11275
11277
  // src/components/sheet/sheet.tsx
11276
- var React395 = require("react");
11278
+ var React395 = __toESM(require("react"), 1);
11277
11279
  var SheetPrimitive = __toESM(require("@radix-ui/react-dialog"), 1);
11278
11280
  var import_jsx_runtime403 = require("react/jsx-runtime");
11279
11281
  var sheetSizeClasses = {
@@ -11283,8 +11285,74 @@ var sheetSizeClasses = {
11283
11285
  xl: "w-2/3 sm:max-w-xl",
11284
11286
  full: "w-full"
11285
11287
  };
11286
- function Sheet({ ...props }) {
11287
- return /* @__PURE__ */ (0, import_jsx_runtime403.jsx)(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
11288
+ var SHEET_URL_EVENT = "__sheet_url_change__";
11289
+ function readParams() {
11290
+ if (typeof window === "undefined") return new URLSearchParams();
11291
+ return new URLSearchParams(window.location.search);
11292
+ }
11293
+ function useUrlSearchParams() {
11294
+ const [params, setParams] = React395.useState(readParams);
11295
+ React395.useEffect(() => {
11296
+ const sync = () => setParams(readParams());
11297
+ sync();
11298
+ window.addEventListener("popstate", sync);
11299
+ window.addEventListener(SHEET_URL_EVENT, sync);
11300
+ return () => {
11301
+ window.removeEventListener("popstate", sync);
11302
+ window.removeEventListener(SHEET_URL_EVENT, sync);
11303
+ };
11304
+ }, []);
11305
+ const setSearchParams = React395.useCallback(
11306
+ (updater, options) => {
11307
+ const next = updater(readParams());
11308
+ const query = next.toString();
11309
+ const url = `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`;
11310
+ if (options?.replace) {
11311
+ window.history.replaceState(window.history.state, "", url);
11312
+ } else {
11313
+ window.history.pushState(window.history.state, "", url);
11314
+ }
11315
+ window.dispatchEvent(new Event(SHEET_URL_EVENT));
11316
+ },
11317
+ []
11318
+ );
11319
+ return [params, setSearchParams];
11320
+ }
11321
+ function Sheet({
11322
+ id,
11323
+ urlReplace = false,
11324
+ open: openProp,
11325
+ defaultOpen,
11326
+ onOpenChange,
11327
+ ...props
11328
+ }) {
11329
+ const [searchParams, setSearchParams] = useUrlSearchParams();
11330
+ const isControlled = openProp !== void 0;
11331
+ const isUrlSynced = id !== void 0 && !isControlled;
11332
+ const urlParam = id !== void 0 ? `sheet-${id}` : void 0;
11333
+ const open = isControlled ? openProp : isUrlSynced && urlParam !== void 0 ? searchParams.has(urlParam) : void 0;
11334
+ const handleOpenChange = (next) => {
11335
+ if (isUrlSynced && urlParam !== void 0) {
11336
+ setSearchParams(
11337
+ (prev) => {
11338
+ const p = new URLSearchParams(prev);
11339
+ if (next) p.set(urlParam, "1");
11340
+ else p.delete(urlParam);
11341
+ return p;
11342
+ },
11343
+ { replace: urlReplace }
11344
+ );
11345
+ }
11346
+ onOpenChange?.(next);
11347
+ };
11348
+ const stateProps = isControlled || isUrlSynced ? { open, onOpenChange: handleOpenChange } : { defaultOpen, onOpenChange: handleOpenChange };
11349
+ return /* @__PURE__ */ (0, import_jsx_runtime403.jsx)(SheetPrimitive.Root, { "data-slot": "sheet", ...stateProps, ...props });
11350
+ }
11351
+ function useSheetHref(id) {
11352
+ const [searchParams] = useUrlSearchParams();
11353
+ const params = new URLSearchParams(searchParams);
11354
+ params.set(`sheet-${id}`, "1");
11355
+ return `?${params.toString()}`;
11288
11356
  }
11289
11357
  function SheetTrigger({
11290
11358
  ...props
@@ -11435,6 +11503,18 @@ var SIDEBAR_WIDTH = "13.75rem";
11435
11503
  var SIDEBAR_WIDTH_MOBILE = "18rem";
11436
11504
  var SIDEBAR_WIDTH_ICON = "4.125rem";
11437
11505
  var SIDEBAR_KEYBOARD_SHORTCUT = "b";
11506
+ var HOVER_OPEN_DELAY = 150;
11507
+ var HOVER_CLOSE_DELAY = 200;
11508
+ function readSidebarCookie() {
11509
+ if (typeof document === "undefined") return void 0;
11510
+ const match = document.cookie.match(
11511
+ new RegExp("(?:^|; )" + SIDEBAR_COOKIE_NAME + "=([^;]+)")
11512
+ );
11513
+ if (match === null) return void 0;
11514
+ if (match[1] === "true") return true;
11515
+ if (match[1] === "false") return false;
11516
+ return void 0;
11517
+ }
11438
11518
  function SidebarProvider({
11439
11519
  defaultOpen = true,
11440
11520
  open: openProp,
@@ -11444,26 +11524,33 @@ function SidebarProvider({
11444
11524
  children,
11445
11525
  ...props
11446
11526
  }) {
11447
- const isMobile = useIsMobile();
11527
+ const isMobile = Boolean(useIsMobile());
11448
11528
  const [openMobile, setOpenMobile] = import_react394.default.useState(false);
11449
- const [_open, _setOpen] = import_react394.default.useState(defaultOpen);
11450
- const open = openProp ?? _open;
11529
+ const [isHovered, setIsHovered] = import_react394.default.useState(false);
11530
+ const [internalOpen, setInternalOpen] = import_react394.default.useState(() => {
11531
+ const stored = readSidebarCookie();
11532
+ return stored ?? defaultOpen;
11533
+ });
11534
+ const open = Boolean(openProp ?? internalOpen);
11451
11535
  const setOpen = import_react394.default.useCallback(
11452
11536
  (value) => {
11453
- const openState = typeof value === "function" ? value(open) : value;
11537
+ const next = typeof value === "function" ? value(open) : value;
11454
11538
  if (setOpenProp !== void 0) {
11455
- setOpenProp(openState);
11539
+ setOpenProp(next);
11456
11540
  } else {
11457
- _setOpen(openState);
11541
+ setInternalOpen(next);
11458
11542
  }
11459
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
11543
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${next}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
11460
11544
  },
11461
11545
  [setOpenProp, open]
11462
11546
  );
11463
- const [isHovered, setIsHovered] = import_react394.default.useState(false);
11464
11547
  const toggleSidebar = import_react394.default.useCallback(() => {
11465
- return isMobile ? setOpenMobile((open2) => !open2) : setOpen((open2) => !open2);
11466
- }, [isMobile, setOpen, setOpenMobile]);
11548
+ if (isMobile) {
11549
+ setOpenMobile((v3) => !v3);
11550
+ } else {
11551
+ setOpen((v3) => !v3);
11552
+ }
11553
+ }, [isMobile, setOpen]);
11467
11554
  import_react394.default.useEffect(() => {
11468
11555
  const handleKeyDown2 = (event) => {
11469
11556
  if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
@@ -11474,7 +11561,7 @@ function SidebarProvider({
11474
11561
  window.addEventListener("keydown", handleKeyDown2);
11475
11562
  return () => window.removeEventListener("keydown", handleKeyDown2);
11476
11563
  }, [toggleSidebar]);
11477
- const state = open === true ? "expanded" : "collapsed";
11564
+ const state = open ? "expanded" : "collapsed";
11478
11565
  const contextValue = import_react394.default.useMemo(
11479
11566
  () => ({
11480
11567
  state,
@@ -11487,20 +11574,12 @@ function SidebarProvider({
11487
11574
  isHovered,
11488
11575
  setIsHovered
11489
11576
  }),
11490
- [
11491
- state,
11492
- open,
11493
- setOpen,
11494
- isMobile,
11495
- openMobile,
11496
- setOpenMobile,
11497
- toggleSidebar,
11498
- isHovered
11499
- ]
11577
+ [state, open, setOpen, isMobile, openMobile, toggleSidebar, isHovered]
11500
11578
  );
11501
11579
  return /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(SidebarContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11502
11580
  "div",
11503
11581
  {
11582
+ "data-slot": "sidebar-wrapper",
11504
11583
  style: {
11505
11584
  "--sidebar-width": SIDEBAR_WIDTH,
11506
11585
  "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
@@ -11531,19 +11610,32 @@ function Sidebar({
11531
11610
  isHovered,
11532
11611
  setIsHovered
11533
11612
  } = useSidebar();
11613
+ const openTimer = import_react394.default.useRef(null);
11614
+ const closeTimer = import_react394.default.useRef(null);
11615
+ const clearTimers = import_react394.default.useCallback(() => {
11616
+ if (openTimer.current) clearTimeout(openTimer.current);
11617
+ if (closeTimer.current) clearTimeout(closeTimer.current);
11618
+ openTimer.current = null;
11619
+ closeTimer.current = null;
11620
+ }, []);
11621
+ import_react394.default.useEffect(() => clearTimers, [clearTimers]);
11534
11622
  const handleMouseEnter = import_react394.default.useCallback(() => {
11535
- if (Boolean(isMobile) || state === "expanded") {
11536
- return;
11537
- }
11538
- setIsHovered(true);
11539
- }, [isMobile, state, setIsHovered]);
11623
+ if (isMobile == true || state === "expanded" || collapsible !== "icon") return;
11624
+ clearTimers();
11625
+ openTimer.current = setTimeout(() => setIsHovered(true), HOVER_OPEN_DELAY);
11626
+ }, [isMobile, state, collapsible, clearTimers, setIsHovered]);
11540
11627
  const handleMouseLeave = import_react394.default.useCallback(() => {
11541
- setIsHovered(false);
11542
- }, [setIsHovered]);
11628
+ clearTimers();
11629
+ closeTimer.current = setTimeout(
11630
+ () => setIsHovered(false),
11631
+ HOVER_CLOSE_DELAY
11632
+ );
11633
+ }, [clearTimers, setIsHovered]);
11543
11634
  if (collapsible === "none") {
11544
11635
  return /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11545
11636
  "div",
11546
11637
  {
11638
+ "data-slot": "sidebar",
11547
11639
  className: cn(
11548
11640
  "flex h-full w-(--sidebar-width) flex-col bg-white text-gray-900",
11549
11641
  className
@@ -11553,7 +11645,7 @@ function Sidebar({
11553
11645
  }
11554
11646
  );
11555
11647
  }
11556
- if (isMobile === true) {
11648
+ if (isMobile == true) {
11557
11649
  return /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(Sheet, { open: openMobile, onOpenChange: setOpenMobile, ...props, children: /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(
11558
11650
  SheetContent,
11559
11651
  {
@@ -11561,14 +11653,12 @@ function Sidebar({
11561
11653
  "data-slot": "sidebar",
11562
11654
  "data-mobile": "true",
11563
11655
  className: "w-(--sidebar-width) bg-white p-0 text-gray-900 [&>button]:hidden",
11564
- style: {
11565
- "--sidebar-width": SIDEBAR_WIDTH_MOBILE
11566
- },
11656
+ style: { "--sidebar-width": SIDEBAR_WIDTH_MOBILE },
11567
11657
  side,
11568
11658
  children: [
11569
11659
  /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(SheetHeader, { className: "sr-only", children: [
11570
11660
  /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(SheetTitle, { children: "Sidebar" }),
11571
- /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(SheetDescription, { children: "Displays the mobile sidebar." })
11661
+ /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(SheetDescription, { children: "Menampilkan sidebar mobile." })
11572
11662
  ] }),
11573
11663
  /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("div", { className: "flex h-full w-full flex-col", children })
11574
11664
  ]
@@ -11584,6 +11674,7 @@ function Sidebar({
11584
11674
  "data-variant": variant,
11585
11675
  "data-side": side,
11586
11676
  "data-hovered": isHovered,
11677
+ "data-slot": "sidebar",
11587
11678
  children: [
11588
11679
  /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11589
11680
  "div",
@@ -11600,11 +11691,11 @@ function Sidebar({
11600
11691
  "div",
11601
11692
  {
11602
11693
  className: cn(
11603
- "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
11694
+ "fixed inset-y-0 z-21 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
11604
11695
  side === "left" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
11605
- // Adjust the padding for floating and inset variants.
11606
11696
  variant === "floating" || variant === "inset" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]" : "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=left]:border-gray-200 group-data-[side=right]:border-l group-data-[side=right]:border-gray-200",
11607
11697
  "group-data-[collapsible=icon]:group-data-[hovered=true]:w-(--sidebar-width)",
11698
+ "group-data-[collapsible=icon]:group-data-[hovered=true]:shadow-lg",
11608
11699
  className
11609
11700
  ),
11610
11701
  onMouseEnter: handleMouseEnter,
@@ -11629,12 +11720,19 @@ function SidebarTrigger({
11629
11720
  onClick,
11630
11721
  ...props
11631
11722
  }) {
11632
- const { toggleSidebar } = useSidebar();
11723
+ const { toggleSidebar, state } = useSidebar();
11633
11724
  return /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(
11634
11725
  "button",
11635
11726
  {
11727
+ type: "button",
11636
11728
  "data-sidebar": "trigger",
11637
- className: cn("size-7", className),
11729
+ "aria-label": "Toggle Sidebar",
11730
+ "aria-expanded": state === "expanded",
11731
+ className: cn(
11732
+ "inline-flex size-7 cursor-pointer items-center justify-center rounded-md text-gray-700",
11733
+ "focus-visible:ring-primary-500 hover:bg-gray-100 focus-visible:ring-2 focus-visible:outline-none",
11734
+ className
11735
+ ),
11638
11736
  onClick: (event) => {
11639
11737
  onClick?.(event);
11640
11738
  toggleSidebar();
@@ -11692,7 +11790,8 @@ function SidebarContent({ className, ...props }) {
11692
11790
  {
11693
11791
  "data-sidebar": "content",
11694
11792
  className: cn(
11695
- "flex min-h-0 flex-1 flex-col gap-2 overflow-auto p-3",
11793
+ "flex min-h-0 flex-1 flex-col gap-2 overflow-x-hidden overflow-y-auto p-3",
11794
+ "scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent",
11696
11795
  className
11697
11796
  ),
11698
11797
  ...props
@@ -11709,64 +11808,66 @@ function SidebarMenu({ className, ...props }) {
11709
11808
  }
11710
11809
  );
11711
11810
  }
11811
+ function MenuItemInner({
11812
+ icon,
11813
+ expanded,
11814
+ children
11815
+ }) {
11816
+ return /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(import_jsx_runtime404.Fragment, { children: [
11817
+ /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("span", { className: "shrink-0", children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(Icon_default, { name: "ellipse", size: 18 }) }),
11818
+ /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11819
+ "span",
11820
+ {
11821
+ className: cn(
11822
+ "flex-1 truncate transition-opacity duration-150",
11823
+ expanded ? "opacity-100" : "pointer-events-none w-0 opacity-0"
11824
+ ),
11825
+ children
11826
+ }
11827
+ )
11828
+ ] });
11829
+ }
11712
11830
  function SidebarMenuItem({
11713
11831
  children,
11714
11832
  className,
11715
11833
  icon,
11716
- active,
11834
+ active = false,
11717
11835
  asChild = true,
11718
11836
  ...props
11719
11837
  }) {
11720
11838
  const { state, isHovered } = useSidebar();
11839
+ const expanded = state === "expanded" || isHovered;
11721
11840
  const itemClassName = cn(
11722
11841
  "flex w-full items-center gap-2 rounded-sm bg-white px-3 py-2.5 text-sm text-gray-800 transition-colors",
11723
11842
  "hover:bg-primary-100",
11724
- Boolean(active) && "bg-primary-100 text-primary-1000 before:bg-primary-1000 before:absolute before:top-1/2 before:left-0 before:h-5 before:w-1 before:-translate-y-1/2 before:rounded-r-md"
11843
+ "focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none",
11844
+ active == true && "bg-primary-100 text-primary-1000 before:bg-primary-1000 before:absolute before:top-1/2 before:left-0 before:h-5 before:w-1 before:-translate-y-1/2 before:rounded-r-md"
11725
11845
  );
11726
- const iconElement = icon !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("span", { className: "shrink-0", children: icon }) : /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("span", { className: "shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(Icon_default, { name: "ellipse", size: 18 }) });
11846
+ let body;
11847
+ if (asChild) {
11848
+ const child = import_react394.default.Children.only(children);
11849
+ if (!import_react394.default.isValidElement(child)) {
11850
+ throw new Error(
11851
+ "SidebarMenuItem with asChild requires a single valid React element as child"
11852
+ );
11853
+ }
11854
+ const childEl = child;
11855
+ body = import_react394.default.cloneElement(childEl, {
11856
+ className: cn(itemClassName, childEl.props.className),
11857
+ children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(MenuItemInner, { icon, expanded, children: childEl.props.children })
11858
+ });
11859
+ } else {
11860
+ body = /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("div", { className: itemClassName, children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(MenuItemInner, { icon, expanded, children }) });
11861
+ }
11727
11862
  return /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11728
11863
  "li",
11729
11864
  {
11730
11865
  "data-sidebar": "menu-item",
11866
+ "data-active": active,
11867
+ "aria-current": active ? "page" : void 0,
11731
11868
  className: cn("group/menu-item relative", className),
11732
11869
  ...props,
11733
- children: asChild === true ? (() => {
11734
- const child = import_react394.default.Children.only(children);
11735
- if (import_react394.default.isValidElement(child) === false) {
11736
- throw new Error(
11737
- "SidebarMenuItem with asChild requires a single valid React element as child"
11738
- );
11739
- }
11740
- const childElement = child;
11741
- return import_react394.default.cloneElement(childElement, {
11742
- className: cn(itemClassName, childElement.props.className),
11743
- children: /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(import_jsx_runtime404.Fragment, { children: [
11744
- iconElement,
11745
- /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11746
- "span",
11747
- {
11748
- className: cn(
11749
- "flex-1",
11750
- state === "collapsed" && isHovered === false && "hidden"
11751
- ),
11752
- children: childElement.props.children
11753
- }
11754
- )
11755
- ] })
11756
- });
11757
- })() : /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)("div", { className: itemClassName, children: [
11758
- iconElement,
11759
- /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11760
- "span",
11761
- {
11762
- className: cn(
11763
- "flex-1",
11764
- state === "collapsed" && isHovered === false && "hidden"
11765
- ),
11766
- children
11767
- }
11768
- )
11769
- ] })
11870
+ children: body
11770
11871
  }
11771
11872
  );
11772
11873
  }
@@ -11779,29 +11880,30 @@ function SidebarMenuGroup({
11779
11880
  ...props
11780
11881
  }) {
11781
11882
  const { state, isHovered } = useSidebar();
11883
+ const expanded = state === "expanded" || isHovered;
11782
11884
  const [isOpen, setIsOpen] = import_react394.default.useState(active);
11783
11885
  const triggerClassName = cn(
11784
- "hover:bg-primary-100 relative flex w-full items-center gap-2 rounded-sm bg-white px-3 py-2.5 text-sm text-gray-800 transition-colors",
11785
- "cursor-pointer",
11786
- Boolean(active) && "bg-primary-100 text-primary-1000 before:bg-primary-1000 before:absolute before:top-1/2 before:left-0 before:h-5 before:w-1 before:-translate-y-1/2 before:rounded-r-md"
11886
+ "relative flex w-full cursor-pointer items-center gap-2 rounded-sm bg-white px-3 py-2.5 text-sm text-gray-800 transition-colors",
11887
+ "hover:bg-primary-100",
11888
+ "focus-visible:ring-primary-500 focus-visible:ring-2 focus-visible:outline-none",
11889
+ active && "bg-primary-100 text-primary-1000 before:bg-primary-1000 before:absolute before:top-1/2 before:left-0 before:h-5 before:w-1 before:-translate-y-1/2 before:rounded-r-md"
11787
11890
  );
11788
- const iconElement = icon !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("span", { className: "shrink-0", children: icon }) : /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("span", { className: "shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(Icon_default, { name: "ellipse", size: 18 }) });
11789
11891
  return /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(
11790
11892
  Collapsible,
11791
11893
  {
11792
- open: Boolean(isOpen) && (state === "expanded" || isHovered),
11894
+ open: isOpen && expanded,
11793
11895
  onOpenChange: setIsOpen,
11794
11896
  className: cn("group/menu-group flex flex-col gap-y-1", className),
11795
11897
  ...props,
11796
11898
  children: [
11797
11899
  /* @__PURE__ */ (0, import_jsx_runtime404.jsxs)(CollapsibleTrigger2, { className: triggerClassName, children: [
11798
- iconElement,
11900
+ /* @__PURE__ */ (0, import_jsx_runtime404.jsx)("span", { className: "shrink-0", children: icon ?? /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(Icon_default, { name: "ellipse", size: 18 }) }),
11799
11901
  /* @__PURE__ */ (0, import_jsx_runtime404.jsx)(
11800
11902
  "span",
11801
11903
  {
11802
11904
  className: cn(
11803
- "flex-1 text-left",
11804
- state === "collapsed" && isHovered === false && "hidden"
11905
+ "flex-1 truncate text-left transition-opacity duration-150",
11906
+ expanded ? "opacity-100" : "pointer-events-none w-0 opacity-0"
11805
11907
  ),
11806
11908
  children: label
11807
11909
  }
@@ -11813,8 +11915,8 @@ function SidebarMenuGroup({
11813
11915
  size: 18,
11814
11916
  className: cn(
11815
11917
  "shrink-0 transition-transform duration-200",
11816
- state === "collapsed" && "hidden",
11817
- Boolean(isOpen) && "rotate-180"
11918
+ !expanded && "hidden",
11919
+ isOpen && "rotate-180"
11818
11920
  )
11819
11921
  }
11820
11922
  )
@@ -17135,33 +17237,99 @@ function Select({
17135
17237
  }
17136
17238
 
17137
17239
  // src/components/tabs/tabs.tsx
17138
- var import_react414 = require("react");
17240
+ var import_react414 = __toESM(require("react"), 1);
17139
17241
  var import_jsx_runtime435 = require("react/jsx-runtime");
17140
17242
  var TabsContext = (0, import_react414.createContext)(void 0);
17243
+ var TAB_URL_EVENT = "__tab_url_change__";
17244
+ function readParams2() {
17245
+ if (typeof window === "undefined") {
17246
+ return new URLSearchParams();
17247
+ }
17248
+ return new URLSearchParams(window.location.search);
17249
+ }
17250
+ function useUrlSearchParams2() {
17251
+ const [params, setParams] = (0, import_react414.useState)(readParams2);
17252
+ (0, import_react414.useEffect)(() => {
17253
+ const sync = () => setParams(readParams2());
17254
+ sync();
17255
+ window.addEventListener("popstate", sync);
17256
+ window.addEventListener(TAB_URL_EVENT, sync);
17257
+ return () => {
17258
+ window.removeEventListener("popstate", sync);
17259
+ window.removeEventListener(TAB_URL_EVENT, sync);
17260
+ };
17261
+ }, []);
17262
+ const setSearchParams = import_react414.default.useCallback(
17263
+ (updater, options) => {
17264
+ const next = updater(readParams2());
17265
+ const query = next.toString();
17266
+ const url = `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`;
17267
+ if (options?.replace) {
17268
+ window.history.replaceState(window.history.state, "", url);
17269
+ } else {
17270
+ window.history.pushState(window.history.state, "", url);
17271
+ }
17272
+ window.dispatchEvent(new Event(TAB_URL_EVENT));
17273
+ },
17274
+ []
17275
+ );
17276
+ return [params, setSearchParams];
17277
+ }
17141
17278
  var useTabsContext = () => {
17142
17279
  const context = (0, import_react414.useContext)(TabsContext);
17143
- if (!context) {
17280
+ if (context === void 0) {
17144
17281
  throw new Error("Tabs components must be used within Tabs");
17145
17282
  }
17146
17283
  return context;
17147
17284
  };
17285
+ var useTabHref = (value) => {
17286
+ const { buildHref } = useTabsContext();
17287
+ return buildHref?.(value);
17288
+ };
17148
17289
  var Tabs = ({
17149
17290
  defaultValue,
17150
17291
  value: controlledValue,
17151
17292
  onValueChange,
17293
+ id,
17294
+ urlReplace = true,
17152
17295
  orientation = "horizontal",
17153
17296
  unmountOnHide = true,
17154
17297
  className,
17155
17298
  children
17156
17299
  }) => {
17300
+ const [searchParams, setSearchParams] = useUrlSearchParams2();
17157
17301
  const [uncontrolledValue, setUncontrolledValue] = (0, import_react414.useState)(
17158
17302
  defaultValue ?? ""
17159
17303
  );
17160
17304
  const triggersRef = (0, import_react414.useRef)(/* @__PURE__ */ new Map());
17161
17305
  const isControlled = controlledValue !== void 0;
17162
- const value = isControlled ? controlledValue : uncontrolledValue;
17306
+ const urlParam = id !== void 0 ? `tab-${id}` : void 0;
17307
+ const isUrlSynced = urlParam !== void 0 && !isControlled;
17308
+ let value;
17309
+ if (isControlled) {
17310
+ value = controlledValue;
17311
+ } else if (isUrlSynced) {
17312
+ value = searchParams.get(urlParam) ?? defaultValue ?? "";
17313
+ } else {
17314
+ value = uncontrolledValue;
17315
+ }
17316
+ const buildHref = isUrlSynced ? (newValue) => {
17317
+ const next = new URLSearchParams(searchParams);
17318
+ next.set(urlParam, newValue);
17319
+ return `?${next.toString()}`;
17320
+ } : void 0;
17163
17321
  const handleValueChange = (newValue) => {
17164
- if (!isControlled) {
17322
+ if (isUrlSynced && urlParam !== void 0) {
17323
+ setSearchParams(
17324
+ (prev) => {
17325
+ const next = new URLSearchParams(prev);
17326
+ next.set(urlParam, newValue);
17327
+ return next;
17328
+ },
17329
+ { replace: urlReplace }
17330
+ );
17331
+ }
17332
+ if (!isUrlSynced && !isControlled) {
17165
17333
  setUncontrolledValue(newValue);
17166
17334
  }
17167
17335
  onValueChange?.(newValue);
@@ -17181,7 +17349,9 @@ var Tabs = ({
17181
17349
  orientation,
17182
17350
  unmountOnHide,
17183
17351
  registerTrigger,
17184
- unregisterTrigger
17352
+ unregisterTrigger,
17353
+ buildHref,
17354
+ urlReplace
17185
17355
  },
17186
17356
  children: /* @__PURE__ */ (0, import_jsx_runtime435.jsx)("div", { className: cn(className), "data-orientation": orientation, children })
17187
17357
  }
@@ -17194,11 +17364,11 @@ var TabsList = ({ className, children }) => {
17194
17364
  const [isInitialized, setIsInitialized] = (0, import_react414.useState)(false);
17195
17365
  (0, import_react414.useEffect)(() => {
17196
17366
  const updateIndicator = () => {
17197
- if (!listRef.current) return;
17367
+ if (listRef.current === null) return;
17198
17368
  const activeButton = listRef.current.querySelector(
17199
- `[aria-selected="true"]`
17369
+ '[aria-selected="true"]'
17200
17370
  );
17201
- if (activeButton === null || activeButton === void 0) return;
17371
+ if (activeButton === null) return;
17202
17372
  const listRect = listRef.current.getBoundingClientRect();
17203
17373
  const buttonRect = activeButton.getBoundingClientRect();
17204
17374
  if (orientation === "horizontal") {
@@ -17271,36 +17441,63 @@ var TabsTrigger = ({
17271
17441
  className,
17272
17442
  children
17273
17443
  }) => {
17274
- const { value, onValueChange, registerTrigger, unregisterTrigger } = useTabsContext();
17444
+ const {
17445
+ value,
17446
+ onValueChange,
17447
+ buildHref,
17448
+ registerTrigger,
17449
+ unregisterTrigger
17450
+ } = useTabsContext();
17275
17451
  const isSelected = value === triggerValue;
17276
17452
  const triggerRef = (0, import_react414.useRef)(null);
17453
+ const href = buildHref?.(triggerValue);
17277
17454
  (0, import_react414.useEffect)(() => {
17278
- if (triggerRef.current) {
17455
+ if (triggerRef.current !== null) {
17279
17456
  registerTrigger(triggerValue, triggerRef.current);
17280
17457
  }
17281
17458
  return () => {
17282
17459
  unregisterTrigger(triggerValue);
17283
17460
  };
17284
17461
  }, [triggerValue, registerTrigger, unregisterTrigger]);
17462
+ const sharedClass = cn(
17463
+ "inline-flex cursor-pointer items-center justify-center rounded-md px-4 py-2 whitespace-nowrap",
17464
+ "text-sm font-semibold transition-colors duration-200",
17465
+ "focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1 focus-visible:outline-none",
17466
+ "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
17467
+ isSelected ? "text-white" : "text-gray-700 hover:text-gray-900",
17468
+ className
17469
+ );
17470
+ const sharedA11y = {
17471
+ "role": "tab",
17472
+ "aria-selected": isSelected,
17473
+ "aria-controls": `panel-${triggerValue}`,
17474
+ "id": `tab-${triggerValue}`
17475
+ };
17476
+ if (href !== void 0 && !disabled) {
17477
+ return /* @__PURE__ */ (0, import_jsx_runtime435.jsx)(
17478
+ "a",
17479
+ {
17480
+ ref: triggerRef,
17481
+ href,
17482
+ onClick: (e) => {
17483
+ e.preventDefault();
17484
+ onValueChange(triggerValue);
17485
+ },
17486
+ className: sharedClass,
17487
+ ...sharedA11y,
17488
+ children
17489
+ }
17490
+ );
17491
+ }
17285
17492
  return /* @__PURE__ */ (0, import_jsx_runtime435.jsx)(
17286
17493
  "button",
17287
17494
  {
17288
17495
  ref: triggerRef,
17289
- role: "tab",
17290
17496
  type: "button",
17291
- "aria-selected": isSelected,
17292
- "aria-controls": `panel-${triggerValue}`,
17293
- id: `tab-${triggerValue}`,
17294
17497
  disabled,
17295
17498
  onClick: () => onValueChange(triggerValue),
17296
- className: cn(
17297
- "inline-flex cursor-pointer items-center justify-center rounded-md px-4 py-2 whitespace-nowrap",
17298
- "text-sm font-semibold transition-colors duration-200",
17299
- "focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1 focus-visible:outline-none",
17300
- "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
17301
- isSelected ? "text-white" : "text-gray-700 hover:text-gray-900",
17302
- className
17303
- ),
17499
+ className: sharedClass,
17500
+ ...sharedA11y,
17304
17501
  children
17305
17502
  }
17306
17503
  );
@@ -36649,7 +36846,9 @@ var Radio = ({ label, description, className, size: sizeProp, ...props }) => {
36649
36846
  toDateOnly,
36650
36847
  useCopy,
36651
36848
  useIsMobile,
36849
+ useSheetHref,
36652
36850
  useSidebar,
36851
+ useTabHref,
36653
36852
  useToast
36654
36853
  });
36655
36854
  //# sourceMappingURL=clients.cjs.map