@lerianstudio/sindarian-ui 2.0.0-beta.2 → 2.0.0-beta.21

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 (227) hide show
  1. package/LICENSE +93 -0
  2. package/README.md +52 -1
  3. package/dist/components/breadcrumb/index.d.ts.map +1 -1
  4. package/dist/components/breadcrumb/index.js +25 -1
  5. package/dist/components/card/account-card/index.js +5 -5
  6. package/dist/components/card/basic-card/index.d.ts.map +1 -1
  7. package/dist/components/card/basic-card/index.js +2 -2
  8. package/dist/components/card/entity-card/index.js +1 -1
  9. package/dist/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  10. package/dist/components/dialog/confirmation-dialog/index.js +4 -1
  11. package/dist/components/entity-box/index.d.ts +18 -2
  12. package/dist/components/entity-box/index.d.ts.map +1 -1
  13. package/dist/components/entity-box/index.js +32 -4
  14. package/dist/components/form/date-picker-field/index.js +1 -1
  15. package/dist/components/form/date-range-field/index.js +1 -1
  16. package/dist/components/form/date-time-picker-field/index.js +1 -1
  17. package/dist/components/form/password-field/index.d.ts +5 -1
  18. package/dist/components/form/password-field/index.d.ts.map +1 -1
  19. package/dist/components/form/password-field/index.js +2 -2
  20. package/dist/components/form/select-field/index.d.ts +15 -1
  21. package/dist/components/form/select-field/index.d.ts.map +1 -1
  22. package/dist/components/form/select-field/index.js +28 -3
  23. package/dist/components/form/switch-field/index.d.ts.map +1 -1
  24. package/dist/components/form/switch-field/index.js +6 -1
  25. package/dist/components/page/index.d.ts +35 -1
  26. package/dist/components/page/index.d.ts.map +1 -1
  27. package/dist/components/page/index.js +6 -2
  28. package/dist/components/page-header/index.js +1 -1
  29. package/dist/components/table/id-table-cell.d.ts +13 -1
  30. package/dist/components/table/id-table-cell.d.ts.map +1 -1
  31. package/dist/components/table/id-table-cell.js +99 -9
  32. package/dist/components/table/index.d.ts +1 -0
  33. package/dist/components/table/index.d.ts.map +1 -1
  34. package/dist/components/table/index.js +1 -0
  35. package/dist/components/table/locked-table-actions.d.ts +24 -0
  36. package/dist/components/table/locked-table-actions.d.ts.map +1 -1
  37. package/dist/components/table/locked-table-actions.js +31 -1
  38. package/dist/components/table/name-table-cell.d.ts +57 -4
  39. package/dist/components/table/name-table-cell.d.ts.map +1 -1
  40. package/dist/components/table/name-table-cell.js +50 -2
  41. package/dist/components/ui/autocomplete/index.d.ts +24 -0
  42. package/dist/components/ui/autocomplete/index.d.ts.map +1 -1
  43. package/dist/components/ui/autocomplete/index.js +24 -0
  44. package/dist/components/ui/badge/index.d.ts +11 -7
  45. package/dist/components/ui/badge/index.d.ts.map +1 -1
  46. package/dist/components/ui/badge/index.js +20 -8
  47. package/dist/components/ui/button/index.d.ts +3 -3
  48. package/dist/components/ui/copy-field/index.d.ts +25 -1
  49. package/dist/components/ui/copy-field/index.d.ts.map +1 -1
  50. package/dist/components/ui/copy-field/index.js +16 -8
  51. package/dist/components/ui/dialog/index.d.ts +1 -1
  52. package/dist/components/ui/dialog/index.d.ts.map +1 -1
  53. package/dist/components/ui/dialog/index.js +2 -2
  54. package/dist/components/ui/file-upload/index.d.ts +159 -0
  55. package/dist/components/ui/file-upload/index.d.ts.map +1 -1
  56. package/dist/components/ui/file-upload/index.js +308 -6
  57. package/dist/components/ui/icon-button/index.d.ts +1 -1
  58. package/dist/components/ui/icon-button/styles.css +42 -0
  59. package/dist/components/ui/input/styles.css +79 -4
  60. package/dist/components/ui/lerian-wordmark/index.d.ts +6 -0
  61. package/dist/components/ui/lerian-wordmark/index.d.ts.map +1 -0
  62. package/dist/components/ui/lerian-wordmark/index.js +7 -0
  63. package/dist/components/ui/otp-input/index.js +1 -1
  64. package/dist/components/ui/radio-group/index.js +1 -1
  65. package/dist/components/ui/select/index.d.ts.map +1 -1
  66. package/dist/components/ui/select/index.js +8 -4
  67. package/dist/components/ui/select/styles.css +1 -1
  68. package/dist/components/ui/sheet/index.d.ts +42 -0
  69. package/dist/components/ui/sheet/index.d.ts.map +1 -1
  70. package/dist/components/ui/sheet/index.js +47 -14
  71. package/dist/components/ui/sidebar/index.d.ts +1 -0
  72. package/dist/components/ui/sidebar/index.d.ts.map +1 -1
  73. package/dist/components/ui/sidebar/index.js +1 -0
  74. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts +1 -1
  75. package/dist/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  76. package/dist/components/ui/sidebar/sidebar-expand-button.js +15 -1
  77. package/dist/components/ui/sidebar/sidebar-item.d.ts +1 -1
  78. package/dist/components/ui/sidebar/sidebar-item.d.ts.map +1 -1
  79. package/dist/components/ui/sidebar/sidebar-item.js +28 -4
  80. package/dist/components/ui/sidebar/sidebar-provider.d.ts +58 -0
  81. package/dist/components/ui/sidebar/sidebar-provider.d.ts.map +1 -1
  82. package/dist/components/ui/sidebar/sidebar-provider.js +146 -4
  83. package/dist/components/ui/sidebar/sidebar-root.d.ts +38 -1
  84. package/dist/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  85. package/dist/components/ui/sidebar/sidebar-root.js +111 -5
  86. package/dist/components/ui/sidebar/sidebar-trigger.d.ts +45 -0
  87. package/dist/components/ui/sidebar/sidebar-trigger.d.ts.map +1 -0
  88. package/dist/components/ui/sidebar/sidebar-trigger.js +57 -0
  89. package/dist/components/ui/textarea/index.js +1 -1
  90. package/dist/components/ui/toast/toaster.d.ts +5 -1
  91. package/dist/components/ui/toast/toaster.d.ts.map +1 -1
  92. package/dist/components/ui/toast/toaster.js +3 -2
  93. package/dist/enterprise/data-table/index.d.ts +77 -7
  94. package/dist/enterprise/data-table/index.d.ts.map +1 -1
  95. package/dist/enterprise/data-table/index.js +56 -11
  96. package/dist/enterprise/date-range-picker/index.js +4 -4
  97. package/dist/enterprise/number-input/index.d.ts.map +1 -1
  98. package/dist/enterprise/number-input/index.js +1 -1
  99. package/dist/esm/components/breadcrumb/index.d.ts.map +1 -1
  100. package/dist/esm/components/breadcrumb/index.js +25 -1
  101. package/dist/esm/components/card/account-card/index.js +5 -5
  102. package/dist/esm/components/card/basic-card/index.d.ts.map +1 -1
  103. package/dist/esm/components/card/basic-card/index.js +2 -2
  104. package/dist/esm/components/card/entity-card/index.js +1 -1
  105. package/dist/esm/components/dialog/confirmation-dialog/index.d.ts.map +1 -1
  106. package/dist/esm/components/dialog/confirmation-dialog/index.js +4 -1
  107. package/dist/esm/components/entity-box/index.d.ts +18 -2
  108. package/dist/esm/components/entity-box/index.d.ts.map +1 -1
  109. package/dist/esm/components/entity-box/index.js +29 -4
  110. package/dist/esm/components/form/date-picker-field/index.js +1 -1
  111. package/dist/esm/components/form/date-range-field/index.js +1 -1
  112. package/dist/esm/components/form/date-time-picker-field/index.js +1 -1
  113. package/dist/esm/components/form/password-field/index.d.ts +5 -1
  114. package/dist/esm/components/form/password-field/index.d.ts.map +1 -1
  115. package/dist/esm/components/form/password-field/index.js +2 -2
  116. package/dist/esm/components/form/select-field/index.d.ts +15 -1
  117. package/dist/esm/components/form/select-field/index.d.ts.map +1 -1
  118. package/dist/esm/components/form/select-field/index.js +29 -4
  119. package/dist/esm/components/form/switch-field/index.d.ts.map +1 -1
  120. package/dist/esm/components/form/switch-field/index.js +7 -2
  121. package/dist/esm/components/page/index.d.ts +35 -1
  122. package/dist/esm/components/page/index.d.ts.map +1 -1
  123. package/dist/esm/components/page/index.js +6 -2
  124. package/dist/esm/components/page-header/index.js +1 -1
  125. package/dist/esm/components/table/id-table-cell.d.ts +13 -1
  126. package/dist/esm/components/table/id-table-cell.d.ts.map +1 -1
  127. package/dist/esm/components/table/id-table-cell.js +100 -7
  128. package/dist/esm/components/table/index.d.ts +1 -0
  129. package/dist/esm/components/table/index.d.ts.map +1 -1
  130. package/dist/esm/components/table/index.js +1 -0
  131. package/dist/esm/components/table/locked-table-actions.d.ts +24 -0
  132. package/dist/esm/components/table/locked-table-actions.d.ts.map +1 -1
  133. package/dist/esm/components/table/locked-table-actions.js +31 -1
  134. package/dist/esm/components/table/name-table-cell.d.ts +57 -4
  135. package/dist/esm/components/table/name-table-cell.d.ts.map +1 -1
  136. package/dist/esm/components/table/name-table-cell.js +50 -2
  137. package/dist/esm/components/ui/autocomplete/index.d.ts +24 -0
  138. package/dist/esm/components/ui/autocomplete/index.d.ts.map +1 -1
  139. package/dist/esm/components/ui/autocomplete/index.js +24 -0
  140. package/dist/esm/components/ui/badge/index.d.ts +11 -7
  141. package/dist/esm/components/ui/badge/index.d.ts.map +1 -1
  142. package/dist/esm/components/ui/badge/index.js +20 -8
  143. package/dist/esm/components/ui/button/index.d.ts +3 -3
  144. package/dist/esm/components/ui/copy-field/index.d.ts +25 -1
  145. package/dist/esm/components/ui/copy-field/index.d.ts.map +1 -1
  146. package/dist/esm/components/ui/copy-field/index.js +16 -8
  147. package/dist/esm/components/ui/dialog/index.d.ts +1 -1
  148. package/dist/esm/components/ui/dialog/index.d.ts.map +1 -1
  149. package/dist/esm/components/ui/dialog/index.js +3 -3
  150. package/dist/esm/components/ui/file-upload/index.d.ts +159 -0
  151. package/dist/esm/components/ui/file-upload/index.d.ts.map +1 -1
  152. package/dist/esm/components/ui/file-upload/index.js +307 -5
  153. package/dist/esm/components/ui/icon-button/index.d.ts +1 -1
  154. package/dist/esm/components/ui/lerian-wordmark/index.d.ts +6 -0
  155. package/dist/esm/components/ui/lerian-wordmark/index.d.ts.map +1 -0
  156. package/dist/esm/components/ui/lerian-wordmark/index.js +4 -0
  157. package/dist/esm/components/ui/otp-input/index.js +1 -1
  158. package/dist/esm/components/ui/radio-group/index.js +1 -1
  159. package/dist/esm/components/ui/select/index.d.ts.map +1 -1
  160. package/dist/esm/components/ui/select/index.js +8 -4
  161. package/dist/esm/components/ui/sheet/index.d.ts +42 -0
  162. package/dist/esm/components/ui/sheet/index.d.ts.map +1 -1
  163. package/dist/esm/components/ui/sheet/index.js +48 -15
  164. package/dist/esm/components/ui/sidebar/index.d.ts +1 -0
  165. package/dist/esm/components/ui/sidebar/index.d.ts.map +1 -1
  166. package/dist/esm/components/ui/sidebar/index.js +1 -0
  167. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts +1 -1
  168. package/dist/esm/components/ui/sidebar/sidebar-expand-button.d.ts.map +1 -1
  169. package/dist/esm/components/ui/sidebar/sidebar-expand-button.js +15 -1
  170. package/dist/esm/components/ui/sidebar/sidebar-item.d.ts +1 -1
  171. package/dist/esm/components/ui/sidebar/sidebar-item.d.ts.map +1 -1
  172. package/dist/esm/components/ui/sidebar/sidebar-item.js +28 -4
  173. package/dist/esm/components/ui/sidebar/sidebar-provider.d.ts +58 -0
  174. package/dist/esm/components/ui/sidebar/sidebar-provider.d.ts.map +1 -1
  175. package/dist/esm/components/ui/sidebar/sidebar-provider.js +143 -1
  176. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts +38 -1
  177. package/dist/esm/components/ui/sidebar/sidebar-root.d.ts.map +1 -1
  178. package/dist/esm/components/ui/sidebar/sidebar-root.js +113 -7
  179. package/dist/esm/components/ui/sidebar/sidebar-trigger.d.ts +45 -0
  180. package/dist/esm/components/ui/sidebar/sidebar-trigger.d.ts.map +1 -0
  181. package/dist/esm/components/ui/sidebar/sidebar-trigger.js +53 -0
  182. package/dist/esm/components/ui/textarea/index.js +1 -1
  183. package/dist/esm/components/ui/toast/toaster.d.ts +5 -1
  184. package/dist/esm/components/ui/toast/toaster.d.ts.map +1 -1
  185. package/dist/esm/components/ui/toast/toaster.js +3 -2
  186. package/dist/esm/enterprise/data-table/index.d.ts +77 -7
  187. package/dist/esm/enterprise/data-table/index.d.ts.map +1 -1
  188. package/dist/esm/enterprise/data-table/index.js +57 -12
  189. package/dist/esm/enterprise/date-range-picker/index.js +4 -4
  190. package/dist/esm/enterprise/number-input/index.d.ts.map +1 -1
  191. package/dist/esm/enterprise/number-input/index.js +1 -1
  192. package/dist/esm/hooks/use-toast.d.ts +18 -2
  193. package/dist/esm/hooks/use-toast.d.ts.map +1 -1
  194. package/dist/esm/hooks/use-toast.js +60 -16
  195. package/dist/esm/index.d.ts +3 -0
  196. package/dist/esm/index.d.ts.map +1 -1
  197. package/dist/esm/index.js +3 -0
  198. package/dist/esm/lib/utils.d.ts +2 -0
  199. package/dist/esm/lib/utils.d.ts.map +1 -1
  200. package/dist/esm/lib/utils.js +10 -0
  201. package/dist/esm/toast/helpers.d.ts +13 -0
  202. package/dist/esm/toast/helpers.d.ts.map +1 -1
  203. package/dist/esm/toast/helpers.js +8 -1
  204. package/dist/fonts/OFL.txt +96 -0
  205. package/dist/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
  206. package/dist/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
  207. package/dist/fonts/ibm-plex-serif-latin-400.woff2 +0 -0
  208. package/dist/fonts/ibm-plex-serif-latin-500.woff2 +0 -0
  209. package/dist/fonts/inter-latin.woff2 +0 -0
  210. package/dist/fonts.css +46 -0
  211. package/dist/globals.css +62 -362
  212. package/dist/hooks/use-toast.d.ts +18 -2
  213. package/dist/hooks/use-toast.d.ts.map +1 -1
  214. package/dist/hooks/use-toast.js +61 -16
  215. package/dist/index.d.ts +3 -0
  216. package/dist/index.d.ts.map +1 -1
  217. package/dist/index.js +3 -0
  218. package/dist/lib/utils.d.ts +2 -0
  219. package/dist/lib/utils.d.ts.map +1 -1
  220. package/dist/lib/utils.js +11 -0
  221. package/dist/public/wordmark.svg +1 -0
  222. package/dist/standalone.css +10 -0
  223. package/dist/toast/helpers.d.ts +13 -0
  224. package/dist/toast/helpers.d.ts.map +1 -1
  225. package/dist/toast/helpers.js +8 -1
  226. package/dist/tokens.css +367 -0
  227. package/package.json +9 -6
