@keboola/design 11.6.1 → 11.9.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.
Files changed (153) hide show
  1. package/AGENTS.md +16 -1
  2. package/CHANGELOG.md +86 -0
  3. package/COMPONENT-API.md +47 -46
  4. package/README.md +1 -1
  5. package/dist/{AIKit-CQxVwyAk.js → AIKit-ELIsegJz.js} +550 -103
  6. package/dist/AIKit-ELIsegJz.js.map +1 -0
  7. package/dist/{Alert-C4Y9IwMI.js → Alert-BsIM_oFK.js} +2 -2
  8. package/dist/{Alert-C4Y9IwMI.js.map → Alert-BsIM_oFK.js.map} +1 -1
  9. package/dist/{BrandEditor-CS9P4r2p.js → BrandEditor-BsTBM3s6.js} +4 -4
  10. package/dist/{BrandEditor-CS9P4r2p.js.map → BrandEditor-BsTBM3s6.js.map} +1 -1
  11. package/dist/{Breadcrumb-D1id7YXd.js → Breadcrumb-xqEUxfwn.js} +2 -2
  12. package/dist/{Breadcrumb-D1id7YXd.js.map → Breadcrumb-xqEUxfwn.js.map} +1 -1
  13. package/dist/{Checkbox-Bqr6zXcW.js → Checkbox-Dq5fPNrO.js} +2 -2
  14. package/dist/{Checkbox-Bqr6zXcW.js.map → Checkbox-Dq5fPNrO.js.map} +1 -1
  15. package/dist/{Clipboard-C2YBRfD8.js → Clipboard-BZitKiSA.js} +2 -2
  16. package/dist/{Clipboard-C2YBRfD8.js.map → Clipboard-BZitKiSA.js.map} +1 -1
  17. package/dist/{ClipboardButton-CrljClL1.js → ClipboardButton-KHQnPEh_.js} +2 -2
  18. package/dist/{ClipboardButton-CrljClL1.js.map → ClipboardButton-KHQnPEh_.js.map} +1 -1
  19. package/dist/{CodeEditor-C9AS8Ch0.js → CodeEditor-BJKJXA0c.js} +4 -4
  20. package/dist/{CodeEditor-C9AS8Ch0.js.map → CodeEditor-BJKJXA0c.js.map} +1 -1
  21. package/dist/{ColorInput-Dg87lKcR.js → ColorInput-Bj3dfPFA.js} +3 -3
  22. package/dist/{ColorInput-Dg87lKcR.js.map → ColorInput-Bj3dfPFA.js.map} +1 -1
  23. package/dist/{ColorModeSwitch-CsWLiTBX.js → ColorModeSwitch-CWt-DZGC.js} +2 -2
  24. package/dist/{ColorModeSwitch-CsWLiTBX.js.map → ColorModeSwitch-CWt-DZGC.js.map} +1 -1
  25. package/dist/{Combobox-BfanUAqY.js → Combobox-D8PrEqTG.js} +3 -3
  26. package/dist/{Combobox-BfanUAqY.js.map → Combobox-D8PrEqTG.js.map} +1 -1
  27. package/dist/{Command-CqxoI_De.js → Command-BDU3C1gg.js} +2 -2
  28. package/dist/{Command-CqxoI_De.js.map → Command-BDU3C1gg.js.map} +1 -1
  29. package/dist/{CopyField-Rx9HPTbJ.js → CopyField-BHRQUyuF.js} +2 -2
  30. package/dist/{CopyField-Rx9HPTbJ.js.map → CopyField-BHRQUyuF.js.map} +1 -1
  31. package/dist/{DateInput-DpifECUQ.js → DateInput-B6N8g0ra.js} +3 -3
  32. package/dist/{DateInput-DpifECUQ.js.map → DateInput-B6N8g0ra.js.map} +1 -1
  33. package/dist/{DateRangeInput-9MIw7P6L.js → DateRangeInput-7M9Z4cVO.js} +3 -3
  34. package/dist/{DateRangeInput-9MIw7P6L.js.map → DateRangeInput-7M9Z4cVO.js.map} +1 -1
  35. package/dist/{DropdownMenu-CASr-jgl.js → DropdownMenu-CgVwhDvl.js} +9 -4
  36. package/dist/DropdownMenu-CgVwhDvl.js.map +1 -0
  37. package/dist/{FieldItem-DtPTzNef.js → FieldItem-DZGIdiXE.js} +3 -3
  38. package/dist/{FieldItem-DtPTzNef.js.map → FieldItem-DZGIdiXE.js.map} +1 -1
  39. package/dist/{Form-DAaatlBk.js → Form-CcK7dRrC.js} +5 -5
  40. package/dist/{Form-DAaatlBk.js.map → Form-CcK7dRrC.js.map} +1 -1
  41. package/dist/{FormGroup-Bl8JmnzJ.js → FormGroup-DR_gZ25-.js} +3 -3
  42. package/dist/{FormGroup-Bl8JmnzJ.js.map → FormGroup-DR_gZ25-.js.map} +1 -1
  43. package/dist/{InputGroup-DcZRlVnN.js → InputGroup-Do8K2hvD.js} +2 -1
  44. package/dist/InputGroup-Do8K2hvD.js.map +1 -0
  45. package/dist/{Kbd-D1Azcc4g.js → Kbd-LCFMumoq.js} +2 -2
  46. package/dist/{Kbd-D1Azcc4g.js.map → Kbd-LCFMumoq.js.map} +1 -1
  47. package/dist/{MermaidDiagram-CujFxVzk.js → MermaidDiagram-ZG0iiDV_.js} +2 -2
  48. package/dist/{MermaidDiagram-CujFxVzk.js.map → MermaidDiagram-ZG0iiDV_.js.map} +1 -1
  49. package/dist/{Modal-Coj-H02o.js → Modal-I3VWk2oo.js} +2 -2
  50. package/dist/{Modal-Coj-H02o.js.map → Modal-I3VWk2oo.js.map} +1 -1
  51. package/dist/{ModalTitle-C76ke2eo.js → ModalTitle-CeLM_mX9.js} +2 -2
  52. package/dist/ModalTitle-CeLM_mX9.js.map +1 -0
  53. package/dist/{MultiActionButtonGroup-CNNoBQbv.js → MultiActionButtonGroup-CYZ8IgSf.js} +2 -2
  54. package/dist/{MultiActionButtonGroup-CNNoBQbv.js.map → MultiActionButtonGroup-CYZ8IgSf.js.map} +1 -1
  55. package/dist/{RadioGroup-CUBsuP7r.js → RadioGroup-Byc2mym4.js} +2 -2
  56. package/dist/{RadioGroup-CUBsuP7r.js.map → RadioGroup-Byc2mym4.js.map} +1 -1
  57. package/dist/{Search-DVpJuzr9.js → Search-Dhig_hPD.js} +2 -2
  58. package/dist/{Search-DVpJuzr9.js.map → Search-Dhig_hPD.js.map} +1 -1
  59. package/dist/{SearchInput-Q85p8Ews.js → SearchInput-92r2bkA7.js} +3 -3
  60. package/dist/{SearchInput-Q85p8Ews.js.map → SearchInput-92r2bkA7.js.map} +1 -1
  61. package/dist/{SectionNav-mpmSM3OC.js → SectionNav-CNLJsiVG.js} +3 -3
  62. package/dist/{SectionNav-mpmSM3OC.js.map → SectionNav-CNLJsiVG.js.map} +1 -1
  63. package/dist/{Sheet-Chf0kX1E.js → Sheet-OparjIi-.js} +2 -2
  64. package/dist/{Sheet-Chf0kX1E.js.map → Sheet-OparjIi-.js.map} +1 -1
  65. package/dist/{Sidebar-CTWsHZhF.js → Sidebar-CLEbBtNY.js} +190 -25
  66. package/dist/Sidebar-CLEbBtNY.js.map +1 -0
  67. package/dist/{Slider-Bv0B6lI0.js → Slider-DLclvRws.js} +2 -2
  68. package/dist/{Slider-Bv0B6lI0.js.map → Slider-DLclvRws.js.map} +1 -1
  69. package/dist/{TextInput-DiEMxVF6.js → TextInput-CFTf4Cz1.js} +5 -4
  70. package/dist/TextInput-CFTf4Cz1.js.map +1 -0
  71. package/dist/{ThemeProvider-BI6JWBdJ.js → ThemeProvider-DAmNn9Sd.js} +2 -2
  72. package/dist/{ThemeProvider-BI6JWBdJ.js.map → ThemeProvider-DAmNn9Sd.js.map} +1 -1
  73. package/dist/{Timeline-BG5Xogxh.js → Timeline-C8-wnRRr.js} +2 -2
  74. package/dist/{Timeline-BG5Xogxh.js.map → Timeline-C8-wnRRr.js.map} +1 -1
  75. package/dist/{ZoomableSvg-U_VH3QRO.js → ZoomableSvg-BZlk3PFJ.js} +3 -3
  76. package/dist/{ZoomableSvg-U_VH3QRO.js.map → ZoomableSvg-BZlk3PFJ.js.map} +1 -1
  77. package/dist/editors.js +2 -2
  78. package/dist/flint.js +1 -1
  79. package/dist/index.d.ts +900 -561
  80. package/dist/index.js +36 -34
  81. package/dist/internal/blocks/AIKit.js +2 -2
  82. package/dist/internal/blocks/BrandEditor.js +1 -1
  83. package/dist/internal/blocks/ChipEditor.js +137 -0
  84. package/dist/internal/blocks/ChipEditor.js.map +1 -0
  85. package/dist/internal/blocks/ClipboardButton.js +1 -1
  86. package/dist/internal/blocks/ColorInput.js +1 -1
  87. package/dist/internal/blocks/ColorModeSwitch.js +1 -1
  88. package/dist/internal/blocks/Command.js +1 -1
  89. package/dist/internal/blocks/CopyField.js +1 -1
  90. package/dist/internal/blocks/DateInput.js +1 -1
  91. package/dist/internal/blocks/DateRangeInput.js +1 -1
  92. package/dist/internal/blocks/ExportMenu.js +2 -2
  93. package/dist/internal/blocks/Form/connectors/MultiComboboxField.js +1 -1
  94. package/dist/internal/blocks/Form.js +1 -1
  95. package/dist/internal/blocks/FormGroup.js +1 -1
  96. package/dist/internal/blocks/MultiActionButtonGroup.js +1 -1
  97. package/dist/internal/blocks/MultiCombobox.js +18 -28
  98. package/dist/internal/blocks/MultiCombobox.js.map +1 -1
  99. package/dist/internal/blocks/NumberInput.js +1 -1
  100. package/dist/internal/blocks/PasswordInput.js +2 -2
  101. package/dist/internal/blocks/SearchInput.js +1 -1
  102. package/dist/internal/blocks/SearchInputWithNavigation.js +2 -2
  103. package/dist/internal/blocks/SectionNav.js +1 -1
  104. package/dist/internal/blocks/SplitButton.js +1 -1
  105. package/dist/internal/blocks/TextInput.js +1 -1
  106. package/dist/internal/blocks/Textarea.js +1 -1
  107. package/dist/internal/blocks/TimeInput.js +2 -2
  108. package/dist/internal/components/Alert.js +1 -1
  109. package/dist/internal/components/Avatar.js +1 -1
  110. package/dist/internal/components/Breadcrumb.js +1 -1
  111. package/dist/internal/components/Checkbox.js +1 -1
  112. package/dist/internal/components/Clipboard.js +1 -1
  113. package/dist/internal/components/CollapsiblePanel.js +1 -1
  114. package/dist/internal/components/Combobox.js +1 -1
  115. package/dist/internal/components/DropdownMenu.js +1 -1
  116. package/dist/internal/components/InputGroup.js +1 -1
  117. package/dist/internal/components/Kbd.js +1 -1
  118. package/dist/internal/components/Modal.js +1 -1
  119. package/dist/internal/components/RadioGroup.js +1 -1
  120. package/dist/internal/components/Search.js +1 -1
  121. package/dist/internal/components/Sheet.js +1 -1
  122. package/dist/internal/components/Sidebar.js +1 -1
  123. package/dist/internal/components/Slider.js +1 -1
  124. package/dist/internal/components/StatusDot.js +67 -0
  125. package/dist/internal/components/StatusDot.js.map +1 -0
  126. package/dist/internal/components/ThemeProvider.js +1 -1
  127. package/dist/internal/components/Timeline.js +1 -1
  128. package/dist/internal/components/Tooltip.js +2 -2
  129. package/dist/internal/components/Truncated.js +1 -1
  130. package/dist/internal/components/ZoomableSvg.js +1 -1
  131. package/dist/internal/hooks/useScrollbarPosition.js +1 -1
  132. package/dist/internal/utils/mergeRefs.js +27 -9
  133. package/dist/internal/utils/mergeRefs.js.map +1 -1
  134. package/dist/internal/utils.js +2 -2
  135. package/dist/markdown-editor.js +5 -5
  136. package/dist/mermaid.js +1 -1
  137. package/dist/rjsf.js +9 -9
  138. package/dist/styles.css +1 -1
  139. package/dist/testing.js +1 -1
  140. package/dist/useElement-BK3AAiIf.js +24 -0
  141. package/dist/useElement-BK3AAiIf.js.map +1 -0
  142. package/dist/{utils-DnkrFYqY.js → utils-BW4AE8VP.js} +31 -3
  143. package/dist/utils-BW4AE8VP.js.map +1 -0
  144. package/package.json +2 -1
  145. package/dist/AIKit-CQxVwyAk.js.map +0 -1
  146. package/dist/DropdownMenu-CASr-jgl.js.map +0 -1
  147. package/dist/InputGroup-DcZRlVnN.js.map +0 -1
  148. package/dist/ModalTitle-C76ke2eo.js.map +0 -1
  149. package/dist/Sidebar-CTWsHZhF.js.map +0 -1
  150. package/dist/TextInput-DiEMxVF6.js.map +0 -1
  151. package/dist/useElement-DkF6esWL.js +0 -15
  152. package/dist/useElement-DkF6esWL.js.map +0 -1
  153. package/dist/utils-DnkrFYqY.js.map +0 -1
