@bizapps/design-system-testing 1.10.1 → 1.11.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/main.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { SearchIcon, BellIcon, CircleHelpIcon, ChevronDownIcon, ChevronLeftIcon, MoreHorizontalIcon, ChevronRightIcon, MinusIcon, CheckIcon, LoaderCircle, ChevronUpIcon, X, ChevronLeft, ChevronRight, ExternalLinkIcon, ChevronsUpDownIcon, XIcon, UploadIcon, Loader2Icon, LoaderIcon, PipetteIcon, CalendarIcon, MenuIcon, Pencil, Clock, Funnel, ArrowUp, ArrowDown, ArrowUpDown, Ellipsis, Rows2, Eye, Search, BrushCleaning, House, Plane, Wallet, LayoutDashboardIcon, InfoIcon, TriangleAlertIcon, OctagonXIcon, CircleCheckIcon } from 'lucide-react';
2
+ import { SearchIcon, BellIcon, CircleHelpIcon, ChevronDownIcon, ChevronLeftIcon, MoreHorizontalIcon, ChevronRightIcon, MinusIcon, CheckIcon, LoaderCircle, ChevronUpIcon, X, ChevronLeft, ChevronRight, ExternalLinkIcon, ChevronsUpDownIcon, XIcon, UploadIcon, Loader2Icon, LoaderIcon, PipetteIcon, CalendarIcon, MenuIcon, Pencil, Clock, Funnel, ArrowUp, ArrowDown, ArrowUpDown, Ellipsis, Rows2, Eye, Search, ChevronsLeft, Menu, ChevronDown, Star, BrushCleaning, House, Plane, Wallet, LayoutDashboardIcon, CircleDashed, InfoIcon, TriangleAlertIcon, OctagonXIcon, CircleCheckIcon } from 'lucide-react';
3
3
  import { cva } from 'class-variance-authority';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
@@ -2217,10 +2217,10 @@ function createStore() {
2217
2217
  listeners: [],
2218
2218
  add(item, id) {
2219
2219
  const toastId = id ?? Math.random().toString(36).slice(2);
2220
- const exists = store.toasts.find((t) => t.id === toastId);
2220
+ const exists = store.toasts.find((t2) => t2.id === toastId);
2221
2221
  if (exists) {
2222
2222
  store.toasts = store.toasts.map(
2223
- (t) => t.id === toastId ? { ...t, ...item, id: toastId } : t
2223
+ (t2) => t2.id === toastId ? { ...t2, ...item, id: toastId } : t2
2224
2224
  );
2225
2225
  } else {
2226
2226
  store.toasts = [{ id: toastId, ...item }, ...store.toasts].slice(0, MAX_TOASTS);
@@ -2235,7 +2235,7 @@ function createStore() {
2235
2235
  remove(id) {
2236
2236
  clearTimeout(timers.get(id));
2237
2237
  timers.delete(id);
2238
- store.toasts = store.toasts.filter((t) => t.id !== id);
2238
+ store.toasts = store.toasts.filter((t2) => t2.id !== id);
2239
2239
  store.listeners.forEach((l) => l([...store.toasts]));
2240
2240
  },
2241
2241
  subscribe(listener) {
@@ -2379,7 +2379,7 @@ function Toaster({ position = "bottom-right", children }) {
2379
2379
  "pointer-events-none fixed z-[100] flex flex-col gap-2",
2380
2380
  positionStyles[position]
2381
2381
  ),
2382
- children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "sync", initial: false, children: toasts.map((t) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(ToastCard, { ...t }) }, t.id)) })
2382
+ children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "sync", initial: false, children: toasts.map((t2) => /* @__PURE__ */ jsx("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx(ToastCard, { ...t2 }) }, t2.id)) })
2383
2383
  }
2384
2384
  )
2385
2385
  ] });
@@ -5160,13 +5160,11 @@ function AbilityProvider({ children, permissions }) {
5160
5160
  setImperativelyResolved(true);
5161
5161
  }, []);
5162
5162
  const permissionKey = permissions === void 0 ? null : [...permissions].sort().join("|");
5163
- const syncedKey = useRef(permissionKey);
5164
- useEffect(() => {
5165
- if (permissionKey === null) return;
5166
- if (permissionKey === syncedKey.current) return;
5167
- syncedKey.current = permissionKey;
5163
+ const [syncedKey, setSyncedKey] = useState(permissionKey);
5164
+ if (permissionKey !== null && permissionKey !== syncedKey) {
5165
+ setSyncedKey(permissionKey);
5168
5166
  setPermissionSet(new Set(permissions));
5169
- }, [permissionKey, permissions]);
5167
+ }
5170
5168
  const value = useMemo(
5171
5169
  () => ({ can: can2, setAbilities, clearAbilities, status }),
5172
5170
  [can2, setAbilities, clearAbilities, status]
@@ -5180,6 +5178,9 @@ function useAbility() {
5180
5178
  }
5181
5179
  return context;
5182
5180
  }
5181
+ function useOptionalAbility() {
5182
+ return useContext(AbilityContext);
5183
+ }
5183
5184
  function useCan(permissions, mode = "any") {
5184
5185
  const { can: can2 } = useAbility();
5185
5186
  return can2(permissions, mode);
@@ -9174,6 +9175,1034 @@ function BottomNavTabsList({ items, className }) {
9174
9175
  }
9175
9176
  );
9176
9177
  }