@@ -2,7 +2,7 @@ import { type VariantProps } from 'class-variance-authority';
2
2
  import { buttonVariants } from '../button/index.js';
3
3
  export declare const iconButtonVariants: (props?: ({
4
4
  rounded?: boolean | null | undefined;
5
- size?: "default" | "small" | null | undefined;
5
+ size?: "small" | "default" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export type IconButtonProps = React.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
8
8
  rounded?: boolean;
@@ -0,0 +1,6 @@
1
+ export type LerianWordmarkProps = {
2
+ className?: string;
3
+ title?: string;
4
+ };
5
+ export declare function LerianWordmark({ className, title }: LerianWordmarkProps): import("react").JSX.Element;
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/lerian-wordmark/index.tsx"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,KAAgB,EACjB,EAAE,mBAAmB,+BAiBrB"}
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export function LerianWordmark({ className, title = 'Lerian' }) {
3
+ return (_jsx("svg", { "data-slot": "lerian-wordmark", viewBox: "0 0 1090.88 280", role: "img", "aria-label": title, fill: "currentColor", xmlns: "http://www.w3.org/2000/svg", className: className, children: _jsx("path", { fillRule: "evenodd", d: "M619.42,29.69c0,15.43-10.87,27.93-27.93,27.93s-27.93-12.51-27.93-27.93,10.86-27.93,27.92-27.93,27.93,12.51,27.93,27.93h0ZM158.64,242.4v33.54H12.13v-33.55h48.36c3.16,0,5.73-2.57,5.73-5.73V87.77c0-3.16-2.57-5.73-5.73-5.73H7.85v-34.31h98.33v188.94c0,3.16,2.57,5.73,5.73,5.73h46.74ZM168.85,179.86c0,58.52,37.29,98.33,99.47,98.33,49.15,0,79.7-30.6,86.27-67.08h-40.69c-6.29,24.54-26.97,33.91-48.61,33.91-48.85,0-53.41-45.18-53.83-55-.04-1.02.77-1.87,1.79-1.87h143.61c.76-5.26,1.13-10.42,1.13-15.44,0-32.71-20.25-91.92-95.33-91.92-57.04,0-93.8,41.26-93.81,99.07ZM314.47,158.39l-99.49.02c-1.08,0-1.94-.96-1.78-2.02,4.49-31.28,30.98-42.82,50.98-42.82,33.88,0,48.71,21.59,52.08,42.79.17,1.08-.69,2.04-1.78,2.04h0ZM867.2,83.16h0s0,0,0,0h0ZM826.87,83.16h40.33v192.83h-40.32v-24.53c0-3.09-3.92-4.41-5.79-1.95-.18.23-.35.47-.53.71h0s0,.02,0,.02h0c-.11.16-.23.32-.35.47-7.92,10.56-20.68,27.53-56.24,27.53-60.83,0-91.19-46.33-91.19-98.7,0-61.42,40.37-98.72,91.17-98.72,36.73,0,48.44,15.73,56.64,26.75l.49.66c1.86,2.49,5.81,1.18,5.81-1.93v-23.14ZM770.75,115.48c34.78,0,56.14,27.81,56.14,64.8h0c0,42-26.32,63.68-56.14,63.68-34.83,0-56.14-27.43-56.14-64.43,0-42.07,26.11-64.05,56.14-64.05ZM1063.39,101.7c14.42,14.06,21.64,36.67,21.64,67.8v106.25h-41.06v-103.99c0-43.98-22.35-56.14-45.96-56.14-31.99,0-51.6,23.22-51.6,62.92v97.21h-40.68V83.15h39.93v25.07c0,3.11,3.95,4.4,5.82,1.92,8.55-11.4,26.72-29.52,55.98-29.52,37.55,0,55.75,20.88,55.93,21.08ZM657.42,275.94v-33.54h0s-37.37,0-37.37,0c-3.16,0-5.73-2.57-5.73-5.73V83.14h-81.34v34.31h37.54c3.16,0,5.73,2.57,5.73,5.73v113.48c0,3.16-2.57,5.73-5.73,5.73h-38.14v33.55h125.03ZM499.27,119.27c0,.13-.1.23-.23.23h0s-36.31,0-36.31,0c-28.68,0-28.65,24.99-28.64,43.62,0,.46,0,.92,0,1.37v111.24c0,.13-.1.23-.23.23h-41.01c-.13,0-.23-.1-.23-.23V83.27c0-.13.1-.23.23-.23h36.49c.13,0,.23.1.23.23v24.03c0,4.05,5.24,5.65,7.49,2.28.22-.32.43-.64.65-.97,8.18-12.25,18.71-28.02,52.51-28.02h9.05v38.68Z" }) }));
4
+ }
@@ -12,7 +12,7 @@ function InputOTPGroup({ className, ...props }) {
12
12
  function InputOTPSlot({ index, className, ...props }) {
13
13
  const inputOTPContext = React.useContext(OTPInputContext);
14
14
  const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
15
- return (_jsxs("div", { "data-slot": "input-otp-slot", "data-active": isActive, className: cn('border-input-border bg-background text-foreground', 'relative flex h-14 w-12 items-center justify-center border-y border-r text-2xl font-semibold shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md', 'data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:z-10 data-[active=true]:ring-2', className), ...props, children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "motion-safe:animate-caret-blink bg-foreground h-6 w-px duration-1000" }) }))] }));
15
+ return (_jsxs("div", { "data-slot": "input-otp-slot", "data-active": isActive, className: cn('border-input-border bg-background text-foreground', 'relative flex h-14 w-12 items-center justify-center border-y border-r text-2xl font-semibold shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md', 'data-[active=true]:ring-ring data-[active=true]:z-10 data-[active=true]:ring-2', className), ...props, children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "motion-safe:animate-caret-blink bg-foreground h-6 w-px duration-1000" }) }))] }));
16
16
  }