@@ -1,17 +1,19 @@
1
1
  import { cn } from "./classNames-BzrkDnOD.js";
2
- import { Tooltip, TooltipProvider } from "./utils-DnkrFYqY.js";
2
+ import { Tooltip, TooltipProvider } from "./utils-BW4AE8VP.js";
3
3
  import { mergeRefs } from "./internal/utils/mergeRefs.js";
4
4
  import { ChevronDown, Search } from "./icons-Cek151jC.js";
5
- import { DropdownMenu } from "./DropdownMenu-CASr-jgl.js";
5
+ import { DropdownMenu } from "./DropdownMenu-CgVwhDvl.js";
6
6
  import { ScrollArea } from "./internal/components/ScrollArea.js";
7
7
  import { Separator } from "./internal/components/Separator.js";
8
+ import { Sheet } from "./Sheet-OparjIi-.js";
8
9
  import { HoverCard } from "./HoverCard-B9ZMJxjn.js";
9
10
  import { Collapsible } from "./Collapsible-BQXWEOBC.js";
11
+ import { useThemeScopeContainer } from "./ThemeProvider-DAmNn9Sd.js";
10
12
  import { BrandLogo } from "./BrandLogo-CoKBk4MI.js";
11
- import { useElement } from "./useElement-DkF6esWL.js";
13
+ import { useElement } from "./useElement-BK3AAiIf.js";
12
14
  import { useScrollbarPosition } from "./internal/hooks/useScrollbarPosition.js";