9178
+ var DEFAULT_LABELS = {
9179
+ navigation: "Modules navigation",
9180
+ title: "Modules",
9181
+ collapse: "Collapse menu",
9182
+ expand: "Expand menu",
9183
+ openMenu: "Open menu",
9184
+ currentPageSuffix: " (contains the current page)",
9185
+ searchPlaceholder: () => "Filter links\u2026",
9186
+ searchLabel: (moduleLabel) => `Filter links of ${moduleLabel}`,
9187
+ clearSearch: "Clear search",
9188
+ noMatchesTitle: "No matches",
9189
+ noMatches: (moduleLabel, query) => `No links in ${moduleLabel} match \u201C${query}\u201D.`,
9190
+ flyoutNoMatches: (query) => `No links match \u201C${query}\u201D.`,
9191
+ emptyModule: "No links in this module yet.",
9192
+ addFavorite: (itemLabel) => `Add to favorites: ${itemLabel}`,
9193
+ removeFavorite: (itemLabel) => `Remove from favorites: ${itemLabel}`
9194
+ };
9195
+ var EASE = "cubic-bezier(.2,.8,.2,1)";
9196
+ var MOTION_MS = 240;
9197
+ var FADE_MS = MOTION_MS / 2;
9198
+ var BOUNCE_KEYFRAMES = [
9199
+ { transform: "translateY(0) scale(1)" },
9200
+ { transform: "translateY(-3px) scale(1.06)", offset: 0.35 },
9201
+ { transform: "translateY(0) scale(0.97)", offset: 0.65 },
9202
+ { transform: "translateY(0) scale(1)" }
9203
+ ];
9204
+ var BOUNCE_MS = 420;
9205
+ var SUBTLE_SCROLLBAR = "[scrollbar-color:var(--floating-sidebar-scrollbar-thumb)_var(--floating-sidebar-scrollbar-track)]! [&::-webkit-scrollbar]:w-2.5! [&::-webkit-scrollbar-track]:bg-floating-sidebar-scrollbar-track! [&::-webkit-scrollbar-thumb]:rounded-full! [&::-webkit-scrollbar-thumb]:border-2! [&::-webkit-scrollbar-thumb]:border-solid! [&::-webkit-scrollbar-thumb]:border-floating-sidebar-scrollbar-track! [&::-webkit-scrollbar-thumb]:bg-floating-sidebar-scrollbar-thumb! [&::-webkit-scrollbar-thumb:hover]:bg-floating-sidebar-scrollbar-thumb-hover!";
9206
+ var DEFAULT_WIDTH = 276;
9207
+ var DEFAULT_COLLAPSED_WIDTH = 48;
9208
+ var MIN_COLLAPSED_WIDTH = 40;
9209
+ var t = (prop, ms = 300, delay = 0) => `${prop} ${ms}ms ${EASE} ${delay}ms`;
9210
+ function transition2(reduced, ...parts) {
9211
+ const kept = reduced ? parts.filter((part) => /^(opacity|visibility|background|color|box-shadow)/.test(part)) : parts;
9212
+ return kept.join(", ") || "none";
9213
+ }
9214
+ function useControllableState2(value, defaultValue, onChange) {
9215
+ const [internal, setInternal] = useState(defaultValue);
9216
+ const isControlled = value !== void 0;
9217
+ const current = isControlled ? value : internal;
9218
+ const setValue = useCallback(
9219
+ (next) => {
9220
+ if (!isControlled) setInternal(next);
9221
+ onChange?.(next);
9222
+ },
9223
+ [isControlled, onChange]
9224
+ );
9225
+ return [current, setValue];
9226
+ }
9227
+ var normalize = (value) => value.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
9228
+ function filterItems(items, query) {
9229
+ const needle = normalize(query.trim());
9230
+ return needle ? items.filter((item) => normalize(item.label).includes(needle)) : items;
9231
+ }
9232
+ var lastUsedSidebar = null;
9233
+ var SHORTCUT_SIDEBAR = '[data-slot="floating-sidebar"][data-shortcut]';
9234
+ function isEditableTarget(target) {
9235
+ if (!(target instanceof HTMLElement)) return false;
9236
+ if (target.closest('[data-slot="floating-sidebar-search"]')) return false;
9237
+ return target.closest('[contenteditable]:not([contenteditable="false"])') !== null || target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT";
9238
+ }
9239
+ function SidebarIcon({
9240
+ icon,
9241
+ resolveIcon,
9242
+ small = false
9243
+ }) {
9244
+ const resolved = typeof icon === "string" ? resolveIcon?.(icon) : icon;
9245
+ if (resolved === void 0 || resolved === null) {
9246
+ return /* @__PURE__ */ jsx("span", { "data-slot": "floating-sidebar-fallback-icon", className: "flex", children: /* @__PURE__ */ jsx(
9247
+ CircleDashed,
9248
+ {
9249
+ "aria-hidden": "true",
9250
+ className: small ? "size-[18px]" : "size-5",
9251
+ strokeWidth: 1.5
9252
+ }
9253
+ ) });
9254
+ }
9255
+ return /* @__PURE__ */ jsx(
9256
+ "span",
9257
+ {
9258
+ "data-slot": "floating-sidebar-icon",
9259
+ className: cn(
9260
+ "flex",
9261
+ "[&>svg]:stroke-[1.5]",
9262
+ small ? "[&>svg]:size-[18px]" : "[&>svg]:size-5"
9263
+ ),
9264
+ children: resolved
9265
+ }
9266
+ );
9267
+ }
9268
+ function FloatingSidebar({
9269
+ modules,
9270
+ resolveIcon,
9271
+ renderLink,
9272
+ open: openProp,
9273
+ defaultOpen = true,
9274
+ onOpenChange,
9275
+ side = "left",
9276
+ width = DEFAULT_WIDTH,
9277
+ collapsedWidth = DEFAULT_COLLAPSED_WIDTH,
9278
+ type = "single",
9279
+ openModuleIds: openModulesProp,
9280
+ defaultOpenModuleIds = [],
9281
+ onOpenModulesChange,
9282
+ hideEmptyModules = true,
9283
+ activeItemId: activeItemProp,
9284
+ defaultActiveItemId = null,
9285
+ onItemSelect,
9286
+ favoriteIds: favoritesProp,
9287
+ defaultFavoriteIds = [],
9288
+ onFavoritesChange,
9289
+ showFavorites = true,
9290
+ loading = false,
9291
+ emptyState,
9292
+ mobileOpen: mobileOpenProp,
9293
+ defaultMobileOpen = false,
9294
+ onMobileOpenChange,
9295
+ shortcut = true,
9296
+ labels: labelsProp,
9297
+ className,
9298
+ ref,
9299
+ style,
9300
+ onPointerDownCapture,
9301
+ onFocusCapture,
9302
+ ...navProps
9303
+ }) {
9304
+ const labels = { ...DEFAULT_LABELS, ...labelsProp };
9305
+ const reduced = useMediaQuery("(prefers-reduced-motion: reduce)");
9306
+ const isMobile = useIsMobile();
9307
+ const baseId = useId();
9308
+ const [open, setOpen] = useControllableState2(openProp, defaultOpen, onOpenChange);
9309
+ const [rawOpenModuleIds, setOpenModuleIds] = useControllableState2(
9310
+ openModulesProp,
9311
+ defaultOpenModuleIds,
9312
+ onOpenModulesChange
9313
+ );
9314
+ const railWidth = Math.max(MIN_COLLAPSED_WIDTH, collapsedWidth);
9315
+ const [activeItemId, setActiveItemId] = useControllableState2(
9316
+ activeItemProp,
9317
+ defaultActiveItemId
9318
+ );
9319
+ const [favoriteIds, setFavoriteIds] = useControllableState2(
9320
+ favoritesProp,
9321
+ defaultFavoriteIds,
9322
+ onFavoritesChange
9323
+ );
9324
+ const [mobileOpen, setMobileOpen] = useControllableState2(
9325
+ mobileOpenProp,
9326
+ defaultMobileOpen,
9327
+ onMobileOpenChange
9328
+ );
9329
+ const [queries, setQueries] = useState({});
9330
+ const [flyoutId, setFlyoutId] = useState(null);
9331
+ const [hoverId, setHoverId] = useState(null);
9332
+ const collapsed = !isMobile && !open;
9333
+ const [prevCollapsed, setPrevCollapsed] = useState(collapsed);
9334
+ const [settling, setSettling] = useState(false);
9335
+ if (prevCollapsed !== collapsed) {
9336
+ setPrevCollapsed(collapsed);
9337
+ setSettling(collapsed);
9338
+ setFlyoutId(null);
9339
+ setHoverId(null);
9340
+ }
9341
+ useEffect(() => {
9342
+ if (!settling) return;
9343
+ const timer = setTimeout(() => setSettling(false), MOTION_MS);
9344
+ return () => clearTimeout(timer);
9345
+ }, [settling]);
9346
+ const toggle = useCallback(() => setOpen(!open), [open, setOpen]);
9347
+ const navRef = useRef(null);
9348
+ useEffect(() => {
9349
+ if (!shortcut) return;
9350
+ const onKeyDown = (event) => {
9351
+ if (event.defaultPrevented || isEditableTarget(event.target)) return;
9352
+ if ((event.ctrlKey || event.metaKey) && !event.shiftKey && !event.altKey && event.key.toLowerCase() === "b") {
9353
+ const owner = event.target instanceof Element ? event.target.closest(SHORTCUT_SIDEBAR) : null;
9354
+ const nav2 = navRef.current;
9355
+ if (owner && owner !== nav2) return;
9356
+ if (!owner) {
9357
+ const fallback = lastUsedSidebar?.isConnected && lastUsedSidebar.matches(SHORTCUT_SIDEBAR) ? lastUsedSidebar : document.querySelector(SHORTCUT_SIDEBAR);
9358
+ if (fallback && fallback !== nav2) return;
9359
+ }
9360
+ event.preventDefault();
9361
+ if (isMobile) setMobileOpen(!mobileOpen);
9362
+ else toggle();
9363
+ }
9364
+ };
9365
+ document.addEventListener("keydown", onKeyDown);
9366
+ return () => document.removeEventListener("keydown", onKeyDown);
9367
+ }, [shortcut, toggle, isMobile, mobileOpen, setMobileOpen]);
9368
+ const selectItem = (item, module, navigates) => {
9369
+ if (navigates) setActiveItemId(item.id);
9370
+ setFlyoutId(null);
9371
+ if (isMobile) setMobileOpen(false);
9372
+ onItemSelect?.(item, module);
9373
+ };
9374
+ const toggleFavorite = (itemId) => setFavoriteIds(
9375
+ favoriteIds.includes(itemId) ? favoriteIds.filter((id) => id !== itemId) : [...favoriteIds, itemId]
9376
+ );
9377
+ const list = {
9378
+ activeItemId,
9379
+ favoriteIds: showFavorites ? favoriteIds : null,
9380
+ reduced,
9381
+ labels,
9382
+ resolveIcon,
9383
+ renderLink,
9384
+ onToggleFavorite: toggleFavorite
9385
+ };
9386
+ const toggleLabel = collapsed ? labels.expand : labels.collapse;
9387
+ const ability = useOptionalAbility();
9388
+ const usesPermissions = modules.some(
9389
+ (module) => module.permission || module.items.some((item) => item.permission)
9390
+ );
9391
+ const permissionsPending = usesPermissions && ability?.status === "loading";
9392
+ const isAllowed = (entry) => !entry.permission || ability?.status === "ready" && ability.can(entry.permission, entry.permissionMode);
9393
+ const authorizedModules = usesPermissions ? modules.filter(isAllowed).flatMap((module) => {
9394
+ const items = module.items.filter(isAllowed);
9395
+ return items.length > 0 || module.items.length === 0 ? [{ ...module, items }] : [];
9396
+ }) : modules;
9397
+ const showSkeletons = loading || permissionsPending;
9398
+ const visibleModules = hideEmptyModules ? authorizedModules.filter((module) => module.items.length > 0) : authorizedModules;
9399
+ const visibleModuleIds = new Set(visibleModules.map((module) => module.id));
9400
+ const openModuleIds = type === "single" ? rawOpenModuleIds.filter((id) => visibleModuleIds.has(id)).slice(0, 1) : rawOpenModuleIds;
9401
+ const toggleModule = (moduleId) => {
9402
+ const isOpen = openModuleIds.includes(moduleId);
9403
+ if (type === "multiple") {
9404
+ setOpenModuleIds(
9405
+ isOpen ? openModuleIds.filter((id) => id !== moduleId) : [...openModuleIds, moduleId]
9406
+ );
9407
+ } else {
9408
+ setOpenModuleIds(isOpen ? [] : [moduleId]);
9409
+ }
9410
+ };
9411
+ const nav = /* @__PURE__ */ jsxs(
9412
+ "nav",
9413
+ {
9414
+ ...navProps,
9415
+ ref: (node) => {
9416
+ navRef.current = node;
9417
+ if (typeof ref === "function") return ref(node);
9418
+ if (ref) ref.current = node;
9419
+ },
9420
+ onPointerDownCapture: (event) => {
9421
+ lastUsedSidebar = event.currentTarget;
9422
+ onPointerDownCapture?.(event);
9423
+ },
9424
+ onFocusCapture: (event) => {
9425
+ lastUsedSidebar = event.currentTarget;
9426
+ onFocusCapture?.(event);
9427
+ },
9428
+ "data-slot": "floating-sidebar",
9429
+ "data-shortcut": shortcut ? "" : void 0,
9430
+ "data-state": collapsed ? "collapsed" : "expanded",
9431
+ "data-side": side,
9432
+ "aria-label": labels.navigation,
9433
+ "aria-busy": showSkeletons || void 0,
9434
+ className: cn(
9435
+ "flex h-full min-h-0 flex-col gap-3",
9436
+ // useIsMobile only resolves after mount; hide the inline layout on phones with CSS
9437
+ // so the first paint never shows it before the drawer takes over.
9438
+ !isMobile && "max-md:hidden",
9439
+ className
9440
+ ),
9441
+ style: isMobile ? style : {
9442
+ ...style,
9443
+ width: collapsed ? railWidth : width,
9444
+ transition: transition2(reduced, t("width", MOTION_MS))
9445
+ },
9446
+ children: [
9447
+ /* @__PURE__ */ jsxs(
9448
+ "div",
9449
+ {
9450
+ "data-slot": "floating-sidebar-header",
9451
+ className: cn(
9452
+ "flex h-10 shrink-0 items-center",
9453
+ side === "right" && "flex-row-reverse"
9454
+ ),
9455
+ children: [
9456
+ /* @__PURE__ */ jsx(
9457
+ "span",
9458
+ {
9459
+ title: labels.title,
9460
+ className: "text-muted-foreground overflow-hidden pl-1.5 text-[11px] font-medium tracking-[.12em] text-ellipsis whitespace-nowrap uppercase",
9461
+ style: {
9462
+ opacity: collapsed ? 0 : 1,
9463
+ maxWidth: collapsed ? 0 : 200,
9464
+ transition: transition2(
9465
+ reduced,
9466
+ t("opacity", FADE_MS, collapsed ? 0 : FADE_MS),
9467
+ t("max-width", MOTION_MS)
9468
+ )
9469
+ },
9470
+ children: labels.title
9471
+ }
9472
+ ),
9473
+ !isMobile && /* @__PURE__ */ jsx(
9474
+ "button",
9475
+ {
9476
+ type: "button",
9477
+ "data-slot": "floating-sidebar-toggle",
9478
+ "aria-label": toggleLabel,
9479
+ "aria-expanded": !collapsed,
9480
+ title: shortcut ? `${toggleLabel} (Ctrl/\u2318 + B)` : toggleLabel,
9481
+ onClick: toggle,
9482
+ className: cn(
9483
+ "text-primary focus-visible:ring-primary bg-sidebar border-floating-sidebar-card-border hover:bg-floating-sidebar-toggle-hover flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-full border shadow-[0_2px_6px_color-mix(in_srgb,var(--color-primary)_6%,transparent)] outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
9484
+ side === "right" ? "mr-auto" : "ml-auto"
9485
+ ),
9486
+ style: {
9487
+ // The auto margin keeps the toggle on the edge while the width animates;
9488
+ // only the outer margin changes, to center it on the collapsed rail.
9489
+ // (`auto` cannot be interpolated, so animating it made the toggle jump.)
9490
+ [side === "right" ? "marginLeft" : "marginRight"]: collapsed ? (railWidth - 32) / 2 : 0,
9491
+ transition: transition2(
9492
+ reduced,
9493
+ t(side === "right" ? "margin-left" : "margin-right", MOTION_MS)
9494
+ )
9495
+ },
9496
+ children: /* @__PURE__ */ jsx(
9497
+ "span",
9498
+ {
9499
+ className: "flex",
9500
+ style: {
9501
+ // The chevrons point towards the edge when they collapse the sidebar.
9502
+ transform: collapsed !== (side === "right") ? "rotate(180deg)" : "rotate(0deg)",
9503
+ transition: transition2(reduced, t("transform", MOTION_MS))
9504
+ },
9505
+ children: /* @__PURE__ */ jsx(ChevronsLeft, { "aria-hidden": "true", className: "size-5", strokeWidth: 1.5 })
9506
+ }
9507
+ )
9508
+ }
9509
+ )
9510
+ ]
9511
+ }
9512
+ ),
9513
+ /* @__PURE__ */ jsxs(
9514
+ "div",
9515
+ {
9516
+ "data-slot": "floating-sidebar-modules",
9517
+ className: "flex min-h-0 flex-1 flex-col",
9518
+ style: {
9519
+ gap: collapsed ? 8 : 12,
9520
+ transition: transition2(reduced, t("gap", MOTION_MS))
9521
+ },
9522
+ children: [
9523
+ showSkeletons && Array.from({ length: 4 }, (_, index) => /* @__PURE__ */ jsx("div", { "data-slot": "floating-sidebar-skeleton", children: /* @__PURE__ */ jsx(
9524
+ Skeleton,
9525
+ {
9526
+ className: collapsed ? "rounded-[14px]" : "h-[58px] w-full rounded-2xl",
9527
+ style: collapsed ? { width: railWidth, height: railWidth } : void 0
9528
+ }
9529
+ ) }, index)),
9530
+ !showSkeletons && visibleModules.length === 0 && emptyState,
9531
+ !showSkeletons && visibleModules.map((module) => /* @__PURE__ */ jsx(
9532
+ ModuleCard,
9533
+ {
9534
+ tileSize: railWidth,
9535
+ module,
9536
+ regionId: `${baseId}-${module.id}`,
9537
+ flyoutRegionId: `${baseId}-${module.id}-flyout`,
9538
+ bodyWidth: isMobile ? void 0 : width - 2,
9539
+ collapsed,
9540
+ side,
9541
+ open: !collapsed && openModuleIds.includes(module.id),
9542
+ flyoutOpen: collapsed && flyoutId === module.id,
9543
+ anyFlyoutOpen: collapsed && flyoutId !== null,
9544
+ settling,
9545
+ tooltipOpen: collapsed && hoverId === module.id && !flyoutId,
9546
+ onTooltipOpenChange: (next) => setHoverId(
9547
+ (current) => next ? module.id : current === module.id ? null : current
9548
+ ),
9549
+ onFlyoutClose: () => setFlyoutId((current) => current === module.id ? null : current),
9550
+ list,
9551
+ query: queries[module.id] ?? "",
9552
+ onQueryChange: (query) => setQueries((current) => ({ ...current, [module.id]: query })),
9553
+ onHeaderClick: () => {
9554
+ if (collapsed) {
9555
+ setHoverId(null);
9556
+ setFlyoutId(flyoutId === module.id ? null : module.id);
9557
+ } else {
9558
+ toggleModule(module.id);
9559
+ }
9560
+ },
9561
+ onSelect: (item, navigates) => selectItem(item, module, navigates)
9562
+ },
9563
+ module.id
9564
+ ))
9565
+ ]
9566
+ }
9567
+ )
9568
+ ]
9569
+ }
9570
+ );
9571
+ if (isMobile) {
9572
+ return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: /* @__PURE__ */ jsxs(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
9573
+ mobileOpenProp === void 0 && /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
9574
+ "button",
9575
+ {
9576
+ type: "button",
9577
+ "data-slot": "floating-sidebar-mobile-trigger",
9578
+ "aria-label": labels.openMenu,
9579
+ className: "text-primary focus-visible:ring-primary bg-sidebar hover:bg-sidebar-accent flex size-10 cursor-pointer items-center justify-center rounded-[10px] shadow-[0_8px_24px_color-mix(in_srgb,var(--color-primary)_8%,transparent)] outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
9580
+ children: /* @__PURE__ */ jsx(Menu, { "aria-hidden": "true", className: "size-5", strokeWidth: 1.5 })
9581
+ }
9582
+ ) }),
9583
+ /* @__PURE__ */ jsxs(
9584
+ SheetContent,
9585
+ {
9586
+ side,
9587
+ "aria-describedby": void 0,
9588
+ className: "p-4 pt-12",
9589
+ onEscapeKeyDown: (event) => {
9590
+ const active = document.activeElement;
9591
+ if (active instanceof HTMLInputElement && active.value && active.closest('[data-slot="floating-sidebar-search"]')) {
9592
+ event.preventDefault();
9593
+ }
9594
+ },
9595
+ children: [
9596
+ /* @__PURE__ */ jsx(SheetTitle, { className: "sr-only", children: labels.title }),
9597
+ nav
9598
+ ]
9599
+ }
9600
+ )
9601
+ ] }) });
9602
+ }
9603
+ return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 300, children: nav });
9604
+ }
9605
+ function ModuleSearch({
9606
+ moduleLabel,
9607
+ query,
9608
+ focusable,
9609
+ labels,
9610
+ onQueryChange,
9611
+ className
9612
+ }) {
9613
+ const tabIndex = focusable ? 0 : -1;
9614
+ const inputRef = useRef(null);
9615
+ return /* @__PURE__ */ jsxs(
9616
+ "div",
9617
+ {
9618
+ "data-slot": "floating-sidebar-search",
9619
+ className: cn(
9620
+ "text-muted-foreground border-floating-sidebar-search-border bg-floating-sidebar-search flex h-[38px] items-center gap-2 rounded-[10px] border pr-1 pl-3",
9621
+ className
9622
+ ),
9623
+ children: [
9624
+ /* @__PURE__ */ jsx(Search, { "aria-hidden": "true", className: "size-4 shrink-0", strokeWidth: 1.5 }),
9625
+ /* @__PURE__ */ jsx(
9626
+ "input",
9627
+ {
9628
+ ref: inputRef,
9629
+ type: "search",
9630
+ "aria-label": labels.searchLabel(moduleLabel),
9631
+ placeholder: labels.searchPlaceholder(moduleLabel),
9632
+ tabIndex,
9633
+ value: query,
9634
+ onChange: (event) => onQueryChange(event.target.value),
9635
+ onKeyDown: (event) => {
9636
+ if (event.key === "Escape" && query) {
9637
+ event.stopPropagation();
9638
+ onQueryChange("");
9639
+ }
9640
+ },
9641
+ className: "text-foreground placeholder:text-muted-foreground h-[34px] min-w-0 flex-1 border-0 bg-transparent p-0 text-[13px] outline-none [&::-webkit-search-cancel-button]:appearance-none"
9642
+ }
9643
+ ),
9644
+ query && /* @__PURE__ */ jsx(
9645
+ "button",
9646
+ {
9647
+ type: "button",
9648
+ "aria-label": labels.clearSearch,
9649
+ tabIndex,
9650
+ onClick: () => {
9651
+ onQueryChange("");
9652
+ inputRef.current?.focus();
9653
+ },
9654
+ className: "focus-visible:ring-primary hover:bg-accent/60 flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-lg border-0 bg-transparent outline-none focus-visible:ring-2",
9655
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "size-4", strokeWidth: 1.5 })
9656
+ }
9657
+ )
9658
+ ]
9659
+ }
9660
+ );
9661
+ }
9662
+ function NoMatches({
9663
+ show,
9664
+ moduleLabel,
9665
+ query,
9666
+ labels,
9667
+ compact
9668
+ }) {
9669
+ return /* @__PURE__ */ jsx("div", { role: "status", "data-slot": "floating-sidebar-no-matches", children: show && /* @__PURE__ */ jsx(
9670
+ NoMatchesMessage,
9671
+ {
9672
+ moduleLabel,
9673
+ query,
9674
+ labels,
9675
+ compact
9676
+ }
9677
+ ) });
9678
+ }
9679
+ function NoMatchesMessage({
9680
+ moduleLabel,
9681
+ query,
9682
+ labels,
9683
+ compact = false
9684
+ }) {
9685
+ return /* @__PURE__ */ jsxs(
9686
+ "div",
9687
+ {
9688
+ className: cn(
9689
+ "flex flex-col items-center text-center",
9690
+ compact ? "gap-1 px-3 py-4" : "gap-1.5 px-3 py-5"
9691
+ ),
9692
+ children: [
9693
+ !compact && /* @__PURE__ */ jsx(
9694
+ Search,
9695
+ {
9696
+ "aria-hidden": "true",
9697
+ className: "text-muted-foreground size-5",
9698
+ strokeWidth: 1.5
9699
+ }
9700
+ ),
9701
+ /* @__PURE__ */ jsx("span", { className: "text-primary text-sm font-semibold", children: labels.noMatchesTitle }),
9702
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-[13px] leading-[1.4]", children: compact ? labels.flyoutNoMatches(query) : labels.noMatches(moduleLabel, query) })
9703
+ ]
9704
+ }
9705
+ );
9706
+ }
9707
+ function ModuleCard({
9708
+ module,
9709
+ tileSize,
9710
+ regionId,
9711
+ flyoutRegionId,
9712
+ bodyWidth,
9713
+ side,
9714
+ collapsed,
9715
+ open,
9716
+ flyoutOpen,
9717
+ anyFlyoutOpen,
9718
+ settling,
9719
+ tooltipOpen,
9720
+ onTooltipOpenChange,
9721
+ onFlyoutClose,
9722
+ list,
9723
+ query,
9724
+ onQueryChange,
9725
+ onHeaderClick,
9726
+ onSelect
9727
+ }) {
9728
+ const { activeItemId, reduced, labels, resolveIcon } = list;
9729
+ const hasActive = module.items.some((item) => item.id === activeItemId);
9730
+ const tileActive = collapsed && hasActive;
9731
+ const tileSelected = anyFlyoutOpen ? flyoutOpen : tileActive;
9732
+ const fillAfterCollapse = tileSelected && tileActive && settling && !reduced;
9733
+ const fillTransition = fillAfterCollapse ? `0ms linear ${MOTION_MS}ms` : `${FADE_MS}ms linear 0ms`;
9734
+ const iconFlipDelay = fillAfterCollapse ? MOTION_MS : FADE_MS / 2;
9735
+ const tilePadding = (tileSize - 2 - 20) / 2;
9736
+ const cardRef = useRef(null);
9737
+ const wasCollapsed = useRef(collapsed);
9738
+ useEffect(() => {
9739
+ const justCollapsed = collapsed && !wasCollapsed.current;
9740
+ wasCollapsed.current = collapsed;
9741
+ if (!justCollapsed || !hasActive || reduced) return;
9742
+ const animation2 = cardRef.current?.animate?.(BOUNCE_KEYFRAMES, {
9743
+ duration: BOUNCE_MS,
9744
+ delay: MOTION_MS,
9745
+ easing: "ease-out"
9746
+ });
9747
+ return () => animation2?.cancel();
9748
+ }, [collapsed, hasActive, reduced]);
9749
+ const items = filterItems(module.items, query);
9750
+ const isEmpty = module.items.length === 0;
9751
+ const emptyMessage = /* @__PURE__ */ jsx(
9752
+ "p",
9753
+ {
9754
+ "data-slot": "floating-sidebar-empty-module",
9755
+ className: "text-muted-foreground px-3 py-4 text-center text-[13px] leading-[1.4]",
9756
+ children: labels.emptyModule
9757
+ }
9758
+ );
9759
+ const tileRef = useRef(null);
9760
+ const closedFromOutside = useRef(false);
9761
+ const skipNextTooltip = useRef(false);
9762
+ return /* @__PURE__ */ jsx(Popover, { open: flyoutOpen, onOpenChange: (next) => !next && onFlyoutClose(), children: /* @__PURE__ */ jsxs(
9763
+ "div",
9764
+ {
9765
+ ref: cardRef,
9766
+ "data-slot": "floating-sidebar-module",
9767
+ "data-module-id": module.id,
9768
+ "data-state": open ? "open" : "closed",
9769
+ "data-active": hasActive ? "true" : void 0,
9770
+ className: cn(
9771
+ "relative flex min-h-0 w-full flex-col",
9772
+ "border",
9773
+ collapsed ? "rounded-[14px]" : "rounded-2xl",
9774
+ tileSelected ? "border-primary bg-primary" : "bg-sidebar border-floating-sidebar-card-border",
9775
+ open ? "shadow-[0_8px_24px_color-mix(in_srgb,var(--color-primary)_8%,transparent)]" : "shadow-[0_2px_8px_color-mix(in_srgb,var(--color-primary)_4%,transparent)]"
9776
+ ),
9777
+ style: {
9778
+ flex: open ? "0 1 auto" : "0 0 auto",
9779
+ transition: transition2(
9780
+ reduced,
9781
+ t("border-radius", MOTION_MS),
9782
+ `background-color ${fillTransition}`,
9783
+ `border-color ${fillTransition}`,
9784
+ t("box-shadow", MOTION_MS)
9785
+ )
9786
+ },
9787
+ children: [
9788
+ /* @__PURE__ */ jsxs(
9789
+ Tooltip,
9790
+ {
9791
+ open: tooltipOpen,
9792
+ onOpenChange: (next) => {
9793
+ if (next && skipNextTooltip.current) return;
9794
+ onTooltipOpenChange(collapsed && next);
9795
+ },
9796
+ children: [
9797
+ /* @__PURE__ */ jsx(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
9798
+ "button",
9799
+ {
9800
+ ref: tileRef,
9801
+ type: "button",
9802
+ "data-slot": "floating-sidebar-module-trigger",
9803
+ "aria-label": collapsed && hasActive ? module.label + labels.currentPageSuffix : module.label,
9804
+ "aria-expanded": collapsed ? flyoutOpen : open,
9805
+ "aria-controls": collapsed ? flyoutOpen ? flyoutRegionId : void 0 : regionId,
9806
+ onClick: onHeaderClick,
9807
+ className: cn(
9808
+ "group/head focus-visible:ring-primary relative flex w-full shrink-0 cursor-pointer items-center gap-3 overflow-hidden border-0 bg-transparent text-left outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
9809
+ collapsed ? "rounded-[14px]" : "h-[58px] rounded-2xl",
9810
+ tileSelected ? "text-primary-foreground" : "text-primary"
9811
+ ),
9812
+ style: {
9813
+ // Collapsed: a square tile (border included) with the icon centered.
9814
+ ...collapsed && { height: tileSize - 2 },
9815
+ paddingLeft: collapsed ? tilePadding : 20,
9816
+ paddingRight: collapsed ? tilePadding : 20,
9817
+ transition: transition2(
9818
+ reduced,
9819
+ t("height", MOTION_MS),
9820
+ t("padding", MOTION_MS),
9821
+ `color 0ms linear ${iconFlipDelay}ms`,
9822
+ t("border-radius", MOTION_MS)
9823
+ )
9824
+ },
9825
+ children: [
9826
+ /* @__PURE__ */ jsx(
9827
+ "span",
9828
+ {
9829
+ "aria-hidden": "true",
9830
+ "data-slot": "floating-sidebar-module-hover",
9831
+ className: cn(
9832
+ "pointer-events-none absolute transition-colors duration-180 ease-out",
9833
+ // Inset on expanded cards; edge to edge on collapsed tiles.
9834
+ collapsed ? "inset-0 rounded-[inherit]" : "inset-1.5 rounded-[10px]",
9835
+ !open && (tileSelected ? "group-hover/head:bg-primary-foreground/12" : "group-hover/head:bg-floating-sidebar-hover")
9836
+ )
9837
+ }
9838
+ ),
9839
+ /* @__PURE__ */ jsx(
9840
+ "span",
9841
+ {
9842
+ "data-slot": "floating-sidebar-module-icon",
9843
+ className: "relative flex shrink-0 items-center justify-center",
9844
+ children: /* @__PURE__ */ jsx(SidebarIcon, { icon: module.icon, resolveIcon })
9845
+ }
9846
+ ),
9847
+ /* @__PURE__ */ jsx(
9848
+ "span",
9849
+ {
9850
+ "data-slot": "floating-sidebar-module-label",
9851
+ "aria-hidden": collapsed || void 0,
9852
+ className: "relative min-w-0 flex-1 text-sm font-medium whitespace-nowrap",
9853
+ style: {
9854
+ opacity: collapsed ? 0 : 1,
9855
+ transition: transition2(
9856
+ reduced,
9857
+ t("opacity", FADE_MS, collapsed ? 0 : FADE_MS)
9858
+ )
9859
+ },
9860
+ children: module.label
9861
+ }
9862
+ ),
9863
+ /* @__PURE__ */ jsx(
9864
+ "span",
9865
+ {
9866
+ "data-slot": "floating-sidebar-module-chevron",
9867
+ "aria-hidden": "true",
9868
+ className: cn(
9869
+ "relative flex shrink-0",
9870
+ !tileSelected && "text-muted-foreground"
9871
+ ),
9872
+ style: {
9873
+ opacity: collapsed ? 0 : 1,
9874
+ transform: open ? "rotate(180deg)" : "rotate(0deg)",
9875
+ transition: transition2(
9876
+ reduced,
9877
+ t("transform", 220),
9878
+ t("opacity", FADE_MS, collapsed ? 0 : FADE_MS)
9879
+ )
9880
+ },
9881
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5", strokeWidth: 1.5 })
9882
+ }
9883
+ )
9884
+ ]
9885
+ }
9886
+ ) }) }),
9887
+ collapsed && /* @__PURE__ */ jsx(
9888
+ TooltipContent,
9889
+ {
9890
+ side: side === "right" ? "left" : "right",
9891
+ sideOffset: 12,
9892
+ "data-slot": "floating-sidebar-tooltip",
9893
+ children: module.label
9894
+ }
9895
+ )
9896
+ ]
9897
+ }
9898
+ ),
9899
+ /* @__PURE__ */ jsx(
9900
+ "div",
9901
+ {
9902
+ className: "grid min-h-0 flex-[1_1_auto]",
9903
+ style: {
9904
+ gridTemplateRows: open ? "1fr" : "0fr",
9905
+ transition: transition2(reduced, t("grid-template-rows", MOTION_MS))
9906
+ },
9907
+ children: /* @__PURE__ */ jsx(
9908
+ "div",
9909
+ {
9910
+ id: regionId,
9911
+ "data-slot": "floating-sidebar-module-content",
9912
+ "data-state": open ? "open" : "closed",
9913
+ "data-scroll": "muted",
9914
+ className: cn("min-h-0 overflow-x-hidden", SUBTLE_SCROLLBAR),
9915
+ style: {
9916
+ overflowY: open ? "auto" : "hidden",
9917
+ visibility: open ? "visible" : "hidden",
9918
+ transition: open ? "visibility 0s" : `visibility 0s linear ${MOTION_MS}ms`
9919
+ },
9920
+ children: /* @__PURE__ */ jsxs("div", { "data-slot": "floating-sidebar-module-body", style: { width: bodyWidth }, children: [
9921
+ isEmpty && emptyMessage,
9922
+ !isEmpty && /* @__PURE__ */ jsx(
9923
+ "div",
9924
+ {
9925
+ "data-slot": "floating-sidebar-search-bar",
9926
+ className: "bg-sidebar sticky top-0 z-[2] px-3 pb-3",
9927
+ children: /* @__PURE__ */ jsx(
9928
+ ModuleSearch,
9929
+ {
9930
+ moduleLabel: module.label,
9931
+ query,
9932
+ focusable: open,
9933
+ labels,
9934
+ onQueryChange
9935
+ }
9936
+ )
9937
+ }
9938
+ ),
9939
+ !isEmpty && /* @__PURE__ */ jsx(
9940
+ "ul",
9941
+ {
9942
+ "data-slot": "floating-sidebar-item-list",
9943
+ className: "flex flex-col gap-0.5 px-3 pb-3",
9944
+ children: items.map((item, index) => /* @__PURE__ */ jsx(
9945
+ ItemRow,
9946
+ {
9947
+ item,
9948
+ list,
9949
+ visible: open,
9950
+ staggerIndex: index,
9951
+ onSelect: (navigates) => onSelect(item, navigates)
9952
+ },
9953
+ item.id
9954
+ ))
9955
+ }
9956
+ ),
9957
+ !isEmpty && /* @__PURE__ */ jsx(
9958
+ NoMatches,
9959
+ {
9960
+ show: items.length === 0,
9961
+ moduleLabel: module.label,
9962
+ query,
9963
+ labels
9964
+ }
9965
+ )
9966
+ ] })
9967
+ }
9968
+ )
9969
+ }
9970
+ ),
9971
+ collapsed && /* @__PURE__ */ jsxs(
9972
+ PopoverContent,
9973
+ {
9974
+ id: flyoutRegionId,
9975
+ role: "group",
9976
+ "aria-label": module.label,
9977
+ "data-slot": "floating-sidebar-flyout",
9978
+ "data-side": side,
9979
+ side: side === "right" ? "left" : "right",
9980
+ align: "start",
9981
+ sideOffset: 16,
9982
+ collisionPadding: 8,
9983
+ className: "ring-floating-sidebar-card-border max-h-(--radix-popover-content-available-height) w-[268px] gap-0 rounded-2xl px-2 pt-4 pb-2",
9984
+ onEscapeKeyDown: (event) => {
9985
+ if (!query) return;
9986
+ event.preventDefault();
9987
+ onQueryChange("");
9988
+ },
9989
+ onInteractOutside: (event) => {
9990
+ if (tileRef.current?.contains(event.target)) {
9991
+ event.preventDefault();
9992
+ return;
9993
+ }
9994
+ closedFromOutside.current = true;
9995
+ },
9996
+ onCloseAutoFocus: (event) => {
9997
+ event.preventDefault();
9998
+ if (!closedFromOutside.current) {
9999
+ skipNextTooltip.current = true;
10000
+ tileRef.current?.focus();
10001
+ skipNextTooltip.current = false;
10002
+ }
10003
+ closedFromOutside.current = false;
10004
+ },
10005
+ children: [
10006
+ /* @__PURE__ */ jsx(
10007
+ "div",
10008
+ {
10009
+ "data-slot": "floating-sidebar-flyout-title",
10010
+ className: "text-muted-foreground px-3 pb-2.5 text-[11px] font-medium tracking-[.1em] uppercase",
10011
+ children: module.label
10012
+ }
10013
+ ),
10014
+ isEmpty && emptyMessage,
10015
+ !isEmpty && /* @__PURE__ */ jsx(
10016
+ ModuleSearch,
10017
+ {
10018
+ moduleLabel: module.label,
10019
+ query,
10020
+ focusable: flyoutOpen,
10021
+ labels,
10022
+ onQueryChange,
10023
+ className: "mx-2 mb-2"
10024
+ }
10025
+ ),
10026
+ /* @__PURE__ */ jsxs(
10027
+ "div",
10028
+ {
10029
+ "data-slot": "floating-sidebar-flyout-list",
10030
+ "data-scroll": "muted",
10031
+ className: cn(
10032
+ "max-h-[420px] min-h-0 overflow-y-auto",
10033
+ SUBTLE_SCROLLBAR
10034
+ ),
10035
+ children: [
10036
+ !isEmpty && /* @__PURE__ */ jsx(
10037
+ "ul",
10038
+ {
10039
+ "data-slot": "floating-sidebar-item-list",
10040
+ className: "flex flex-col gap-0.5",
10041
+ children: items.map((item) => /* @__PURE__ */ jsx(
10042
+ ItemRow,
10043
+ {
10044
+ item,
10045
+ list,
10046
+ visible: flyoutOpen,
10047
+ onSelect: (navigates) => onSelect(item, navigates)
10048
+ },
10049
+ item.id
10050
+ ))
10051
+ }
10052
+ ),
10053
+ !isEmpty && /* @__PURE__ */ jsx(
10054
+ NoMatches,
10055
+ {
10056
+ show: items.length === 0,
10057
+ moduleLabel: module.label,
10058
+ query,
10059
+ labels,
10060
+ compact: true
10061
+ }
10062
+ )
10063
+ ]
10064
+ }
10065
+ )
10066
+ ]
10067
+ }
10068
+ )
10069
+ ]
10070
+ }
10071
+ ) });
10072
+ }
10073
+ function ItemRow({ item, list, visible, staggerIndex, onSelect }) {
10074
+ const { activeItemId, favoriteIds, reduced, labels, resolveIcon, renderLink } = list;
10075
+ const active = item.id === activeItemId;
10076
+ const favorite = favoriteIds?.includes(item.id) ?? false;
10077
+ const tabIndex = visible ? 0 : -1;
10078
+ const staggered = staggerIndex !== void 0;
10079
+ const delay = staggered && visible ? Math.min(staggerIndex * 20, FADE_MS) : 0;
10080
+ const rowStyle = staggered ? {
10081
+ opacity: visible ? 1 : 0,
10082
+ transition: transition2(
10083
+ reduced,
10084
+ t("opacity", FADE_MS, delay),
10085
+ "background-color 180ms ease-out"
10086
+ )
10087
+ } : { transition: "background-color 180ms ease-out" };
10088
+ const className = cn(
10089
+ "focus-visible:ring-primary flex min-h-[46px] min-w-0 flex-1 cursor-pointer items-start gap-3 rounded-[10px] border-0 bg-transparent py-[13px] pr-1 pl-3 text-left text-[13px] leading-5 transition-transform duration-180 ease-[cubic-bezier(.2,.8,.2,1)] outline-none hover:text-primary focus-visible:ring-2 focus-visible:ring-inset disabled:cursor-not-allowed disabled:opacity-50",
10090
+ active ? "text-primary font-bold" : "font-normal text-floating-sidebar-item-foreground hover:translate-x-0.5 motion-reduce:hover:translate-x-0"
10091
+ );
10092
+ const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
10093
+ /* @__PURE__ */ jsx(
10094
+ "span",
10095
+ {
10096
+ className: cn("flex shrink-0", active ? "text-primary" : "text-muted-foreground"),
10097
+ children: /* @__PURE__ */ jsx(SidebarIcon, { icon: item.icon, resolveIcon, small: true })
10098
+ }
10099
+ ),
10100
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 [overflow-wrap:anywhere]", children: item.label })
10101
+ ] });
10102
+ const common = {
10103
+ className,
10104
+ tabIndex,
10105
+ "aria-current": active ? "page" : void 0,
10106
+ "data-slot": "floating-sidebar-item",
10107
+ "data-active": active ? "true" : void 0
10108
+ };
10109
+ let control;
10110
+ if (item.href && !item.disabled) {
10111
+ const linkProps = {
10112
+ ...common,
10113
+ href: item.href,
10114
+ children: content,
10115
+ // Only a plain click on an in-app link moves the current page; external links and
10116
+ // modifier or middle clicks open elsewhere and leave this tab where it is.
10117
+ onClick: (event) => onSelect(
10118
+ !item.external && event.button === 0 && !(event.ctrlKey || event.metaKey || event.shiftKey || event.altKey)
10119
+ ),
10120
+ ...item.external ? { target: "_blank", rel: "noopener noreferrer" } : {}
10121
+ };
10122
+ control = renderLink ? renderLink(linkProps, item) : /* @__PURE__ */ jsx("a", { ...linkProps });
10123
+ } else {
10124
+ control = /* @__PURE__ */ jsx(
10125
+ "button",
10126
+ {
10127
+ type: "button",
10128
+ ...common,
10129
+ disabled: item.disabled,
10130
+ onClick: () => onSelect(false),
10131
+ children: content
10132
+ }
10133
+ );
10134
+ }
10135
+ const favoriteLabel = favorite ? labels.removeFavorite(item.label) : labels.addFavorite(item.label);
10136
+ return /* @__PURE__ */ jsxs(
10137
+ "li",
10138
+ {
10139
+ "data-slot": "floating-sidebar-item-row",
10140
+ className: cn(
10141
+ "group/row relative flex shrink-0 items-start rounded-[10px]",
10142
+ active ? "bg-accent/70" : "hover:bg-floating-sidebar-hover"
10143
+ ),
10144
+ style: rowStyle,
10145
+ children: [
10146
+ /* @__PURE__ */ jsx(
10147
+ "span",
10148
+ {
10149
+ "aria-hidden": "true",
10150
+ "data-slot": "floating-sidebar-item-indicator",
10151
+ className: "bg-floating-sidebar-indicator absolute top-3.5 bottom-3.5 left-0 w-[3px] rounded-r-[3px]",
10152
+ style: { opacity: active ? 1 : 0, transition: "opacity 160ms ease-out" }
10153
+ }
10154
+ ),
10155
+ control,
10156
+ favoriteIds && item.favoritable !== false && /* @__PURE__ */ jsx(
10157
+ "button",
10158
+ {
10159
+ type: "button",
10160
+ "data-slot": "floating-sidebar-favorite",
10161
+ "data-favorite": favorite ? "true" : void 0,
10162
+ "aria-pressed": favorite,
10163
+ "aria-label": favoriteLabel,
10164
+ title: favoriteLabel,
10165
+ tabIndex,
10166
+ onClick: (event) => {
10167
+ event.stopPropagation();
10168
+ if (!reduced) {
10169
+ event.currentTarget.animate?.(
10170
+ [
10171
+ { transform: "scale(1)" },
10172
+ { transform: "scale(1.3)" },
10173
+ { transform: "scale(1)" }
10174
+ ],
10175
+ { duration: 220, easing: "ease-out" }
10176
+ );
10177
+ }
10178
+ list.onToggleFavorite(item.id);
10179
+ },
10180
+ className: cn(
10181
+ "focus-visible:ring-primary hover:bg-primary/6 mt-[9px] mr-1.5 flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-lg border-0 bg-transparent outline-none focus-visible:ring-2",
10182
+ "hover:text-secondary",
10183
+ // Stars stay hidden until their row is hovered or focused, unless favorited.
10184
+ favorite ? "text-secondary opacity-100" : (
10185
+ // Revealed on row hover or focus; always shown on touch, where there is no hover.
10186
+ "text-muted-foreground opacity-0 group-focus-within/row:opacity-100 group-hover/row:opacity-100 [@media(hover:none)]:opacity-100"
10187
+ )
10188
+ ),
10189
+ style: {
10190
+ transition: "color 120ms ease-out, background 120ms ease-out, opacity 120ms ease-out"
10191
+ },
10192
+ children: /* @__PURE__ */ jsx(
10193
+ Star,
10194
+ {
10195
+ "aria-hidden": "true",
10196
+ className: cn("size-3.5", favorite && "fill-secondary/10"),
10197
+ strokeWidth: 1.5
10198
+ }
10199
+ )
10200
+ }
10201
+ )
10202
+ ]
10203
+ }
10204
+ );
10205
+ }
9177
10206
  var DrawerContext = createContext({ isOpen: false, modal: true });