17
17
  function InputOTPSeparator({ ...props }) {
18
18
  return (_jsx("div", { "data-slot": "input-otp-separator", role: "separator", ...props, children: _jsx(MinusIcon, {}) }));
@@ -7,6 +7,6 @@ function RadioGroup({ className, ...props }) {
7
7
  return (_jsx(RadioGroupPrimitive.Root, { "data-slot": "radio-group", className: cn('grid gap-3', className), ...props }));
8
8
  }
9
9
  function RadioGroupItem({ className, ...props }) {
10
- return (_jsx(RadioGroupPrimitive.Item, { "data-slot": "radio-group-item", className: cn('border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', className), ...props, children: _jsx(RadioGroupPrimitive.Indicator, { "data-slot": "radio-group-indicator", className: "relative flex items-center justify-center", children: _jsx(Circle, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" }) }) }));
10
+ return (_jsx(RadioGroupPrimitive.Item, { "data-slot": "radio-group-item", className: cn('border-input-border text-primary focus-visible:ring-ring aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:aria-invalid:ring-destructive/40 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50', className), ...props, children: _jsx(RadioGroupPrimitive.Indicator, { "data-slot": "radio-group-indicator", className: "relative flex items-center justify-center", children: _jsx(Circle, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" }) }) }));
11
11
  }
12
12
  export { RadioGroup, RadioGroupItem };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/select/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAKzD,iBAAS,MAAM,CAAC,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,qBAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAEpD;AAED;;;;GAIG;AACH,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAEpD;AAED,KAAK,kBAAkB,GAAG,KAAK,CAAC,cAAc,CAC5C,OAAO,eAAe,CAAC,OAAO,CAC/B,GAAG;IACF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAsBD,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,kBAAkB,qBAsBpB;AAED,iBAAS,oBAAoB,CAAC,EAC5B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC,qBAU7D;AACD,iBAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,gBAAgB,CAAC,qBAU/D;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,qBA0CtD;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,qBAQvC;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAQpD;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,qBAgBnD;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,SAAS,CAAC,qBAQxD;AAED,OAAO,EACL,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/select/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAA;AAKzD,iBAAS,MAAM,CAAC,EACd,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,qBAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAEpD;AAED;;;;GAIG;AACH,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAEpD;AAED,KAAK,kBAAkB,GAAG,KAAK,CAAC,cAAc,CAC5C,OAAO,eAAe,CAAC,OAAO,CAC/B,GAAG;IACF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AA0BD,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,kBAAkB,qBAsBpB;AAED,iBAAS,oBAAoB,CAAC,EAC5B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC,qBAU7D;AACD,iBAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,gBAAgB,CAAC,qBAU/D;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,qBA0CtD;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,wBAAwB,CAAC,KAAK,CAAC,qBAQvC;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,qBAQpD;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,qBAgBnD;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,SAAS,CAAC,qBAQxD;AAED,OAAO,EACL,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,CAAA"}
@@ -27,15 +27,19 @@ function SelectValue({ ...props }) {
27
27
  * slot shrink, `truncate` ellipsises what no longer fits — the chevron keeps its
28
28
  * place because the value absorbs all the shrinkage.
29
29
  *
30
- * Written as a child-scoped variant on the TRIGGER because Radix strips
31
- * `className` off `Select.Value` itself; the `>` combinator holds because Radix
32
- * renders that span as the trigger's direct child.
30
+ * Written as a descendant-scoped variant on the TRIGGER because Radix strips
31
+ * `className` off `Select.Value` itself. DESCENDANT, not `>`: a trigger that
32
+ * carries a leading glyph groups the glyph and the value into one flex child
33
+ * (see `SelectField`'s `leadingIcon`), so the value span is no longer the
34
+ * trigger's direct child and a `>` combinator stopped truncating exactly where
35
+ * the trigger has the least room. The wrapper carries `min-w-0` itself, which
36
+ * is what lets the shrinkage reach the value.
33
37
  *
34
38
  * Truncation hides text, so a trigger showing a long value should also carry
35
39
  * `title` — on the trigger, never on the value slot, which Radix renders
36
40
  * `pointer-events: none`.
37
41
  */
38
- const VALUE_OVERFLOW_CLASS = '[&>[data-slot=select-value]]:min-w-0 [&>[data-slot=select-value]]:truncate';
42
+ const VALUE_OVERFLOW_CLASS = '[&_[data-slot=select-value]]:min-w-0 [&_[data-slot=select-value]]:truncate';
39
43
  function SelectTrigger({ className, readOnly, children, ...props }) {
40
44
  return (_jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": "default", className: cn('select-trigger select-read-only select-disabled', VALUE_OVERFLOW_CLASS, className), "aria-readonly": readOnly, "data-read-only": readOnly ? '' : undefined, ...props, children: [children, !readOnly && (_jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDown, { className: "select-chevron" }) }))] }));
41
45
  }
@@ -6,6 +6,48 @@ declare function SheetTrigger({ ...props }: React.ComponentProps<typeof SheetPri
6
6
  declare function SheetClose({ ...props }: React.ComponentProps<typeof SheetPrimitive.Close>): React.JSX.Element;
7
7
  declare function SheetPortal({ ...props }: React.ComponentProps<typeof SheetPrimitive.Portal>): React.JSX.Element;
8
8
  declare function SheetOverlay({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Overlay>): React.JSX.Element;
9
+ /**
10
+ * ⛔ A PANEL BUILT FOR A DESKTOP HAS TO STOP BEING TWO FIFTHS ON A PHONE.
11
+ *
12
+ * `w-2/5` and `p-12` were unconditional. At a 390px viewport that is a 156px
13
+ * panel with 59px of usable width, and a form field inside it measures 9px of
14
+ * text — a sheet that cannot be read, let alone filled in. At 320px the panel
15
+ * is 128px and the field has NOTHING: its own padding is wider than its box.
16
+ * Thirteen product-console routes opened a sheet that looked like that, which
17
+ * is why that console has carried a rule against `[data-slot='sheet-content']`
18
+ * since its M10 lane; this is that rule brought home, and the console can drop
19
+ * its copy.
20
+ *
21
+ * ⚠️ THE PHONE VALUES CARRY THE MODIFIER, THE DESKTOP ONES DO NOT, AND THAT
22
+ * ASYMMETRY IS THE WHOLE MECHANISM. `cn` resolves these through tailwind-merge
23
+ * before the cascade sees them, and tailwind-merge only drops a conflicting
24
+ * class carrying the SAME modifiers. So a caller's `w-[594px]` replaces
25
+ * `w-2/5` and leaves `max-sm:w-full` standing: the fifteen product-console
26
+ * sheets that declare a pixel width of their own — and the two that declare
27
+ * `w-full` — all still fill a phone, with no edit at the call site. Written
28
+ * the other way round — `w-full sm:w-2/5` — the caller's bare `w-[594px]`
29
+ * would have been overruled by `sm:w-2/5` at every desktop width instead,
30
+ * which is the same bug pointing the other way.
31
+ *
32
+ * ⚠️ IT CUTS BOTH WAYS, AND THE PADDING IS WHERE THAT IS FELT. A caller's bare
33
+ * `p-0` drops `p-12` and cannot reach `max-sm:px-4` either, so a panel that
34
+ * asked for no padding gets 16px a side below 40rem. That is deliberate — it
35
+ * is what makes the phone step reach the call sites that need it most — and it
36
+ * is what product-console's own unlayered rule already did to those five
37
+ * sheets, so nothing there moves. For any other consumer it is a behaviour
38
+ * change from 2.0.0-beta.11, and the way out is one token.
39
+ *
40
+ * A call site that genuinely wants its own phone width or padding says so with
41
+ * the modifier (`max-sm:w-[320px]`, `max-sm:p-0`), which is one token and
42
+ * strictly more than the console's unlayered rule allowed anyone.
43
+ *
44
+ * 40rem rather than 768px, unlike `SidebarTrigger` next door: nothing here is
45
+ * paired with a pixel media query in JavaScript. This is a reading-width
46
+ * decision and it is the complement of `sm:`, so it moves with the reader's
47
+ * font exactly as the rest of the package's responsive steps do. The one panel
48
+ * that IS coupled to the pixel breakpoint is the navigation drawer, and
49
+ * `SidebarRoot` opts it out by restating both tokens under `max-sm:`.
50
+ */
9
51
  declare const sheetVariants: (props?: ({
10
52
  side?: "bottom" | "left" | "right" | "top" | null | undefined;
11
53
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sheet/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,iBAAS,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,qBAE5E;AAED,iBAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,qBAErD;AAED,iBAAS,UAAU,CAAC,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,qBAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,qBAEpD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,qBAWrD;AAED,QAAA,MAAM,aAAa;;8EAiBlB,CAAA;AAED,KAAK,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,GAC1E,YAAY,CAAC,OAAO,aAAa,CAAC,CAAA;AAEpC,iBAAS,YAAY,CAAC,EACpB,IAAc,EACd,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,GAAG,KAAK,EACT,EAAE,iBAAiB,qBAsCnB;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,qBAWnD;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,WAAW,CAAC,qBAQzD;AAED,OAAO,EACL,KAAK,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EACjB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sheet/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,iBAAS,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,qBAE5E;AAED,iBAAS,YAAY,CAAC,EACpB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,qBAErD;AAED,iBAAS,UAAU,CAAC,EAClB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,qBAEnD;AAED,iBAAS,WAAW,CAAC,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,MAAM,CAAC,qBAEpD;AAED,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,qBAWrD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,QAAA,MAAM,aAAa;;8EAiBlB,CAAA;AAED,KAAK,iBAAiB,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,OAAO,CAAC,GAC1E,YAAY,CAAC,OAAO,aAAa,CAAC,CAAA;AAEpC,iBAAS,YAAY,CAAC,EACpB,IAAc,EACd,SAAS,EACT,QAAQ,EACR,iBAAiB,EACjB,GAAG,KAAK,EACT,EAAE,iBAAiB,qBA6BnB;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,KAAK,CAAC,qBAWnD;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,WAAW,CAAC,qBAQzD;AAED,OAAO,EACL,KAAK,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,EACjB,CAAA"}
@@ -1,10 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import * as React from 'react';
4
3
  import * as SheetPrimitive from '@radix-ui/react-dialog';
5
4
  import { cva } from 'class-variance-authority';
6
5
  import { X } from 'lucide-react';
7
- import { cn } from '../../../lib/utils.js';
6
+ import { cn, keepOpenOnToast } from '../../../lib/utils.js';
8
7
  function Sheet({ ...props }) {
9
8
  return _jsx(SheetPrimitive.Root, { "data-slot": "sheet", ...props });
10
9
  }
@@ -20,13 +19,55 @@ function SheetPortal({ ...props }) {
20
19
  function SheetOverlay({ className, ...props }) {
21
20
  return (_jsx(SheetPrimitive.Overlay, { "data-slot": "sheet-overlay", className: cn('motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', className), ...props }));
22
21
  }
23
- const sheetVariants = cva('fixed z-50 gap-4 bg-background p-12 shadow-lg transition ease-in-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500', {
22
+ /**
23
+ * ⛔ A PANEL BUILT FOR A DESKTOP HAS TO STOP BEING TWO FIFTHS ON A PHONE.
24
+ *
25
+ * `w-2/5` and `p-12` were unconditional. At a 390px viewport that is a 156px
26
+ * panel with 59px of usable width, and a form field inside it measures 9px of
27
+ * text — a sheet that cannot be read, let alone filled in. At 320px the panel
28
+ * is 128px and the field has NOTHING: its own padding is wider than its box.
29
+ * Thirteen product-console routes opened a sheet that looked like that, which
30
+ * is why that console has carried a rule against `[data-slot='sheet-content']`
31
+ * since its M10 lane; this is that rule brought home, and the console can drop
32
+ * its copy.
33
+ *
34
+ * ⚠️ THE PHONE VALUES CARRY THE MODIFIER, THE DESKTOP ONES DO NOT, AND THAT
35
+ * ASYMMETRY IS THE WHOLE MECHANISM. `cn` resolves these through tailwind-merge
36
+ * before the cascade sees them, and tailwind-merge only drops a conflicting
37
+ * class carrying the SAME modifiers. So a caller's `w-[594px]` replaces
38
+ * `w-2/5` and leaves `max-sm:w-full` standing: the fifteen product-console
39
+ * sheets that declare a pixel width of their own — and the two that declare
40
+ * `w-full` — all still fill a phone, with no edit at the call site. Written
41
+ * the other way round — `w-full sm:w-2/5` — the caller's bare `w-[594px]`
42
+ * would have been overruled by `sm:w-2/5` at every desktop width instead,
43
+ * which is the same bug pointing the other way.
44
+ *
45
+ * ⚠️ IT CUTS BOTH WAYS, AND THE PADDING IS WHERE THAT IS FELT. A caller's bare
46
+ * `p-0` drops `p-12` and cannot reach `max-sm:px-4` either, so a panel that
47
+ * asked for no padding gets 16px a side below 40rem. That is deliberate — it
48
+ * is what makes the phone step reach the call sites that need it most — and it
49
+ * is what product-console's own unlayered rule already did to those five
50
+ * sheets, so nothing there moves. For any other consumer it is a behaviour
51
+ * change from 2.0.0-beta.11, and the way out is one token.
52
+ *
53
+ * A call site that genuinely wants its own phone width or padding says so with
54
+ * the modifier (`max-sm:w-[320px]`, `max-sm:p-0`), which is one token and
55
+ * strictly more than the console's unlayered rule allowed anyone.
56
+ *
57
+ * 40rem rather than 768px, unlike `SidebarTrigger` next door: nothing here is
58
+ * paired with a pixel media query in JavaScript. This is a reading-width
59
+ * decision and it is the complement of `sm:`, so it moves with the reader's
60
+ * font exactly as the rest of the package's responsive steps do. The one panel
61
+ * that IS coupled to the pixel breakpoint is the navigation drawer, and
62
+ * `SidebarRoot` opts it out by restating both tokens under `max-sm:`.
63
+ */
64
+ const sheetVariants = cva('fixed z-50 gap-4 bg-background p-12 max-sm:px-4 shadow-lg transition ease-in-out motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500', {
24
65
  variants: {
25
66
  side: {
26
67
  top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
27
68
  bottom: 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
28
- left: 'inset-y-0 left-0 h-full w-2/5 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left',
29
- right: 'inset-y-0 right-0 h-full w-2/5 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right'
69
+ left: 'inset-y-0 left-0 h-full w-2/5 max-sm:w-full border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left',
70
+ right: 'inset-y-0 right-0 h-full w-2/5 max-sm:w-full border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right'
30
71
  }
31
72
  },
32
73
  defaultVariants: {
@@ -34,15 +75,7 @@ const sheetVariants = cva('fixed z-50 gap-4 bg-background p-12 shadow-lg transit
34
75
  }
35
76
  });
36
77
  function SheetContent({ side = 'right', className, children, onInteractOutside, ...props }) {
37
- const handleInteractOutside = React.useCallback((event) => {
38
- const target = event.target;
39
- if (target?.closest('[data-sonner-toaster]')) {
40
- event.preventDefault();
41
- return;
42
- }
43
- onInteractOutside?.(event);
44
- }, [onInteractOutside]);
45
- return (_jsxs(SheetPortal, { children: [_jsx(SheetOverlay, {}), _jsxs(SheetPrimitive.Content, { "data-slot": "sheet-content", className: cn('flex max-h-screen flex-col overflow-x-auto px-8 pb-0', sheetVariants({ side }), className), onInteractOutside: handleInteractOutside, ...props, children: [children, _jsxs(SheetPrimitive.Close, { className: "data-[state=open]:bg-secondary absolute top-7 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-hidden disabled:pointer-events-none", children: [_jsx(X, { className: "h-6 w-6" }), _jsx("span", { className: "sr-only", children: "Close" })] })] })] }));
78
+ return (_jsxs(SheetPortal, { children: [_jsx(SheetOverlay, {}), _jsxs(SheetPrimitive.Content, { "data-slot": "sheet-content", className: cn('flex max-h-screen flex-col overflow-x-auto px-8 pb-0', sheetVariants({ side }), className), onInteractOutside: keepOpenOnToast(onInteractOutside), ...props, children: [children, _jsxs(SheetPrimitive.Close, { className: "data-[state=open]:bg-secondary ring-offset-background focus-visible:ring-ring absolute top-7 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-hidden disabled:pointer-events-none", children: [_jsx(X, { className: "h-6 w-6" }), _jsx("span", { className: "sr-only", children: "Close" })] })] })] }));
46
79
  }
47
80
  function SheetHeader({ className, ...props }) {
48
81
  return (_jsx("div", { "data-slot": "sheet-header", className: cn('mb-4 flex flex-col space-y-2 text-center sm:text-left', className), ...props }));
@@ -54,6 +87,6 @@ function SheetTitle({ className, ...props }) {
54
87
  return (_jsx(SheetPrimitive.Title, { "data-slot": "sheet-title", className: cn('text-muted-foreground mb-2 flex text-xl font-bold', className), ...props }));
55
88
  }
56
89
  function SheetDescription({ className, ...props }) {
57
- return (_jsx(SheetPrimitive.Description, { "data-slot": "sheet-description", className: cn('text-shadcn-500 text-sm font-medium', className), ...props }));
90
+ return (_jsx(SheetPrimitive.Description, { "data-slot": "sheet-description", className: cn('text-muted-foreground text-sm font-medium', className), ...props }));
58
91
  }
59
92
  export { Sheet, SheetPortal, SheetOverlay, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription };
@@ -4,6 +4,7 @@ export * from './sidebar-item-icon-button.js';
4
4
  export * from './sidebar-item-button.js';
5
5
  export * from './sidebar-item.js';
6
6
  export * from './sidebar-expand-button.js';
7
+ export * from './sidebar-trigger.js';
7
8
  export * from './sidebar-back-button.js';
8
9
  export * from './sidebar-provider.js';
9
10
  export * from './sidebar-item-collapsible.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/index.tsx"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,uBAAuB,CAAA;AACrC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,yBAAyB,CAAA;AACvC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/index.tsx"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,sBAAsB,CAAA;AACpC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,uBAAuB,CAAA;AACrC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,kBAAkB,CAAA"}
@@ -4,6 +4,7 @@ export * from './sidebar-item-icon-button.js';
4
4
  export * from './sidebar-item-button.js';
5
5
  export * from './sidebar-item.js';
6
6
  export * from './sidebar-expand-button.js';
7
+ export * from './sidebar-trigger.js';
7
8
  export * from './sidebar-back-button.js';
8
9
  export * from './sidebar-provider.js';
9
10
  export * from './sidebar-item-collapsible.js';
@@ -7,6 +7,6 @@ type SidebarExpandButtonProps = {
7
7
  */
8
8
  tooltip?: string;
9
9
  };
10
- export declare const SidebarExpandButton: ({ tooltip }: SidebarExpandButtonProps) => React.JSX.Element;
10
+ export declare const SidebarExpandButton: ({ tooltip }: SidebarExpandButtonProps) => React.JSX.Element | null;
11
11
  export {};
12
12
  //# sourceMappingURL=sidebar-expand-button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-expand-button.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-expand-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,KAAK,wBAAwB,GAAG;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,aAAa,wBAAwB,sBAyDxE,CAAA"}
1
+ {"version":3,"file":"sidebar-expand-button.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-expand-button.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,KAAK,wBAAwB,GAAG;IAC9B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,aAAa,wBAAwB,6BAwExE,CAAA"}
@@ -7,7 +7,21 @@ import { SidebarFooter } from './sidebar-components.js';
7
7
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip/index.js';
8
8
  import { IconButton } from '../icon-button/index.js';
9
9
  export const SidebarExpandButton = ({ tooltip }) => {
10
- const { isCollapsed, toggleSidebar } = useSidebar();
10
+ const { isCollapsed, isDrawer, toggleSidebar } = useSidebar();
11
+ /**
12
+ * Nothing to collapse in a drawer. The expanded branch below hangs its button
13
+ * at `right-[-20px]`, twenty pixels outside the rail — off the canvas of an
14
+ * overlay that has no page beside it — and collapsing to a 72px strip inside
15
+ * a 244px sheet is not a state worth reaching. The drawer's own close control
16
+ * and the backdrop are how it is dismissed.
17
+ *
18
+ * ⚠️ `isDrawer`, NOT `isMobile`. A consumer left on the default
19
+ * `mobile="inline"` still has a real rail below 768px, and its collapse
20
+ * control has to come with it.
21
+ */
22
+ if (isDrawer) {
23
+ return null;
24
+ }
11
25
  return (_jsxs(React.Fragment, { children: [!isCollapsed && (_jsx("div", { "data-slot": "sidebar-expand-button", className: "border-border bg-card flex w-full", children: _jsx("div", { className: "absolute right-[-20px] bottom-4", children: _jsx(IconButton, { variant: "secondary", rounded: true, onClick: toggleSidebar, "aria-label": tooltip || 'Collapse sidebar', "aria-expanded": true, children: _jsx(PanelLeftClose, { className: "text-muted-foreground" }) }) }) })), isCollapsed && (_jsx(SidebarFooter, { children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger
12
26
  // `hover:text-accent-foreground` on the TRIGGER, not only on
13
27
  // the glyph below. The base ink here used to be base/400, which
@@ -9,5 +9,5 @@ export type SidebarItemProps = React.ComponentProps<typeof SidebarItemButton> &
9
9
  disabled?: boolean;
10
10
  children?: React.ReactNode;
11
11
  };
12
- export declare const SidebarItem: ({ active, href, children: _children, ...props }: SidebarItemProps) => React.JSX.Element;
12
+ export declare const SidebarItem: ({ active, href, children: _children, onClick, ...props }: SidebarItemProps) => React.JSX.Element;
13
13
  //# sourceMappingURL=sidebar-item.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-item.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-item.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAIlE,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,iBAAiB,CAAC,GAC3E,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,GAAG;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,CAAA;AAEH,eAAO,MAAM,WAAW,GAAI,iDAKzB,gBAAgB,sBA0BlB,CAAA"}
1
+ {"version":3,"file":"sidebar-item.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-item.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAIlE,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,iBAAiB,CAAC,GAC3E,KAAK,CAAC,cAAc,CAAC,OAAO,qBAAqB,CAAC,GAAG;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,CAAA;AAEH,eAAO,MAAM,WAAW,GAAI,0DAMzB,gBAAgB,sBAsDlB,CAAA"}
@@ -4,13 +4,37 @@ import { SidebarItemButton } from './sidebar-item-button.js';
4
4
  import { SidebarItemIconButton } from './sidebar-item-icon-button.js';
5
5
  import { useSidebar } from './sidebar-provider.js';
6
6
  import { useSidebarRouter } from './sidebar-router.js';
7
- export const SidebarItem = ({ active, href, children: _children, ...props }) => {
7
+ export const SidebarItem = ({ active, href, children: _children, onClick, ...props }) => {
8
8
  const { usePathname } = useSidebarRouter();
9
9
  const pathname = usePathname();
10
- const { isCollapsed } = useSidebar();
10
+ const { isCollapsed, isDrawer, setOpenMobile } = useSidebar();
11
11
  const isActive = (href) => pathname === href;
12
+ /**
13
+ * ⛔ ACTIVATING A DESTINATION CLOSES THE DRAWER. It is the whole point of the
14
+ * drawer and it was the one interaction that left it open: Escape, the
15
+ * backdrop and the X all dismissed it, a navigation link did not.
16
+ *
17
+ * The overlay is modal, so `document.body` carries `pointer-events: none`
18
+ * while it is up, and a consumer's `SidebarItem` is a client-side `Link`
19
+ * under a provider that survives the route change — so the reader landed on
20
+ * the new page rendered INERT behind a drawer they had to dismiss a second
21
+ * time, on a phone.
22
+ *
23
+ * Here rather than in `SidebarRoot`, because this is the component that knows
24
+ * an activation happened; `SidebarBackButton` and every
25
+ * `SidebarItemCollapsibleContent` leaf render through it, so they are covered
26
+ * by construction. Guarded on `isDrawer` so an inline rail — where nothing is
27
+ * covering the page — behaves exactly as before, and the consumer's own
28
+ * handler still runs either way.
29
+ */
30
+ const handleClick = (event) => {
31
+ onClick?.(event);
32
+ if (isDrawer) {
33
+ setOpenMobile(false);
34
+ }
35
+ };
12
36
  if (isCollapsed) {
13
- return (_jsx(SidebarItemIconButton, { "data-slot": "sidebar-item", href: href, active: isActive(href) || active, ...props }));
37
+ return (_jsx(SidebarItemIconButton, { "data-slot": "sidebar-item", href: href, active: isActive(href) || active, onClick: handleClick, ...props }));
14
38
  }
15
- return (_jsx(SidebarItemButton, { "data-slot": "sidebar-item", href: href, active: isActive(href) || active, ...props }));
39
+ return (_jsx(SidebarItemButton, { "data-slot": "sidebar-item", href: href, active: isActive(href) || active, onClick: handleClick, ...props }));
16
40
  };
@@ -1,12 +1,70 @@
1
1
  import React from 'react';
2
+ /**
3
+ * The viewport below which the rail stops being a layout and becomes a drawer.
4
+ *
5
+ * ⛔ THE NEGATION OF THE TRIGGER'S QUERY, SPELLED AS A NEGATION.
6
+ *
7
+ * `SidebarTrigger` hides itself at `min-[768px]`, which is `width >= 768`. This
8
+ * is its exact complement AT ANY PRECISION, which `(max-width: 767px)` was not:
9
+ * that pair leaves the open interval (767, 768) matched by neither rule, and a
10
+ * viewport there draws the rail AND a hamburger that opens nothing — with the
11
+ * rail inline, `SidebarRoot` mounts no `Sheet`, so the control is dead. Chromium
12
+ * snaps its layout viewport to a whole pixel and never lands there, measured at
13
+ * four zoom levels; that is a rounding behaviour to rely on, not a boundary.
14
+ *
15
+ * ⚠️ THE PAIR HAS TO BE IN THE SAME UNIT. It used to be `md:hidden` over there,
16
+ * and `md` is 48rem: rem in a media query follows the BROWSER'S default font
17
+ * size, so at Chrome's "Small" setting that class hid the hamburger from 576px
18
+ * while this query still asked for a drawer up to 767px — a band of viewports
19
+ * with no navigation at all. Anything else that hides or shows a control at
20
+ * this boundary states it in pixels for the same reason.
21
+ *
22
+ * Media Queries Level 4 boolean logic, which is not a new requirement here:
23
+ * Tailwind v4 emits MQ4 RANGE syntax for everything this package ships —
24
+ * `min-[768px]` on the trigger compiles to `@media (width >= 768px)` and
25
+ * `max-sm:` on `SheetContent` to `@media (width < 40rem)` — and range syntax
26
+ * and boolean `not` landed in the same browsers (Chrome 88, Firefox 64,
27
+ * Safari 16.4). `(width < 768px)` is the equivalent range spelling of this
28
+ * line, should a reader prefer the pair to match character for character.
29
+ */
30
+ export declare const SIDEBAR_MOBILE_QUERY = "not (min-width: 768px)";
2
31
  export type SidebarContextProps = {
3
32
  isCollapsed: boolean;
33
+ /**
34
+ * True only inside a drawer that `SidebarRoot` is actually rendering, which
35
+ * needs `mobile="drawer"` as well as a narrow viewport. `SidebarRoot`
36
+ * re-provides the context for that subtree; nothing else sets it.
37
+ */
38
+ isDrawer: boolean;
39
+ /**
40
+ * True while the viewport is narrow enough for a drawer. Reported in BOTH
41
+ * modes, so a consumer still on `mobile="inline"` can build its own
42
+ * responsive behaviour from it.
43
+ */
44
+ isMobile: boolean;
45
+ /** Whether the mobile drawer is showing. Meaningless while `isMobile` is false. */
46
+ openMobile: boolean;
47
+ setOpenMobile: (open: boolean) => void;
48
+ /**
49
+ * Puts focus back on whatever opened the drawer. `SidebarRoot` calls it when
50
+ * the drawer closes; nothing else should need it.
51
+ */
52
+ restoreDrawerFocus: () => void;
53
+ /** The drawer's DOM id, so `SidebarTrigger` can point `aria-controls` at it. */
54
+ sidebarId: string;
4
55
  items: Record<string, boolean>;
5
56
  setItems: React.Dispatch<React.SetStateAction<Record<string, boolean>>>;
6
57
  getItemCollapsed: (key: string) => boolean;
7
58
  setItemCollapsed: (key: string, value: boolean) => void;
8
59
  toggleSidebar: () => void;
9
60
  };
61
+ /**
62
+ * Exported so `SidebarRoot` can re-provide it for the drawer's subtree. That
63
+ * subtree is the only place `isCollapsed` and `isDrawer` differ from the
64
+ * provider's own values, and scoping the override to it is what keeps a
65
+ * consumer on `mobile="inline"` seeing exactly today's rail.
66
+ */
67
+ export declare const SidebarContext: React.Context<SidebarContextProps | undefined>;
10
68
  export declare const useSidebar: () => SidebarContextProps;
11
69
  export declare const SidebarProvider: ({ children }: React.PropsWithChildren) => React.JSX.Element;
12
70
  //# sourceMappingURL=sidebar-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-provider.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAA;IACpB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACvE,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IAC1C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACvD,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAMD,eAAO,MAAM,UAAU,2BAMtB,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,cAAc,KAAK,CAAC,iBAAiB,sBAqDpE,CAAA"}
1
+ {"version":3,"file":"sidebar-provider.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/sidebar/sidebar-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,oBAAoB,2BAA2B,CAAA;AAU5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,mFAAmF;IACnF,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;OAGG;IACH,kBAAkB,EAAE,MAAM,IAAI,CAAA;IAC9B,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;IACvE,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAA;IAC1C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;IACvD,aAAa,EAAE,MAAM,IAAI,CAAA;CAC1B,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,gDAEf,CAAA;AAEZ,eAAO,MAAM,UAAU,2BAMtB,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,cAAc,KAAK,CAAC,iBAAiB,sBAkKpE,CAAA"}
@@ -2,7 +2,49 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React from 'react';
4
4
  import { getStorage, getStorageObject } from '../../../lib/storage/index.js';
5
- const SidebarContext = React.createContext(undefined);
5
+ /**
6
+ * The viewport below which the rail stops being a layout and becomes a drawer.
7
+ *
8
+ * ⛔ THE NEGATION OF THE TRIGGER'S QUERY, SPELLED AS A NEGATION.
9
+ *
10
+ * `SidebarTrigger` hides itself at `min-[768px]`, which is `width >= 768`. This
11
+ * is its exact complement AT ANY PRECISION, which `(max-width: 767px)` was not:
12
+ * that pair leaves the open interval (767, 768) matched by neither rule, and a
13
+ * viewport there draws the rail AND a hamburger that opens nothing — with the
14
+ * rail inline, `SidebarRoot` mounts no `Sheet`, so the control is dead. Chromium
15
+ * snaps its layout viewport to a whole pixel and never lands there, measured at
16
+ * four zoom levels; that is a rounding behaviour to rely on, not a boundary.
17
+ *
18
+ * ⚠️ THE PAIR HAS TO BE IN THE SAME UNIT. It used to be `md:hidden` over there,
19
+ * and `md` is 48rem: rem in a media query follows the BROWSER'S default font
20
+ * size, so at Chrome's "Small" setting that class hid the hamburger from 576px
21
+ * while this query still asked for a drawer up to 767px — a band of viewports
22
+ * with no navigation at all. Anything else that hides or shows a control at
23
+ * this boundary states it in pixels for the same reason.
24
+ *
25
+ * Media Queries Level 4 boolean logic, which is not a new requirement here:
26
+ * Tailwind v4 emits MQ4 RANGE syntax for everything this package ships —
27
+ * `min-[768px]` on the trigger compiles to `@media (width >= 768px)` and
28
+ * `max-sm:` on `SheetContent` to `@media (width < 40rem)` — and range syntax
29
+ * and boolean `not` landed in the same browsers (Chrome 88, Firefox 64,
30
+ * Safari 16.4). `(width < 768px)` is the equivalent range spelling of this
31
+ * line, should a reader prefer the pair to match character for character.
32
+ */
33
+ export const SIDEBAR_MOBILE_QUERY = 'not (min-width: 768px)';
34
+ /**
35
+ * Where focus goes when the rail has to receive it. The rail's own content is
36
+ * links and buttons, so this is deliberately the short list rather than the
37
+ * full tabbable grammar: a `[tabindex]` sweep would have to exclude `-1`, and
38
+ * nothing in a sidebar carries one.
39
+ */
40
+ const FOCUSABLE = 'a[href], button:not([disabled])';
41
+ /**
42
+ * Exported so `SidebarRoot` can re-provide it for the drawer's subtree. That
43
+ * subtree is the only place `isCollapsed` and `isDrawer` differ from the
44
+ * provider's own values, and scoping the override to it is what keeps a
45
+ * consumer on `mobile="inline"` seeing exactly today's rail.
46
+ */
47
+ export const SidebarContext = React.createContext(undefined);
6
48
  export const useSidebar = () => {
7
49
  const context = React.useContext(SidebarContext);
8
50
  if (!context) {
@@ -14,6 +56,61 @@ export const SidebarProvider = ({ children }) => {
14
56
  const [hydrated, setHydrated] = React.useState(false);
15
57
  const [collapsed, setCollapsed] = React.useState(false);
16
58
  const [items, _setItems] = React.useState({});
59
+ const [isMobile, setIsMobile] = React.useState(false);
60
+ const [openMobile, _setOpenMobile] = React.useState(false);
61
+ const sidebarId = React.useId();
62
+ /**
63
+ * ⛔ RADIX CANNOT RESTORE THIS FOCUS BY ITSELF. `DialogContent` preventDefaults
64
+ * the focus scope's own restore and focuses `triggerRef.current` instead —
65
+ * the ref a `SheetTrigger` would have filled. The drawer is opened from this
66
+ * state rather than from a trigger inside the dialog, so that ref is null and
67
+ * closing dropped focus onto `<body>`: a keyboard reader who opened the
68
+ * navigation and pressed Escape was returned to the top of the document.
69
+ *
70
+ * Captured here rather than in `SidebarTrigger` so that a consumer opening
71
+ * the drawer from its own control gets the same behaviour.
72
+ */
73
+ const opener = React.useRef(null);
74
+ const setOpenMobile = React.useCallback((open) => {
75
+ if (open && typeof document !== 'undefined') {
76
+ opener.current = document.activeElement;
77
+ }
78
+ _setOpenMobile(open);
79
+ }, []);
80
+ /**
81
+ * ⛔ THE VIEWPORT AT THE MOMENT FOCUS MOVES, NOT AT THE MOMENT IT OPENED.
82
+ *
83
+ * Radix calls `restoreDrawerFocus` from the focus scope's UNMOUNT handler,
84
+ * which is the last thing in the commit to touch focus — later than any
85
+ * effect in this provider, so the decision has to be made inside the handler
86
+ * rather than beside it. By then `isMobile` has already flipped.
87
+ */
88
+ const isMobileRef = React.useRef(false);
89
+ isMobileRef.current = isMobile;
90
+ const restoreDrawerFocus = React.useCallback(() => {
91
+ // `isConnected`: the control that opened the drawer may itself have been
92
+ // unmounted by whatever the reader did inside it.
93
+ //
94
+ // ⛔ AND NOT AT ALL WHEN THE VIEWPORT IS THE ONE THAT DISMISSED IT. A
95
+ // tablet rotated from portrait to landscape with the navigation open
96
+ // crosses 768px, so the drawer is replaced by the rail and the opener is
97
+ // `SidebarTrigger` — which the same breakpoint just hid.
98
+ // `.focus()` on a `display: none` element is a silent no-op, and Radix's
99
+ // own restore is already `preventDefault()`ed, so focus fell to `<body>`
100
+ // and the reader lost their place (SC 2.4.3). Measured in Chromium at
101
+ // 390 → 1280: `{"rails":1,"triggerDisplay":"none","focus":"BODY:"}`.
102
+ if (isMobileRef.current && opener.current?.isConnected) {
103
+ opener.current.focus();
104
+ return;
105
+ }
106
+ // The rail is what the drawer became, so that is where the reader goes.
107
+ // Below the breakpoint there is nothing here to find — a closed drawer
108
+ // leaves no navigation in the DOM — and focus stays where Radix left it.
109
+ document
110
+ .getElementById(sidebarId)
111
+ ?.querySelector(FOCUSABLE)
112
+ ?.focus();
113
+ }, [sidebarId]);
17
114
  const toggleSidebar = () => setCollapsed((collapsed) => !collapsed);
18
115
  const getItemCollapsed = (key) => {
19
116
  return items[key] || false;
@@ -27,6 +124,37 @@ export const SidebarProvider = ({ children }) => {
27
124
  _setItems(getStorageObject('sidebar-items', {}));
28
125
  setHydrated(true);
29
126
  }, []);
127
+ /**
128
+ * ⚠️ FALSE UNTIL THE CLIENT SAYS OTHERWISE. There is no viewport on the
129
+ * server, so the first paint is always the rail and the drawer appears on
130
+ * hydration; starting from a guess would make the markup differ between the
131
+ * two renders. The `matchMedia` guard is the one `theme-provider.tsx` next
132
+ * door already carries: jsdom and some embedded runtimes ship without it, and
133
+ * a missing media API is a desktop, not a crash.
134
+ */
135
+ React.useEffect(() => {
136
+ if (typeof window.matchMedia !== 'function') {
137
+ return;
138
+ }
139
+ const media = window.matchMedia(SIDEBAR_MOBILE_QUERY);
140
+ const sync = () => setIsMobile(media.matches);
141
+ sync();
142
+ media.addEventListener('change', sync);
143
+ return () => media.removeEventListener('change', sync);
144
+ }, []);
145
+ /**
146
+ * A drawer left open while the viewport grows back would keep an overlay and
147
+ * a focus trap over a layout that is already showing its rail, with nothing
148
+ * on screen to dismiss them.
149
+ *
150
+ * Where focus goes afterwards is `restoreDrawerFocus`'s decision, not this
151
+ * effect's: Radix's unmount handler runs later than anything here.
152
+ */
153
+ React.useEffect(() => {
154
+ if (!isMobile) {
155
+ _setOpenMobile(false);
156
+ }
157
+ }, [isMobile]);
30
158
  // Only persist to localStorage after hydration to avoid overwriting stored values
31
159
  React.useEffect(() => {
32
160
  if (!hydrated) {
@@ -41,7 +169,21 @@ export const SidebarProvider = ({ children }) => {
41
169
  localStorage.setItem('sidebar-items', JSON.stringify(items));
42
170
  }, [items, hydrated]);
43
171
  return (_jsx(SidebarContext.Provider, { value: {
172
+ /**
173
+ * ⚠️ A NARROW VIEWPORT DOES NOT TOUCH THIS. It used to be forced false
174
+ * whenever `isMobile`, which silently changed the rail for every
175
+ * consumer — including the ones that never asked for a drawer.
176
+ * `SidebarRoot` overrides it for the drawer's own subtree instead, so
177
+ * the stored preference reaches an inline rail unchanged at every
178
+ * viewport.
179
+ */
44
180
  isCollapsed: collapsed,
181
+ isDrawer: false,
182
+ isMobile,
183
+ openMobile,
184
+ setOpenMobile,
185
+ restoreDrawerFocus,
186
+ sidebarId,
45
187
  items,
46
188
  setItems: _setItems,
47
189
  getItemCollapsed,