13
15
  import { Root, Slot, Slottable } from "@radix-ui/react-slot";
14
- import { createContext, use, useCallback, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState } from "react";
16
+ import { createContext, use, useCallback, useEffect, useLayoutEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
15
17
  import { jsx, jsxs } from "react/jsx-runtime";
16
18
  //#region src/components/Sidebar/SidebarProvider/useTransitionPresence.ts
17
19
  const FALLBACK_TIMEOUT_MS = 500;
@@ -79,20 +81,47 @@ const SidebarContent = ({ ref, className, children, contentRef }) => {
79
81
  });
80
82
  };
81
83
  //#endregion
84
+ //#region src/hooks/useMediaQuery.ts
85
+ /**
86
+ * Whether a CSS media query currently matches, re-rendering when it flips.
87
+ *
88
+ * - `false` wherever `matchMedia` is absent (SSR, a stubbed test environment), so the
89
+ * caller renders its desktop branch rather than crashing.
90
+ * - The subscription is the query's own `change` event — no resize listener, no polling.
91
+ */
92
+ const useMediaQuery = (query) => {
93
+ const subscribe = useCallback((onStoreChange) => {
94
+ const list = globalThis.matchMedia?.(query);
95
+ list?.addEventListener?.("change", onStoreChange);
96
+ return () => list?.removeEventListener?.("change", onStoreChange);
97
+ }, [query]);
98
+ const getSnapshot = useCallback(() => globalThis.matchMedia?.(query).matches ?? false, [query]);
99
+ return useSyncExternalStore(subscribe, getSnapshot, () => false);
100
+ };
101
+ //#endregion
82
102
  //#region src/components/Sidebar/utils.ts