9178
10207
  function Drawer({ children, open, onOpenChange, modal = true, ...props }) {
9179
10208
  const [internalOpen, setInternalOpen] = useState(props.defaultOpen ?? false);
@@ -9602,6 +10631,6 @@ function TCCEProvider({
9602
10631
  return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: tooltipDelayDuration, children: /* @__PURE__ */ jsx(AbilityProvider, { permissions, children: /* @__PURE__ */ jsx(Toaster, { position: toasterPosition, children }) }) });
9603
10632
  }
9604
10633
 
9605
- export { AbilityProvider, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge2 as Badge, BottomNav, BottomNavTabs, BottomNavTabsContent, BottomNavTabsList, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CONFETTI_COLORS, Can, CanNot, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, Checkbox, ColorPicker, ColorPickerAlpha, ColorPickerEyeDropper, ColorPickerFormat, ColorPickerHue, ColorPickerOutput, ColorPickerPresets, ColorPickerSelection, Combobox, DataTable, DataTableCardView, DataTableColumnFilter, DataTableFooter, DataTableHeaderCell, DataTableRowActions, DataTableSearch, DataTableSkeleton, DataTableToolbar, DatePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, DropzoneContent, DropzoneEmptyState, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EventCalendar, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, FilterOption, Input, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, KNOWN_PERMISSIONS, Label, Link, Logo, MiniCalendar, MiniCalendarDay, MiniCalendarDays, MiniCalendarNavigation, Navbar, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PhoneField, PinInput, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, SegmentedControl, SegmentedControlItem, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SignaturePad, Skeleton, Slider, Spinner, SpinnerDots, SpinnerLoader, Status, StatusIndicator, StatusLabel, Switch, TCCEProvider, TEXT_SIZES, TEXT_WEIGHTS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TablePagination, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, Toaster, Toggle, ToggleGroup2 as ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alertVariants, animation, avatarVariants, badgeVariants2 as badgeVariants, buttonVariants, columnFiltersToArrayQueryParams, columnFiltersToJsonString, columnFiltersToQueryParams, columnFiltersToRecord, createBackendParams, createBackendParamsWithFilters, duration, ease, fadeIn, fireConfetti, getActiveFilterCount, getActiveFilterValues, getColumnValueCounts, getUniqueColumnValues, hasActiveFilters, linkVariants, logos, matchPermission, mergeFilters, multiSelectFilter, navigationMenuTriggerStyle, parseJsonToFilters, parseQueryParamsToFilters, progressIndicatorVariants, progressVariants, resetConfetti, scaleIn, searchInArray, skeletonVariants, slideRight, slideUp, sortRecordToSortingState, sortingStateToJsonString, sortingStateToRecord, spinnerDotsVariants, spinnerLoaderVariants, spinnerVariants, spring, stagger, toggleVariants, tooltipContentVariants, transition, useAbility, useAbilityStatus, useAppForm, useCan, useCarousel, useColorPicker, useColumnFilter, useSidebar, useTableContext, useTableData, useTableFiltering, useTableGlobalFilter, useTableSizing, useTableSorting, useTableVisibility, useToast, validatePhone };
10634
+ export { AbilityProvider, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge2 as Badge, BottomNav, BottomNavTabs, BottomNavTabsContent, BottomNavTabsList, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, CONFETTI_COLORS, Can, CanNot, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, Checkbox, ColorPicker, ColorPickerAlpha, ColorPickerEyeDropper, ColorPickerFormat, ColorPickerHue, ColorPickerOutput, ColorPickerPresets, ColorPickerSelection, Combobox, DataTable, DataTableCardView, DataTableColumnFilter, DataTableFooter, DataTableHeaderCell, DataTableRowActions, DataTableSearch, DataTableSkeleton, DataTableToolbar, DatePicker, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerBody, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Dropzone, DropzoneContent, DropzoneEmptyState, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EventCalendar, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, FilterOption, FloatingSidebar, Input, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, KNOWN_PERMISSIONS, Label, Link, Logo, MiniCalendar, MiniCalendarDay, MiniCalendarDays, MiniCalendarNavigation, Navbar, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PhoneField, PinInput, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, SegmentedControl, SegmentedControlItem, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SignaturePad, Skeleton, Slider, Spinner, SpinnerDots, SpinnerLoader, Status, StatusIndicator, StatusLabel, Switch, TCCEProvider, TEXT_SIZES, TEXT_WEIGHTS, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TablePagination, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Text, Textarea, Toaster, Toggle, ToggleGroup2 as ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, alertVariants, animation, avatarVariants, badgeVariants2 as badgeVariants, buttonVariants, columnFiltersToArrayQueryParams, columnFiltersToJsonString, columnFiltersToQueryParams, columnFiltersToRecord, createBackendParams, createBackendParamsWithFilters, duration, ease, fadeIn, fireConfetti, getActiveFilterCount, getActiveFilterValues, getColumnValueCounts, getUniqueColumnValues, hasActiveFilters, linkVariants, logos, matchPermission, mergeFilters, multiSelectFilter, navigationMenuTriggerStyle, parseJsonToFilters, parseQueryParamsToFilters, progressIndicatorVariants, progressVariants, resetConfetti, scaleIn, searchInArray, skeletonVariants, slideRight, slideUp, sortRecordToSortingState, sortingStateToJsonString, sortingStateToRecord, spinnerDotsVariants, spinnerLoaderVariants, spinnerVariants, spring, stagger, toggleVariants, tooltipContentVariants, transition, useAbility, useAbilityStatus, useAppForm, useCan, useCarousel, useColorPicker, useColumnFilter, useSidebar, useTableContext, useTableData, useTableFiltering, useTableGlobalFilter, useTableSizing, useTableSorting, useTableVisibility, useToast, validatePhone };
9606
10635
  //# sourceMappingURL=main.js.map
9607
10636
  //# sourceMappingURL=main.js.map