83
103
  const SidebarWidthInPx = {
84
104
  MIN_DEFAULT: 256,
85
105
  COLLAPSED_ICON: 52,
86
106
  FLOATING_VARIANT_PADDING: 8
87
107
  };
108
+ /**
109
+ * The query a rail watches to know whether it is a sheet.
110
+ *
111
+ * - `max-width`, so it is exclusive of the breakpoint itself — the width passed in is the
112
+ * first one at which the rail is a column again.
113
+ * - Per side, because the width at which a rail stops fitting is the rail's own: a 320px
114
+ * panel beside a capped reading column runs out of room long before a navigation rail does.
115
+ */
116
+ const sidebarMobileMediaQuery = (breakpointPx) => `(max-width: ${breakpointPx - .02}px)`;
88
117
  const floatingSideCount = {
89
118
  "sided-floating": 1,
90
119
  floating: 2,
91
120
  inset: 0,
92
121
  none: 0
93
122
  };
94
- const calcEffectiveWidths = ({ variant, width: customWidth, collapsible, state, mode }) => {
95
- if (variant === "none") return {
123
+ const calcEffectiveWidths = ({ variant, width: customWidth, collapsible, state, mode, isMobile = false }) => {
124
+ if (variant === "none" || isMobile) return {
96
125
  sidebar: 0,
97
126
  gap: 0,
98
127
  fill: 0
@@ -140,14 +169,16 @@ const useSidebar = (side = "left") => {
140
169
  //#region src/components/Sidebar/SidebarProvider/useHoverTracking.ts
141
170
  const PORTAL_OPEN_SELECTORS_STRING = ["[aria-haspopup=\"menu\"][aria-expanded=true]", "[aria-haspopup=\"dialog\"][aria-expanded=true]"].join(",");
142
171
  const useHoverTracking = (sidebarElement) => {
143
- const [isHovered, setIsHovered] = useState(false);
172
+ const [hoveredElement, setHoveredElement] = useState(null);
144
173
  const isLockedRef = useRef(false);
174
+ if (hoveredElement !== null && hoveredElement !== sidebarElement) setHoveredElement(null);
175
+ const isHovered = hoveredElement !== null;
145
176
  useEffect(() => {
146
177
  if (!sidebarElement) return;
147
- const handleMouseEnter = () => setIsHovered(true);
178
+ const handleMouseEnter = () => setHoveredElement(sidebarElement);
148
179
  const handleMouseLeave = () => {
149
180
  if (isLockedRef.current) return;
150
- setIsHovered(false);
181
+ setHoveredElement(null);
151
182
  };
152
183
  sidebarElement.addEventListener("mouseenter", handleMouseEnter);
153
184
  sidebarElement.addEventListener("mouseleave", handleMouseLeave);
@@ -164,7 +195,7 @@ const useHoverTracking = (sidebarElement) => {
164
195
  isLockedRef.current = hasOpenPortal;
165
196
  if (hasOpenPortal) return;
166
197
  animationFrameId = requestAnimationFrame(() => {
167
- setIsHovered(sidebarElement.matches(":hover"));
198
+ setHoveredElement(sidebarElement.matches(":hover") ? sidebarElement : null);
168
199
  });
169
200
  });
170
201
  isLockedRef.current = sidebarElement.querySelector(PORTAL_OPEN_SELECTORS_STRING) !== null;
@@ -221,14 +252,31 @@ const useSidebarState = ({ defaultMode, mode: modeProp, onModeChange }) => {
221
252
  const DEFAULT_SIDEBAR_VARIANT = "none";
222
253
  const DEFAULT_SIDEBAR_MODE = "expanded";
223
254
  const DEFAULT_SIDEBAR_COLLAPSIBLE = "off-canvas";
224
- const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, leftMode, onLeftModeChange, defaultRightMode = DEFAULT_SIDEBAR_MODE, rightMode, onRightModeChange, leftCollapsible = DEFAULT_SIDEBAR_COLLAPSIBLE, leftVariant = DEFAULT_SIDEBAR_VARIANT, leftWidth, rightCollapsible = DEFAULT_SIDEBAR_COLLAPSIBLE, rightVariant = DEFAULT_SIDEBAR_VARIANT, rightWidth, onLeftWidthChange, onRightWidthChange, defaultFilledSide = null }) => {
255
+ /**
256
+ * What `setMode` becomes for a rail that is currently a sheet.
257
+ *
258
+ * - The collapse axis has nothing to act on there, and the call site's own `mode` prop is a
259
+ * stored desktop preference — `Sidebar.SearchInput` expands the rail on focus, which would
260
+ * otherwise overwrite a stored `collapsed` the first time someone searches on a phone.
261
+ */
262
+ const ignoreModeChange = () => {};
263
+ /** The width a side watches: its own when it named one, the default when it just opted in. */
264
+ const mobileBreakpointOf = (mobileSheet) => typeof mobileSheet === "number" ? mobileSheet : 768;
265
+ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, leftMode, onLeftModeChange, defaultRightMode = DEFAULT_SIDEBAR_MODE, rightMode, onRightModeChange, leftMobileSheet = false, rightMobileSheet = false, leftCollapsible = DEFAULT_SIDEBAR_COLLAPSIBLE, leftVariant = DEFAULT_SIDEBAR_VARIANT, leftWidth, rightCollapsible = DEFAULT_SIDEBAR_COLLAPSIBLE, rightVariant = DEFAULT_SIDEBAR_VARIANT, rightWidth, onLeftWidthChange, onRightWidthChange, defaultFilledSide = null }) => {
266
+ const isLeftNarrow = useMediaQuery(sidebarMobileMediaQuery(mobileBreakpointOf(leftMobileSheet)));
267
+ const isRightNarrow = useMediaQuery(sidebarMobileMediaQuery(mobileBreakpointOf(rightMobileSheet)));
268
+ const isLeftMobile = isLeftNarrow && leftMobileSheet !== false && leftVariant !== "none";
269
+ const isRightMobile = isRightNarrow && rightMobileSheet !== false && rightVariant !== "none";
225
270
  const [filledSide, setFilledSide] = useState(defaultFilledSide);
271
+ const [openMobileSide, setOpenMobileSide] = useState(null);
226
272
  const [isLeftDragging, setIsLeftDragging] = useState(false);
227
273
  const [isRightDragging, setIsRightDragging] = useState(false);
228
274
  const [leftDragWidth, setLeftDragWidth] = useState(null);
229
275
  const [rightDragWidth, setRightDragWidth] = useState(null);
230
276
  if (leftDragWidth !== null && leftWidth === leftDragWidth) setLeftDragWidth(null);
231
277
  if (rightDragWidth !== null && rightWidth === rightDragWidth) setRightDragWidth(null);
278
+ if (openMobileSide === "left" && !isLeftMobile) setOpenMobileSide(null);
279
+ if (openMobileSide === "right" && !isRightMobile) setOpenMobileSide(null);
232
280
  const leftState = useSidebarState({
233
281
  defaultMode: defaultLeftMode,
234
282
  mode: leftMode,
@@ -239,6 +287,10 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
239
287
  mode: rightMode,
240
288
  onModeChange: onRightModeChange
241
289
  });
290
+ const toggleLeftMobile = useCallback(() => setOpenMobileSide((prev) => prev === "left" ? null : "left"), []);
291
+ const toggleRightMobile = useCallback(() => setOpenMobileSide((prev) => prev === "right" ? null : "right"), []);
292
+ const setLeftMobileOpen = useCallback((open) => setOpenMobileSide((prev) => open ? "left" : prev === "left" ? null : prev), []);
293
+ const setRightMobileOpen = useCallback((open) => setOpenMobileSide((prev) => open ? "right" : prev === "right" ? null : prev), []);
242
294
  const toggleLeftFill = useCallback(() => setFilledSide((prev) => prev === "left" ? null : "left"), []);
243
295
  const toggleRightFill = useCallback(() => setFilledSide((prev) => prev === "right" ? null : "right"), []);
244
296
  const setLeftFill = useCallback((fill) => setFilledSide((prev) => fill ? "left" : prev === "left" ? null : prev), []);
@@ -246,6 +298,15 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
246
298
  const value = useMemo(() => ({
247
299
  left: {
248
300
  ...leftState,
301
+ ...isLeftMobile ? {
302
+ mode: "expanded",
303
+ state: "expanded",
304
+ toggle: toggleLeftMobile,
305
+ setMode: ignoreModeChange
306
+ } : null,
307
+ isMobile: isLeftMobile,
308
+ isMobileOpen: openMobileSide === "left",
309
+ setMobileOpen: setLeftMobileOpen,
249
310
  isFill: filledSide === "left",
250
311
  toggleFill: toggleLeftFill,
251
312
  setFill: setLeftFill,
@@ -254,7 +315,8 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
254
315
  width: leftDragWidth ?? leftWidth,
255
316
  collapsible: leftCollapsible,
256
317
  state: leftState.state,
257
- mode: leftState.mode
318
+ mode: leftState.mode,
319
+ isMobile: isLeftMobile
258
320
  }),
259
321
  collapsible: leftCollapsible,
260
322
  variant: leftVariant,
@@ -266,6 +328,15 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
266
328
  },
267
329
  right: {
268
330
  ...rightState,
331
+ ...isRightMobile ? {
332
+ mode: "expanded",
333
+ state: "expanded",
334
+ toggle: toggleRightMobile,
335
+ setMode: ignoreModeChange
336
+ } : null,
337
+ isMobile: isRightMobile,
338
+ isMobileOpen: openMobileSide === "right",
339
+ setMobileOpen: setRightMobileOpen,
269
340
  isFill: filledSide === "right",
270
341
  toggleFill: toggleRightFill,
271
342
  setFill: setRightFill,
@@ -274,7 +345,8 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
274
345
  width: rightDragWidth ?? rightWidth,
275
346
  collapsible: rightCollapsible,
276
347
  state: rightState.state,
277
- mode: rightState.mode
348
+ mode: rightState.mode,
349
+ isMobile: isRightMobile
278
350
  }),
279
351
  collapsible: rightCollapsible,
280
352
  variant: rightVariant,
@@ -285,6 +357,13 @@ const SidebarProvider = ({ children, defaultLeftMode = DEFAULT_SIDEBAR_MODE, lef
285
357
  setIsDragging: setIsRightDragging
286
358
  }
287
359
  }), [
360
+ isLeftMobile,
361
+ isRightMobile,
362
+ openMobileSide,
363
+ toggleLeftMobile,
364
+ setLeftMobileOpen,
365
+ toggleRightMobile,
366
+ setRightMobileOpen,
288
367
  leftState,
289
368
  filledSide,
290
369
  toggleLeftFill,
@@ -407,12 +486,39 @@ const SidebarMenuIcon = ({ ref, className, children, ...rest }) => /* @__PURE__
407
486
  children
408
487
  });
409
488
  //#endregion
489
+ //#region src/components/Sidebar/SidebarMenu/useDestinationDismiss.ts
490
+ /**
491
+ * The click handler a sidebar menu item runs: the caller's own, then the sheet's dismissal.
492
+ *
493
+ * - On a phone the rail is a sheet over the page, so a chosen destination has to dismiss it —
494
+ * otherwise the page it navigated to sits behind the overlay.
495
+ * - Two kinds of click are not a destination:
496
+ * - Opening a popup. `DropdownMenu.Trigger` and `Sidebar.SubMenu` both hand their child an
497
+ * `aria-haspopup` / `aria-expanded`, and closing the sheet under their popup would take
498
+ * the popup with it.
499
+ * - Acting on the rail itself. `Sidebar.Trigger` marks its child `data-sidebar-trigger`; its
500
+ * own `toggle` runs after this handler, so dismissing here would hand `toggle` a closed
501
+ * sheet and it would open it straight back up.
502
+ * - Above the breakpoint the caller's `onClick` is all that runs.
503
+ */
504
+ const useDestinationDismiss = (props, onClick) => {
505
+ const { side } = useSidebarInstance();
506
+ const { isMobile, setMobileOpen } = useSidebar(side);
507
+ const isDestination = props["aria-haspopup"] === void 0 && props["aria-expanded"] === void 0 && props["data-sidebar-trigger"] === void 0;
508
+ return (event) => {
509
+ onClick?.(event);
510
+ if (isMobile && isDestination) setMobileOpen(false);
511
+ };
512
+ };
513
+ //#endregion
410
514
  //#region src/components/Sidebar/SidebarMenu/SidebarMenuButton.tsx
411
- const SidebarMenuButton = ({ ref, "aria-selected": selected, className, children, asChild = false, icon, tooltip, ...props }) => {
515
+ const SidebarMenuButton = ({ ref, "aria-selected": selected, className, children, asChild = false, icon, tooltip, onClick, ...props }) => {
412
516
  const Component = asChild ? Root : "button";
413
517
  const { state, mode, side } = useSidebarInstance();
518
+ const handleClick = useDestinationDismiss(props, onClick);
414
519
  const button = /* @__PURE__ */ jsxs(Component, {
415
520
  ...props,
521
+ onClick: handleClick,
416
522
  ref,
417
523
  "data-slot": "sidebar-menu-button",
418
524
  ...asChild ? {} : { type: "button" },
@@ -605,8 +711,9 @@ const SidebarMenuSub = ({ children, icon, isActive = false, label, defaultOpen =
605
711
  };
606
712
  //#endregion
607
713
  //#region src/components/Sidebar/SidebarMenu/SidebarMenuSubItem.tsx
608
- const SidebarMenuSubItem = ({ ref, className, asChild = false, children, disabled, "aria-current": ariaCurrent, ...props }) => {
714
+ const SidebarMenuSubItem = ({ ref, className, asChild = false, children, disabled, onClick, "aria-current": ariaCurrent, ...props }) => {
609
715
  const { mode } = useSidebarInstance();
716
+ const handleClick = useDestinationDismiss(props, onClick);
610
717
  if (mode === "collapsed" || mode === "expand-on-hover") return /* @__PURE__ */ jsx(DropdownMenu.Item, {
611
718
  "aria-current": ariaCurrent,
612
719
  asChild,
@@ -618,6 +725,7 @@ const SidebarMenuSubItem = ({ ref, className, asChild = false, children, disable
618
725
  className: "tw:group/sidebar-menu-sub-item tw:relative",
619
726
  children: /* @__PURE__ */ jsx(asChild ? Root : "button", {
620
727
  ...props,
728
+ onClick: handleClick,
621
729
  ref,
622
730
  "aria-current": ariaCurrent,
623
731
  "data-slot": "sidebar-menu-sub-button",
@@ -725,22 +833,26 @@ const SidebarSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx(Separa
725
833
  //#endregion
726
834
  //#region src/components/Sidebar/SidebarTrigger.tsx
727
835
  const SidebarTrigger = ({ side = "left", onClick, hideWhenCollapsed = false, className, ...rest }) => {
728
- const { toggle } = useSidebar(side);
836
+ const { toggle, state, isMobile, isMobileOpen } = useSidebar(side);
729
837
  const handleOnClick = (event) => {
730
838
  toggle();
731
839
  onClick?.(event);
732
840
  };
733
841
  return /* @__PURE__ */ jsx(Slot, {
734
842
  ...rest,
843
+ "aria-expanded": isMobile ? isMobileOpen : state === "expanded",
844
+ ...isMobile ? { "aria-haspopup": "dialog" } : null,
845
+ "data-sidebar-trigger": "",
735
846
  onClick: handleOnClick,
736
847
  className: cn({ "tw:group-data-[state=collapsed]/sidebar:hidden": hideWhenCollapsed }, className)
737
848
  });
738
849
  };
739
850
  //#endregion
740
851
  //#region src/components/Sidebar/Sidebar.tsx
741
- const Sidebar = ({ children, className, id, side = "left", style, container = false, keepMounted, mountAfterEnter, resizable = false, ...rest }) => {
852
+ const Sidebar = ({ children, className, id, side = "left", style, container = false, keepMounted, mountAfterEnter, resizable = false, mobileTitle, ...rest }) => {
742
853
  const oppositeSide = side === "left" ? "right" : "left";
743
- const { setSidebarElement, state, mode, isFill, widths, collapsible, variant, isDragging } = useSidebar(side);
854
+ const { setSidebarElement, state, mode, isFill, widths, collapsible, variant, isDragging, isMobile, isMobileOpen, setMobileOpen } = useSidebar(side);
855
+ const themeScopeContainer = useThemeScopeContainer();
744
856
  const { isMounted, completeUnmount } = useTransitionPresence({
745
857
  mounted: collapsible !== "off-canvas" || mode !== "collapsed",
746
858
  keepMounted,
@@ -756,6 +868,23 @@ const Sidebar = ({ children, className, id, side = "left", style, container = fa
756
868
  mode,
757
869
  side
758
870
  ]);
871
+ const focusOriginRef = useRef(null);
872
+ useEffect(() => {
873
+ if (!isMobile || isMobileOpen) return;
874
+ const remember = (event) => {
875
+ if (event.target instanceof HTMLElement) focusOriginRef.current = event.target;
876
+ };
877
+ document.addEventListener("focusin", remember);
878
+ return () => document.removeEventListener("focusin", remember);
879
+ }, [isMobile, isMobileOpen]);
880
+ const wasSheetUpRef = useRef(false);
881
+ useEffect(() => {
882
+ const wasSheetUp = wasSheetUpRef.current;
883
+ wasSheetUpRef.current = isMobile && isMobileOpen;
884
+ if (!wasSheetUp || isMobile) return;
885
+ const origin = focusOriginRef.current;
886
+ if (origin?.isConnected) origin.focus();
887
+ }, [isMobile, isMobileOpen]);
759
888
  const handleTransitionEnd = (event) => {
760
889
  if (event.target !== event.currentTarget) return;
761
890
  completeUnmount();
@@ -768,18 +897,54 @@ const Sidebar = ({ children, className, id, side = "left", style, container = fa
768
897
  "--opposite-sidebar-width": `${oppositeWidths.fill}px`
769
898
  };
770
899
  if (variant === "none") return null;
900
+ const railAttributes = {
901
+ "data-state": state,
902
+ "data-side": side,
903
+ "data-mode": mode,
904
+ "data-collapsible": collapsible,
905
+ "data-variant": variant,
906
+ "data-fill": isFill
907
+ };
908
+ if (isMobile) return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(SidebarInstanceContext, {
909
+ value: sidebarInstanceContextValue,
910
+ children: /* @__PURE__ */ jsx(Sheet, {
911
+ open: isMobileOpen,
912
+ onOpenChange: setMobileOpen,
913
+ children: /* @__PURE__ */ jsxs(Sheet.Content, {
914
+ side,
915
+ container: themeScopeContainer ?? void 0,
916
+ className: "tw:w-[min(20rem,85vw)] tw:bg-sidebar tw:text-sidebar-foreground tw:p-0",
917
+ onCloseAutoFocus: (event) => {
918
+ const origin = focusOriginRef.current;
919
+ if (!origin?.isConnected) return;
920
+ event.preventDefault();
921
+ origin.focus();
922
+ },
923
+ children: [/* @__PURE__ */ jsx(Sheet.Title, {
924
+ visuallyHidden: true,
925
+ children: mobileTitle ?? (side === "left" ? "Navigation" : "Side panel")
926
+ }), /* @__PURE__ */ jsx("div", {
927
+ ...rest,
928
+ ...railAttributes,
929
+ id,
930
+ style,
931
+ className: cn("tw:flex tw:min-h-0 tw:flex-1 tw:flex-col", { "tw:group/sidebar tw:peer/sidebar": !container }, className),
932
+ children: /* @__PURE__ */ jsx("div", {
933
+ "data-slot": "sidebar",
934
+ className: cn("tw:bg-sidebar", "tw:relative", "tw:flex", "tw:flex-col", "tw:size-full", "tw:overflow-hidden", "tw:border-sidebar-border", "tw:group-[]/sidebar:pt-2"),
935
+ children
936
+ })
937
+ })]
938
+ })
939
+ })
940
+ }) });
771
941
  return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(SidebarInstanceContext, {
772
942
  value: sidebarInstanceContextValue,
773
943
  children: /* @__PURE__ */ jsxs("div", {
774
944
  ...rest,
945
+ ...railAttributes,
775
946
  id,
776
947
  ref: setSidebarElement,
777
- "data-state": state,
778
- "data-side": side,
779
- "data-mode": mode,
780
- "data-collapsible": collapsible,
781
- "data-variant": variant,
782
- "data-fill": isFill,
783
948
  style: styles,
784
949
  className: cn("tailwindcss-preflight", "tw:flex", "tw:relative", mode === "expand-on-hover" ? "tw:z-[51]" : "tw:z-50", { "tw:group/sidebar tw:peer/sidebar": !container }, "tw:[&>[data-slot=gap]]:w-(--sidebar-width-gap)", "tw:[&[data-side=right]>[data-slot=gap]]:rotate-180", "tw:[&>[data-slot=sidebar-wrapper]]:w-(--sidebar-width)", "tw:[&[data-side=left]>[data-slot=sidebar-wrapper]]:left-0", "tw:[&[data-side=right]>[data-slot=sidebar-wrapper]]:right-0", "tw:[&[data-state=collapsed][data-collapsible=off-canvas][data-side=left]>[data-slot=sidebar-wrapper]]:-translate-x-full", "tw:[&[data-state=collapsed][data-collapsible=off-canvas][data-side=right]>[data-slot=sidebar-wrapper]]:translate-x-full", "tw:[&[data-variant=sided-floating]>[data-slot=sidebar-wrapper]]:pt-(--sidebar-floating-padding)", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]]:pr-(--sidebar-floating-padding)", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]]:pl-(--sidebar-floating-padding)", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]]:p-(--sidebar-floating-padding)", "tw:[&[data-fill=true]>[data-slot=sidebar-wrapper]]:!w-[calc(100svw-var(--opposite-sidebar-width))]", "tw:[&[data-fill=true][data-variant=floating]>[data-slot=sidebar-wrapper]]:!p-(--sidebar-floating-padding)", "tw:[&[data-fill=true][data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:!rounded-tr-xl", "tw:[&[data-fill=true][data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:!rounded-tl-xl", "tw:[&[data-variant=inset][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-r", "tw:[&[data-variant=inset][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-l", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:shadow", "tw:[&[data-variant=floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-xl", "tw:[&[data-variant=sided-floating]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:shadow", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-tr-xl", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:rounded-tl-xl", "tw:[&[data-variant=sided-floating][data-side=left]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-r", "tw:[&[data-variant=sided-floating][data-side=right]>[data-slot=sidebar-wrapper]>[data-slot=sidebar]]:border-l", isDragging ? "tw:transition-none" : "tw:transition-[width,translate,transform] tw:duration-(--sidebar-motion-duration) tw:ease-(--sidebar-motion-easing) tw:motion-reduce:transition-none"),
785
950
  children: [/* @__PURE__ */ jsx("div", {
@@ -822,4 +987,4 @@ Sidebar.SubItem = SidebarMenuSubItem;
822
987
  //#endregion
823
988
  export { Sidebar, SidebarProvider, useOptionalSidebar, useSidebar };
824
989
 
825
- //# sourceMappingURL=Sidebar-CTWsHZhF.js.map
990
+ //# sourceMappingURL=Sidebar-CLEbBtNY.js.map