@godxjp/ui 19.6.0 → 20.1.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 (326) hide show
  1. package/README.md +8 -2
  2. package/dist/app/theme-axes.d.ts +2 -0
  3. package/dist/app/theme-axes.js +45 -0
  4. package/dist/components/charts/chart-cartesian.d.ts +2 -1
  5. package/dist/components/charts/chart-cartesian.js +52 -3
  6. package/dist/components/charts/chart-category-axis.d.ts +55 -0
  7. package/dist/components/charts/chart-category-axis.js +93 -0
  8. package/dist/components/charts/chart-frame.d.ts +10 -1
  9. package/dist/components/charts/chart-frame.js +19 -3
  10. package/dist/components/charts/compact-bar-trend.d.ts +1 -1
  11. package/dist/components/charts/compact-bar-trend.js +2 -0
  12. package/dist/components/charts/pie-chart.d.ts +1 -1
  13. package/dist/components/charts/pie-chart.js +12 -1
  14. package/dist/components/charts/recharts-peer.d.ts +49 -0
  15. package/dist/components/charts/recharts-peer.js +45 -0
  16. package/dist/components/data-display/card.d.ts +14 -3
  17. package/dist/components/data-display/card.js +22 -4
  18. package/dist/components/data-display/code-block.js +6 -2
  19. package/dist/components/data-display/collapsible.d.ts +23 -4
  20. package/dist/components/data-display/collapsible.js +119 -4
  21. package/dist/components/data-display/data-table.d.ts +39 -4
  22. package/dist/components/data-display/data-table.js +802 -270
  23. package/dist/components/data-display/descriptions.d.ts +27 -6
  24. package/dist/components/data-display/descriptions.js +58 -17
  25. package/dist/components/data-display/index.d.ts +5 -1
  26. package/dist/components/data-display/index.js +4 -0
  27. package/dist/components/data-display/legend.d.ts +15 -0
  28. package/dist/components/data-display/legend.js +11 -0
  29. package/dist/components/data-display/list-row.d.ts +10 -1
  30. package/dist/components/data-display/list-row.js +8 -2
  31. package/dist/components/data-display/popover.d.ts +60 -7
  32. package/dist/components/data-display/popover.js +268 -39
  33. package/dist/components/data-display/progress.d.ts +50 -2
  34. package/dist/components/data-display/progress.js +57 -9
  35. package/dist/components/data-display/range-timeline.d.ts +38 -0
  36. package/dist/components/data-display/range-timeline.js +161 -0
  37. package/dist/components/data-display/scroll-area.js +13 -2
  38. package/dist/components/data-display/service-launcher-card.js +10 -10
  39. package/dist/components/data-display/table.d.ts +11 -3
  40. package/dist/components/data-display/table.js +48 -18
  41. package/dist/components/data-display/tree-list.js +4 -9
  42. package/dist/components/data-entry/calendar.d.ts +2 -2
  43. package/dist/components/data-entry/calendar.js +79 -33
  44. package/dist/components/data-entry/cascader.d.ts +1 -1
  45. package/dist/components/data-entry/cascader.js +188 -24
  46. package/dist/components/data-entry/checkbox.d.ts +19 -6
  47. package/dist/components/data-entry/checkbox.js +55 -16
  48. package/dist/components/data-entry/choice-option.d.ts +1 -1
  49. package/dist/components/data-entry/color-picker.d.ts +1 -1
  50. package/dist/components/data-entry/color-picker.js +17 -5
  51. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  52. package/dist/components/data-entry/control-appearance.js +39 -0
  53. package/dist/components/data-entry/control-surface.d.ts +61 -0
  54. package/dist/components/data-entry/control-surface.js +39 -0
  55. package/dist/components/data-entry/date-picker.d.ts +1 -1
  56. package/dist/components/data-entry/date-picker.js +344 -113
  57. package/dist/components/data-entry/date-range-picker.d.ts +2 -2
  58. package/dist/components/data-entry/date-range-picker.js +278 -140
  59. package/dist/components/data-entry/field.js +0 -1
  60. package/dist/components/data-entry/form-field.d.ts +1 -1
  61. package/dist/components/data-entry/form-field.js +39 -4
  62. package/dist/components/data-entry/form.d.ts +4 -0
  63. package/dist/components/data-entry/form.js +5 -3
  64. package/dist/components/data-entry/index.d.ts +7 -3
  65. package/dist/components/data-entry/index.js +10 -1
  66. package/dist/components/data-entry/input-otp.d.ts +1 -1
  67. package/dist/components/data-entry/input.d.ts +12 -34
  68. package/dist/components/data-entry/input.js +92 -24
  69. package/dist/components/data-entry/label.d.ts +3 -2
  70. package/dist/components/data-entry/label.js +23 -10
  71. package/dist/components/data-entry/month-picker.d.ts +2 -2
  72. package/dist/components/data-entry/month-picker.js +47 -10
  73. package/dist/components/data-entry/month-range-picker.d.ts +2 -2
  74. package/dist/components/data-entry/month-range-picker.js +51 -11
  75. package/dist/components/data-entry/number-input.d.ts +7 -0
  76. package/dist/components/data-entry/number-input.js +147 -98
  77. package/dist/components/data-entry/password-input.d.ts +1 -1
  78. package/dist/components/data-entry/radio.d.ts +1 -1
  79. package/dist/components/data-entry/radio.js +61 -13
  80. package/dist/components/data-entry/search-input.d.ts +1 -1
  81. package/dist/components/data-entry/search-input.js +16 -2
  82. package/dist/components/data-entry/search-select.d.ts +2 -2
  83. package/dist/components/data-entry/search-select.js +209 -78
  84. package/dist/components/data-entry/select.d.ts +22 -4
  85. package/dist/components/data-entry/select.js +215 -163
  86. package/dist/components/data-entry/slider.d.ts +9 -1
  87. package/dist/components/data-entry/slider.js +87 -9
  88. package/dist/components/data-entry/switch.d.ts +3 -0
  89. package/dist/components/data-entry/switch.js +29 -3
  90. package/dist/components/data-entry/textarea.d.ts +14 -56
  91. package/dist/components/data-entry/textarea.js +80 -33
  92. package/dist/components/data-entry/time-picker.d.ts +2 -2
  93. package/dist/components/data-entry/time-picker.js +333 -109
  94. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  95. package/dist/components/data-entry/time-range-picker.js +89 -0
  96. package/dist/components/data-entry/transfer.d.ts +1 -1
  97. package/dist/components/data-entry/transfer.js +99 -31
  98. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  99. package/dist/components/data-entry/tree-select.d.ts +1 -1
  100. package/dist/components/data-entry/tree-select.js +197 -92
  101. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  102. package/dist/components/data-entry/tree-utils.js +7 -14
  103. package/dist/components/data-entry/upload-files.d.ts +2 -0
  104. package/dist/components/data-entry/upload-files.js +31 -0
  105. package/dist/components/data-entry/upload-request.d.ts +4 -0
  106. package/dist/components/data-entry/upload-request.js +53 -0
  107. package/dist/components/data-entry/upload-types.d.ts +28 -0
  108. package/dist/components/data-entry/upload-types.js +2 -0
  109. package/dist/components/data-entry/upload.d.ts +2 -2
  110. package/dist/components/data-entry/upload.js +482 -117
  111. package/dist/components/feedback/dialog.d.ts +105 -38
  112. package/dist/components/feedback/dialog.js +268 -193
  113. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  114. package/dist/components/feedback/overlay-close-focus.js +31 -0
  115. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  116. package/dist/components/feedback/sheet.d.ts +53 -11
  117. package/dist/components/feedback/sheet.js +150 -81
  118. package/dist/components/feedback/tooltip.d.ts +51 -7
  119. package/dist/components/feedback/tooltip.js +107 -25
  120. package/dist/components/general/button.d.ts +1 -1
  121. package/dist/components/general/button.js +7 -3
  122. package/dist/components/general/index.d.ts +1 -0
  123. package/dist/components/general/index.js +2 -0
  124. package/dist/components/general/logo.d.ts +17 -0
  125. package/dist/components/general/logo.js +22 -16
  126. package/dist/components/general/typography.d.ts +3 -0
  127. package/dist/components/general/typography.js +15 -1
  128. package/dist/components/general/visually-hidden.d.ts +3 -0
  129. package/dist/components/general/visually-hidden.js +9 -0
  130. package/dist/components/layout/app-launcher.d.ts +34 -0
  131. package/dist/components/layout/app-launcher.js +228 -0
  132. package/dist/components/layout/app-shell.d.ts +3 -1
  133. package/dist/components/layout/app-shell.js +69 -12
  134. package/dist/components/layout/aspect-ratio.js +0 -1
  135. package/dist/components/layout/auth-divider.js +0 -1
  136. package/dist/components/layout/breadcrumb.d.ts +14 -2
  137. package/dist/components/layout/breadcrumb.js +46 -4
  138. package/dist/components/layout/flex.d.ts +1 -1
  139. package/dist/components/layout/flex.js +41 -3
  140. package/dist/components/layout/index.d.ts +3 -0
  141. package/dist/components/layout/index.js +5 -1
  142. package/dist/components/layout/nav-surface.d.ts +26 -0
  143. package/dist/components/layout/nav-surface.js +17 -0
  144. package/dist/components/layout/org-switcher.d.ts +5 -1
  145. package/dist/components/layout/org-switcher.js +25 -4
  146. package/dist/components/layout/page-container.d.ts +1 -1
  147. package/dist/components/layout/page-container.js +5 -3
  148. package/dist/components/layout/responsive-grid.d.ts +16 -2
  149. package/dist/components/layout/responsive-grid.js +29 -2
  150. package/dist/components/layout/separator.js +0 -1
  151. package/dist/components/layout/sidebar.js +4 -1
  152. package/dist/components/layout/split-pane.d.ts +14 -1
  153. package/dist/components/layout/split-pane.js +26 -13
  154. package/dist/components/layout/topbar-item.d.ts +3 -0
  155. package/dist/components/layout/topbar-item.js +19 -5
  156. package/dist/components/layout/topbar.d.ts +1 -1
  157. package/dist/components/layout/topbar.js +27 -6
  158. package/dist/components/navigation/app-setting-picker.js +21 -2
  159. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  160. package/dist/components/navigation/app-setting-toggle.js +96 -0
  161. package/dist/components/navigation/dropdown-menu.d.ts +227 -18
  162. package/dist/components/navigation/dropdown-menu.js +402 -118
  163. package/dist/components/navigation/index.d.ts +2 -0
  164. package/dist/components/navigation/index.js +2 -0
  165. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  166. package/dist/components/navigation/pagination.d.ts +2 -2
  167. package/dist/components/navigation/pagination.js +155 -83
  168. package/dist/components/navigation/steps.d.ts +2 -2
  169. package/dist/components/navigation/steps.js +29 -4
  170. package/dist/components/navigation/tabs.d.ts +29 -16
  171. package/dist/components/navigation/tabs.js +374 -144
  172. package/dist/components/ui/accordion.d.ts +50 -5
  173. package/dist/components/ui/accordion.js +239 -33
  174. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  175. package/dist/components/ui/aspect-ratio.js +15 -13
  176. package/dist/components/ui/avatar.d.ts +29 -4
  177. package/dist/components/ui/avatar.js +111 -25
  178. package/dist/components/ui/hover-card.d.ts +42 -4
  179. package/dist/components/ui/hover-card.js +183 -27
  180. package/dist/components/ui/input-otp.d.ts +26 -28
  181. package/dist/components/ui/input-otp.js +50 -7
  182. package/dist/components/ui/label.js +0 -1
  183. package/dist/components/ui/password-input.d.ts +36 -2
  184. package/dist/components/ui/password-input.js +27 -7
  185. package/dist/components/ui/rating.d.ts +25 -0
  186. package/dist/components/ui/rating.js +67 -27
  187. package/dist/components/ui/segmented.d.ts +12 -3
  188. package/dist/components/ui/segmented.js +17 -2
  189. package/dist/components/ui/separator.d.ts +12 -2
  190. package/dist/components/ui/separator.js +30 -9
  191. package/dist/components/ui/tag-input.d.ts +45 -0
  192. package/dist/components/ui/tag-input.js +109 -27
  193. package/dist/components/ui/toggle-group.d.ts +50 -5
  194. package/dist/components/ui/toggle-group.js +79 -20
  195. package/dist/components/ui/toggle.d.ts +31 -5
  196. package/dist/components/ui/toggle.js +42 -3
  197. package/dist/form/form-context.d.ts +29 -0
  198. package/dist/form/form-context.js +44 -4
  199. package/dist/form/form-field-array.d.ts +22 -0
  200. package/dist/form/form-field-array.js +50 -0
  201. package/dist/form/form-field-control.d.ts +2 -1
  202. package/dist/form/form-field-control.js +116 -40
  203. package/dist/form/form-root.d.ts +2 -1
  204. package/dist/form/form-root.js +142 -23
  205. package/dist/form/index.d.ts +3 -1
  206. package/dist/form/index.js +12 -1
  207. package/dist/i18n/messages/en.json +64 -5
  208. package/dist/i18n/messages/ja.json +64 -5
  209. package/dist/i18n/messages/vi.json +64 -5
  210. package/dist/inertia/index.d.ts +20 -0
  211. package/dist/inertia/index.js +60 -1
  212. package/dist/lib/control-styles.d.ts +25 -3
  213. package/dist/lib/control-styles.js +9 -3
  214. package/dist/lib/datetime/picker-format.d.ts +8 -0
  215. package/dist/lib/datetime/picker-format.js +54 -0
  216. package/dist/lib/slot.d.ts +32 -0
  217. package/dist/lib/slot.js +22 -0
  218. package/dist/lib/variants.d.ts +22 -3
  219. package/dist/lib/variants.js +56 -1
  220. package/dist/props/components/app.prop.d.ts +25 -1
  221. package/dist/props/components/charts.prop.d.ts +21 -0
  222. package/dist/props/components/data-display.prop.d.ts +72 -4
  223. package/dist/props/components/data-entry.prop.d.ts +718 -46
  224. package/dist/props/components/form.prop.d.ts +142 -4
  225. package/dist/props/components/general.prop.d.ts +17 -1
  226. package/dist/props/components/index.d.ts +3 -3
  227. package/dist/props/components/layout.prop.d.ts +281 -11
  228. package/dist/props/components/navigation.prop.d.ts +114 -4
  229. package/dist/props/registry.d.ts +397 -11
  230. package/dist/props/registry.js +526 -11
  231. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  232. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  233. package/dist/props/vocabulary/index.d.ts +5 -5
  234. package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
  235. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  236. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  237. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  238. package/dist/styles/badge-layout.css +2 -1
  239. package/dist/styles/card-layout.css +26 -4
  240. package/dist/styles/chart-layout.css +15 -0
  241. package/dist/styles/control.css +657 -15
  242. package/dist/styles/core.css +5 -2
  243. package/dist/styles/data-display-layout.css +313 -6
  244. package/dist/styles/data-entry-layout.css +13 -0
  245. package/dist/styles/focus-ring.css +4 -0
  246. package/dist/styles/index.css +5 -2
  247. package/dist/styles/layout.css +327 -4
  248. package/dist/styles/navigation-layout.css +227 -0
  249. package/dist/styles/shell-layout.css +369 -13
  250. package/dist/styles/table-layout.css +95 -6
  251. package/dist/styles/text-layout.css +10 -4
  252. package/dist/tokens/base.css +2 -1
  253. package/dist/tokens/components/badge.css +1 -0
  254. package/dist/tokens/components/chart.css +6 -0
  255. package/dist/tokens/components/control.css +79 -2
  256. package/dist/tokens/components/data-display.css +20 -0
  257. package/dist/tokens/components/descriptions.css +11 -0
  258. package/dist/tokens/components/flex.css +8 -0
  259. package/dist/tokens/components/navigation.css +55 -0
  260. package/dist/tokens/components/shell.css +53 -3
  261. package/dist/tokens/components/table.css +14 -0
  262. package/dist/tokens/foundation.css +2 -0
  263. package/dist/tokens/semantic/layout.css +9 -0
  264. package/docs/COMPONENTS.md +9 -3
  265. package/docs/CONSUMER-RULES.md +13 -0
  266. package/docs/DESIGN-AUTHORITY.md +145 -83
  267. package/docs/DEVELOPMENT.md +4 -3
  268. package/docs/FORMS.md +151 -6
  269. package/docs/FRAME-COVERAGE-REPORT.md +32 -17
  270. package/docs/README.md +15 -15
  271. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  272. package/docs/TESTING.md +15 -6
  273. package/docs/WHAT-BELONGS-HERE.md +179 -0
  274. package/docs/charts/cjk-category-axis.tsx +81 -0
  275. package/docs/data-display/card/index.tsx +22 -0
  276. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  277. package/docs/data-display/data-table/index.tsx +23 -0
  278. package/docs/data-display/descriptions.tsx +41 -0
  279. package/docs/data-display/legend.tsx +145 -0
  280. package/docs/data-display/progress.tsx +32 -0
  281. package/docs/data-display/scroll-area.tsx +31 -25
  282. package/docs/data-display/table.tsx +104 -45
  283. package/docs/data-display/timeline.tsx +41 -0
  284. package/docs/data-entry/date-picker.tsx +85 -0
  285. package/docs/data-entry/date-range-picker.tsx +26 -0
  286. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  287. package/docs/data-entry/form.tsx +74 -4
  288. package/docs/data-entry/input-otp.tsx +24 -0
  289. package/docs/data-entry/input.tsx +46 -1
  290. package/docs/data-entry/month-range-picker.tsx +1 -1
  291. package/docs/data-entry/segmented.tsx +1 -1
  292. package/docs/data-entry/select.tsx +29 -2
  293. package/docs/data-entry/switch.tsx +41 -0
  294. package/docs/data-entry/textarea.tsx +38 -0
  295. package/docs/data-entry/time-picker.tsx +85 -1
  296. package/docs/data-entry/time-range-picker.tsx +55 -0
  297. package/docs/data-entry/transfer.tsx +17 -0
  298. package/docs/data-entry/upload.tsx +56 -12
  299. package/docs/feedback/sheet.tsx +1 -1
  300. package/docs/feedback/tooltip.tsx +1 -1
  301. package/docs/general/activity.tsx +2 -2
  302. package/docs/general/button/index.tsx +14 -1
  303. package/docs/general/typography.tsx +14 -1
  304. package/docs/layout/app-launcher.tsx +151 -0
  305. package/docs/layout/app-shell-arrangements.tsx +225 -0
  306. package/docs/layout/app-shell.tsx +11 -0
  307. package/docs/layout/aspect-ratio.tsx +1 -1
  308. package/docs/layout/flex.tsx +50 -0
  309. package/docs/layout/responsive-grid.tsx +21 -1
  310. package/docs/layout/topbar.tsx +5 -9
  311. package/docs/navigation/app-setting-picker.tsx +37 -1
  312. package/docs/navigation/app-setting-toggle.tsx +111 -0
  313. package/docs/navigation/breadcrumb.tsx +48 -0
  314. package/docs/navigation/dropdown-menu.tsx +21 -0
  315. package/docs/navigation/pagination.tsx +52 -0
  316. package/docs/navigation/steps.tsx +37 -0
  317. package/docs/navigation/tabs.tsx +97 -1
  318. package/docs/query/button-refetch.tsx +1 -0
  319. package/package.json +28 -8
  320. package/scripts/_agent-setup.mjs +182 -3
  321. package/scripts/consumer-rule.md +98 -0
  322. package/scripts/guinea-pig-skill.md +322 -0
  323. package/scripts/init-guinea-pig.mjs +84 -0
  324. package/scripts/postinstall.mjs +13 -2
  325. package/scripts/ui-audit.mjs +351 -37
  326. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
@@ -3,6 +3,7 @@ import { Text, Heading } from "./typography.js";
3
3
  import { Logo } from "./logo.js";
4
4
  import { Reveal } from "./reveal.js";
5
5
  import { Activity } from "./activity.js";
6
+ import { VisuallyHidden } from "./visually-hidden.js";
6
7
  export {
7
8
  Activity,
8
9
  Button,
@@ -10,5 +11,6 @@ export {
10
11
  Logo,
11
12
  Reveal,
12
13
  Text,
14
+ VisuallyHidden,
13
15
  buttonVariants
14
16
  };
@@ -45,6 +45,23 @@ export interface LogoProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "
45
45
  * readable wordmark sits beside it.
46
46
  */
47
47
  label?: string;
48
+ /**
49
+ * Mượn thẻ của con làm GỐC của logo thay vì dựng `<span>` — cách để cả cái logo trở thành một
50
+ * LIÊN KẾT (`<a>`, hay `<Link>` của router).
51
+ *
52
+ * Vì sao cần một prop chứ không phải bọc ngoài: `.ui-logo-lockup` là `display: inline-flex`, nên
53
+ * bọc nó trong một `<a>` thường (`display: inline`) đặt lockup lên một line box và phần descender
54
+ * của strut đội thêm vài px vào ô mark — logo bị nhích lên trong thanh trên. Consumer chỉ còn
55
+ * cách viết `className="flex"` lên thẻ `<a>`, thứ `ui-audit` chặn đúng theo luật
56
+ * `no-utility-layout` (đo ở godx-chat, 08/09/2026). Với `asChild`, chính thẻ của consumer MANG
57
+ * `.ui-logo-lockup`, nên không còn phần tử trung gian nào để canh.
58
+ *
59
+ * Đúng MỘT con, và ruột của nó bị bỏ qua: nội dung của logo vẫn do `glyph`/`mark`/`wordmark`
60
+ * quyết định.
61
+ */
62
+ asChild?: boolean;
63
+ /** Chỉ dùng cùng `asChild`: đúng một phần tử để đi mượn. */
64
+ children?: React.ReactNode;
48
65
  }
49
66
  /**
50
67
  * The band the glyph's ink actually occupies, as the (top edge, bottom edge) of the UNION of every
@@ -1,5 +1,6 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
+ import { Slot } from "../../lib/slot.js";
3
4
  import { cn } from "../../lib/utils.js";
4
5
  const X_HEIGHT_TOP = /^[acegmnopqrsuvwxyz]+$/;
5
6
  const LATIN_DESCENDER = /[gjpqy]/;
@@ -83,42 +84,47 @@ const Logo = React.forwardRef(
83
84
  tone = "primary",
84
85
  wordmark,
85
86
  label,
87
+ asChild,
88
+ children,
86
89
  className,
87
90
  ...props
88
91
  }, ref) => {
89
92
  const hasWordmark = wordmark !== void 0 && wordmark !== null && wordmark !== false;
90
93
  const identity = { "data-mark": mark, "data-size": size, "data-tone": tone };
94
+ const renderRoot = (rootProps, content) => {
95
+ if (!asChild) {
96
+ return /* @__PURE__ */ jsx("span", { ref, ...rootProps, children: content });
97
+ }
98
+ const borrowed = React.Children.only(children);
99
+ return /* @__PURE__ */ jsx(Slot, { ...rootProps, ref, children: React.cloneElement(borrowed, void 0, content) });
100
+ };
91
101
  if (hasWordmark) {
92
- return /* @__PURE__ */ jsxs(
93
- "span",
102
+ return renderRoot(
94
103
  {
95
- ref,
96
104
  "data-slot": "logo-lockup",
97
105
  ...identity,
98
106
  className: cn("ui-logo-lockup", className),
99
107
  role: label ? "img" : void 0,
100
108
  "aria-label": label,
101
- ...props,
102
- children: [
103
- /* @__PURE__ */ jsx("span", { "data-slot": "logo", ...identity, className: "ui-logo", "aria-hidden": "true", children: /* @__PURE__ */ jsx(MarkArtwork, { mark, glyph }) }),
104
- /* @__PURE__ */ jsx("span", { "data-slot": "logo-wordmark", "data-logotype": true, className: "ui-logo-wordmark", children: wordmark })
105
- ]
106
- }
109
+ ...props
110
+ },
111
+ /* @__PURE__ */ jsxs(Fragment, { children: [
112
+ /* @__PURE__ */ jsx("span", { "data-slot": "logo", ...identity, className: "ui-logo", "aria-hidden": "true", children: /* @__PURE__ */ jsx(MarkArtwork, { mark, glyph }) }),
113
+ /* @__PURE__ */ jsx("span", { "data-slot": "logo-wordmark", "data-logotype": true, className: "ui-logo-wordmark", children: wordmark })
114
+ ] })
107
115
  );
108
116
  }
109
- return /* @__PURE__ */ jsx(
110
- "span",
117
+ return renderRoot(
111
118
  {
112
- ref,
113
119
  "data-slot": "logo",
114
120
  ...identity,
115
121
  className: cn("ui-logo", className),
116
122
  role: label ? "img" : void 0,
117
123
  "aria-label": label,
118
124
  "aria-hidden": label ? void 0 : true,
119
- ...props,
120
- children: /* @__PURE__ */ jsx(MarkArtwork, { mark, glyph })
121
- }
125
+ ...props
126
+ },
127
+ /* @__PURE__ */ jsx(MarkArtwork, { mark, glyph })
122
128
  );
123
129
  }
124
130
  );
@@ -14,7 +14,10 @@ export declare const Text: React.ForwardRefExoticComponent<Omit<React.HTMLAttrib
14
14
  align?: import("../../props/index.js").TextAlignProp;
15
15
  truncate?: boolean;
16
16
  clamp?: number;
17
+ whitespace?: import("../../props/index.js").TextWhitespaceProp;
17
18
  tabular?: boolean;
19
+ decoration?: "none" | "underline" | "line-through";
20
+ chip?: boolean;
18
21
  mono?: boolean;
19
22
  htmlFor?: string;
20
23
  href?: string;
@@ -12,7 +12,10 @@ const Text = React.forwardRef(
12
12
  align,
13
13
  truncate,
14
14
  clamp,
15
+ whitespace,
15
16
  tabular,
17
+ decoration,
18
+ chip,
16
19
  mono,
17
20
  link,
18
21
  className,
@@ -21,6 +24,7 @@ const Text = React.forwardRef(
21
24
  ...props
22
25
  }, ref) => {
23
26
  const clampLines = typeof clamp === "number" && Number.isFinite(clamp) && clamp >= 1 ? Math.floor(clamp) : void 0;
27
+ const truncating = truncate === true && clampLines === void 0;
24
28
  if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
25
29
  if (clamp !== void 0 && clampLines === void 0) {
26
30
  console.warn(
@@ -32,6 +36,11 @@ const Text = React.forwardRef(
32
36
  "Text: `truncate` and `clamp` are mutually exclusive \u2014 `clamp` takes precedence; drop `truncate`."
33
37
  );
34
38
  }
39
+ if (whitespace === "pre-wrap" && truncating) {
40
+ console.warn(
41
+ 'Text: `truncate` and `whitespace="pre-wrap"` are mutually exclusive \u2014 `truncate` takes precedence (one line, one ellipsis); use `clamp` to keep preserved line breaks and still bound the height.'
42
+ );
43
+ }
35
44
  }
36
45
  const typography = {
37
46
  "data-slot": "text",
@@ -40,10 +49,15 @@ const Text = React.forwardRef(
40
49
  "data-link": link ? "" : void 0,
41
50
  "data-weight": weight,
42
51
  "data-align": align,
43
- "data-truncate": truncate && clampLines === void 0 ? "" : void 0,
52
+ "data-truncate": truncating ? "" : void 0,
44
53
  "data-clamp": clampLines !== void 0 ? "" : void 0,
54
+ // Inert default: `normal` is CSS's own behaviour, so it emits no attribute and there is no
55
+ // `[data-whitespace="normal"]` rule to lose a specificity argument with anything.
56
+ "data-whitespace": whitespace === "pre-wrap" && !truncating ? "pre-wrap" : void 0,
45
57
  style: clampLines !== void 0 ? { ...style, "--text-clamp": clampLines } : style,
46
58
  "data-tabular": tabular ? "" : void 0,
59
+ "data-decoration": decoration,
60
+ "data-chip": chip ? "" : void 0,
47
61
  "data-mono": mono ? "" : void 0,
48
62
  className: cn("ui-text", className),
49
63
  ...props
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ /** Accessible text without a visible layout box. */
3
+ export declare const VisuallyHidden: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLSpanElement> & React.RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,9 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../../lib/utils.js";
4
+ const VisuallyHidden = React.forwardRef(function VisuallyHidden2({ className, ...props }, ref) {
5
+ return /* @__PURE__ */ jsx("span", { ...props, ref, className: cn("sr-only", className) });
6
+ });
7
+ export {
8
+ VisuallyHidden
9
+ };
@@ -0,0 +1,34 @@
1
+ import * as React from "react";
2
+ import type { AppLauncherProp } from "../../props/components/layout.prop.js";
3
+ export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppLauncherProp as AppLauncherProps, } from "../../props/components/layout.prop.js";
4
+ /** Arbitrary `data-*` hooks — the one escape hatch this closed component keeps open. */
5
+ type DataAttributes = {
6
+ [key: `data-${string}`]: string | number | boolean | undefined;
7
+ };
8
+ /**
9
+ * AppLauncher — the nine-dot app grid in the topbar: the platform's standard way to change app.
10
+ *
11
+ * THE TRIGGER IS A `TopbarItem`, NOT A `Button`. A bar cell is as tall as the bar, its hover IS the
12
+ * bar's surface, and its focus mark is hosted inside it; a `Button variant="ghost"` in the same slot
13
+ * draws a `--control-height` pill floating in a taller strip, with its own hover fill and its own
14
+ * ring drawn around that pill. That was the 20.0.0 correction, and it is why nothing here emits a
15
+ * height: the cell stretches to whatever the bar's height happens to be (`--app-shell-bar-height`,
16
+ * `--topbar-height`, or the coarse-pointer override), so it names none of them.
17
+ *
18
+ * The panel is the SAME responsive contract as `OrgSwitcher`: a desktop popover above
19
+ * `--sheet-responsive-breakpoint-width` and a focus-trapped bottom Sheet at/below it, through the
20
+ * shared `useSheetResponsiveMode()` hook rather than a component-local media query.
21
+ *
22
+ * ## Related — two components this is repeatedly confused with
23
+ *
24
+ * - `ServiceLauncherCard` (data-display) is a launcher tile too, but a PAGE-SIZED one: status,
25
+ * hostname, plan, an action button, a reason it is locked. It belongs on a service-catalogue page,
26
+ * where choosing is a considered act. The tile here is bar-sized — mark plus name, the whole tile
27
+ * one link — because changing app is a reflex. Neither is built out of the other, and a grid of
28
+ * `ServiceLauncherCard`s inside a popover is the wrong component, not a smaller version of this.
29
+ * - `AppShellProp.navRail` says the SAME platform scope as a docked column. Pick ONE: the launcher
30
+ * for a platform with MANY apps where switching is occasional (Google Workspace), the rail for a
31
+ * single product where switching workspace is constant enough to be worth permanent screen width
32
+ * (Slack). Shipping both puts one scope in two places and makes neither authoritative.
33
+ */
34
+ export declare function AppLauncher({ apps, groups, labels, columns, linkComponent, loading, error, onRetry, responsive, open, onOpenChange, className, ...rest }: AppLauncherProp & Pick<React.ComponentPropsWithoutRef<"button">, "id"> & DataAttributes): React.JSX.Element;
@@ -0,0 +1,228 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Grip, Loader2, RotateCcw } from "lucide-react";
5
+ import { cn } from "../../lib/utils.js";
6
+ import { Popover, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
7
+ import {
8
+ Sheet,
9
+ SheetBody,
10
+ SheetContent,
11
+ SheetHeader,
12
+ SheetTrigger,
13
+ useSheetResponsiveMode
14
+ } from "../feedback/sheet.js";
15
+ import { Button } from "../general/button.js";
16
+ import { TopbarItem } from "./topbar-item.js";
17
+ function AppMark({ app }) {
18
+ return /* @__PURE__ */ jsx("span", { className: "ui-app-launcher-mark", "aria-hidden": "true", children: app.icon ?? app.name.trim().charAt(0).toUpperCase() });
19
+ }
20
+ function AppLauncherTile({
21
+ app,
22
+ linkComponent: Link,
23
+ externalHint,
24
+ close
25
+ }) {
26
+ const children = /* @__PURE__ */ jsxs(Fragment, { children: [
27
+ /* @__PURE__ */ jsx(AppMark, { app }),
28
+ /* @__PURE__ */ jsx("span", { className: "ui-app-launcher-name", children: app.name }),
29
+ app.external && externalHint != null ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: externalHint }) : null
30
+ ] });
31
+ const linkProps = {
32
+ href: app.href,
33
+ className: "ui-app-launcher-tile ui-focus-ring",
34
+ "data-active": app.current ? "true" : void 0,
35
+ "aria-current": app.current ? "page" : void 0,
36
+ onClick: close,
37
+ children
38
+ };
39
+ return /* @__PURE__ */ jsx("li", { className: "ui-app-launcher-cell", "data-app": app.id, children: app.external || Link == null ? /* @__PURE__ */ jsx(
40
+ "a",
41
+ {
42
+ ...linkProps,
43
+ target: app.external ? "_blank" : void 0,
44
+ rel: app.external ? "noreferrer noopener" : void 0
45
+ }
46
+ ) : /* @__PURE__ */ jsx(Link, { ...linkProps }) });
47
+ }
48
+ function AppLauncherGrid({
49
+ apps,
50
+ linkComponent,
51
+ externalHint,
52
+ close,
53
+ ...props
54
+ }) {
55
+ return /* @__PURE__ */ jsx("ul", { className: "ui-app-launcher-grid", ...props, children: apps.map((app) => /* @__PURE__ */ jsx(
56
+ AppLauncherTile,
57
+ {
58
+ app,
59
+ linkComponent,
60
+ externalHint,
61
+ close
62
+ },
63
+ app.id
64
+ )) });
65
+ }
66
+ function AppLauncherSection({
67
+ label,
68
+ apps,
69
+ linkComponent,
70
+ externalHint,
71
+ close
72
+ }) {
73
+ const labelId = React.useId();
74
+ return /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": labelId, className: "ui-app-launcher-group", children: [
75
+ /* @__PURE__ */ jsx("span", { id: labelId, className: "ui-app-launcher-group-label", children: label }),
76
+ /* @__PURE__ */ jsx(
77
+ AppLauncherGrid,
78
+ {
79
+ apps,
80
+ linkComponent,
81
+ externalHint,
82
+ close
83
+ }
84
+ )
85
+ ] });
86
+ }
87
+ function AppLauncherPanel({
88
+ apps,
89
+ groups,
90
+ labels,
91
+ columns,
92
+ linkComponent,
93
+ loading,
94
+ error,
95
+ onRetry,
96
+ close
97
+ }) {
98
+ if (loading) {
99
+ return /* @__PURE__ */ jsxs("div", { className: "ui-app-launcher-state", role: "status", children: [
100
+ /* @__PURE__ */ jsx(Loader2, { className: "ui-app-launcher-spinner", "aria-hidden": "true" }),
101
+ /* @__PURE__ */ jsx("span", { children: labels.loading })
102
+ ] });
103
+ }
104
+ if (error != null) {
105
+ return /* @__PURE__ */ jsxs("div", { className: "ui-app-launcher-state", role: "alert", children: [
106
+ /* @__PURE__ */ jsx("span", { children: error }),
107
+ onRetry != null ? /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onRetry, children: [
108
+ /* @__PURE__ */ jsx(RotateCcw, { "aria-hidden": "true" }),
109
+ labels.retry
110
+ ] }) : null
111
+ ] });
112
+ }
113
+ if (!apps.length && (groups ?? []).every((group) => !group.apps.length)) {
114
+ return /* @__PURE__ */ jsx("div", { className: "ui-app-launcher-state", role: "status", children: /* @__PURE__ */ jsx("span", { children: labels.empty }) });
115
+ }
116
+ return /* @__PURE__ */ jsxs(
117
+ "div",
118
+ {
119
+ className: "ui-app-launcher-panel",
120
+ style: columns == null ? void 0 : { "--app-launcher-columns": String(columns) },
121
+ children: [
122
+ apps.length ? /* @__PURE__ */ jsx(
123
+ AppLauncherGrid,
124
+ {
125
+ apps,
126
+ linkComponent,
127
+ externalHint: labels.externalHint,
128
+ close,
129
+ "aria-label": labels.title
130
+ }
131
+ ) : null,
132
+ groups?.map((group) => /* @__PURE__ */ jsx(
133
+ AppLauncherSection,
134
+ {
135
+ label: group.label,
136
+ apps: group.apps,
137
+ linkComponent,
138
+ externalHint: labels.externalHint,
139
+ close
140
+ },
141
+ group.label
142
+ ))
143
+ ]
144
+ }
145
+ );
146
+ }
147
+ function AppLauncher({
148
+ apps,
149
+ groups,
150
+ labels,
151
+ columns,
152
+ linkComponent,
153
+ loading = false,
154
+ error,
155
+ onRetry,
156
+ responsive = "auto",
157
+ open,
158
+ onOpenChange,
159
+ className,
160
+ ...rest
161
+ }) {
162
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
163
+ const controlled = open !== void 0;
164
+ const resolvedOpen = controlled ? open : uncontrolledOpen;
165
+ const setOpen = React.useCallback(
166
+ (nextOpen) => {
167
+ if (!controlled) {
168
+ setUncontrolledOpen(nextOpen);
169
+ }
170
+ onOpenChange?.(nextOpen);
171
+ },
172
+ [controlled, onOpenChange]
173
+ );
174
+ const compactViewport = useSheetResponsiveMode("auto") === "bottom";
175
+ const sheet = responsive === "sheet" || responsive === "auto" && compactViewport;
176
+ const close = React.useCallback(() => {
177
+ setOpen(false);
178
+ }, [setOpen]);
179
+ const trigger = /* @__PURE__ */ jsx(
180
+ TopbarItem,
181
+ {
182
+ className: cn("ui-app-launcher-trigger", className),
183
+ "aria-label": labels.trigger,
184
+ ...rest,
185
+ children: /* @__PURE__ */ jsx(Grip, { "aria-hidden": "true" })
186
+ }
187
+ );
188
+ const panel = /* @__PURE__ */ jsx(
189
+ AppLauncherPanel,
190
+ {
191
+ apps,
192
+ groups,
193
+ labels,
194
+ columns,
195
+ linkComponent,
196
+ loading,
197
+ error,
198
+ onRetry,
199
+ close
200
+ }
201
+ );
202
+ if (sheet) {
203
+ return /* @__PURE__ */ jsxs(Sheet, { open: resolvedOpen, onOpenChange: setOpen, children: [
204
+ /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: trigger }),
205
+ /* @__PURE__ */ jsxs(
206
+ SheetContent,
207
+ {
208
+ responsive: "bottom",
209
+ className: "ui-app-launcher-sheet",
210
+ style: {
211
+ "--sheet-bottom-max-height": "var(--app-launcher-sheet-max-height)"
212
+ },
213
+ children: [
214
+ /* @__PURE__ */ jsx(SheetHeader, { title: labels.title }),
215
+ /* @__PURE__ */ jsx(SheetBody, { children: panel })
216
+ ]
217
+ }
218
+ )
219
+ ] });
220
+ }
221
+ return /* @__PURE__ */ jsxs(Popover, { open: resolvedOpen, onOpenChange: setOpen, children: [
222
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: trigger }),
223
+ /* @__PURE__ */ jsx(PopoverContent, { align: "end", className: "ui-app-launcher-popover", "aria-label": labels.title, children: panel })
224
+ ] });
225
+ }
226
+ export {
227
+ AppLauncher
228
+ };
@@ -1,4 +1,6 @@
1
1
  import * as React from "react";
2
2
  import type { AppShellProp } from "../../props/components/layout.prop.js";
3
3
  export type { AppShellProp, AppShellProp as AppShellProps, } from "../../props/components/layout.prop.js";
4
- export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, mobileNav, mobileNavLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
4
+ /** Same rail boundary as shell-layout.css; SSR starts in docked mode. */
5
+ export declare function useAppShellNavigationMode(): "drawer" | "docked";
6
+ export declare function AppShell({ sidebar, topbar, topbarLeft, topbarRight, logo, breadcrumb, footer, children, sidebarCollapsed, responsiveNavigation, topbarSpan, navRail, navRailLabel, mobileNav, mobileNavLabel, mobileNavOpen, onMobileNavOpenChange, }: AppShellProp): React.JSX.Element;
@@ -1,10 +1,15 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Menu } from "lucide-react";
5
+ import { useMediaQuery } from "../../lib/hooks.js";
5
6
  import { useTranslation } from "../../i18n/use-translation.js";
6
7
  import { Button } from "../general/button.js";
7
8
  import { Sheet, SheetBody, SheetContent, SheetHeader, SheetTrigger } from "../feedback/sheet.js";
9
+ import { NavSurfaceProvider } from "./nav-surface.js";
10
+ function useAppShellNavigationMode() {
11
+ return useMediaQuery("(width <= 56.25rem)") ? "drawer" : "docked";
12
+ }
8
13
  function AppShell({
9
14
  sidebar,
10
15
  topbar,
@@ -17,32 +22,70 @@ function AppShell({
17
22
  sidebarCollapsed = false,
18
23
  responsiveNavigation = "drawer",
19
24
  topbarSpan = "content",
25
+ navRail,
26
+ navRailLabel,
20
27
  mobileNav,
21
28
  mobileNavLabel,
22
29
  mobileNavOpen,
23
30
  onMobileNavOpenChange
24
31
  }) {
25
32
  const { t } = useTranslation();
26
- const drawerNav = mobileNav !== void 0 ? mobileNav : sidebar;
27
- const hasDrawer = responsiveNavigation === "drawer" && drawerNav != null;
33
+ const navigationMode = useAppShellNavigationMode();
34
+ const hasSidebar = sidebar !== void 0 && sidebar !== null && sidebar !== false;
35
+ const drawerNav = mobileNav !== void 0 ? mobileNav : navRail !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
36
+ navRail,
37
+ sidebar
38
+ ] }) : sidebar;
39
+ const hasDrawer = responsiveNavigation === "drawer" && drawerNav != null && drawerNav !== false;
40
+ const railInDrawer = mobileNav === void 0 && navRail !== void 0;
28
41
  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
29
42
  const drawerOpen = mobileNavOpen ?? uncontrolledOpen;
30
43
  const setDrawerOpen = onMobileNavOpenChange ?? setUncontrolledOpen;
31
44
  const handleDrawerClick = (event) => {
32
45
  const target = event.target;
33
46
  const hit = target.closest("a[href], button, [role='menuitem']");
34
- if (hit && !hit.classList.contains("sb-nav-group-trigger")) {
47
+ if (!hit) {
48
+ return;
49
+ }
50
+ const opensSomething = hit.hasAttribute("aria-expanded") || hit.hasAttribute("aria-haspopup") || hit.classList.contains("sb-nav-group-trigger");
51
+ if (!opensSomething) {
35
52
  setDrawerOpen(false);
36
53
  }
37
54
  };
38
55
  const hasTopbarContent = topbar !== void 0 || topbarLeft !== void 0 || topbarRight !== void 0 || logo !== void 0;
39
- const resolvedTopbar = topbar !== void 0 ? topbar : /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
40
- logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
56
+ if (process.env.NODE_ENV !== "production" && topbar !== void 0) {
57
+ const ignored = [
58
+ topbarLeft !== void 0 && "topbarLeft",
59
+ topbarRight !== void 0 && "topbarRight"
60
+ ].filter(Boolean);
61
+ if (ignored.length > 0) {
62
+ console.warn(
63
+ `AppShell: \`topbar\` \u0111\u01B0\u1EE3c truy\u1EC1n, n\xEAn ${ignored.join(", ")} b\u1ECB b\u1ECF qua v\xE0 KH\xD4NG \u0111\u01B0\u1EE3c v\u1EBD. Ho\u1EB7c b\u1ECF \`topbar\` \u0111\u1EC3 AppShell t\u1EF1 d\u1EF1ng d\u1EA3i t\u1EEB c\xE1c khe kia, ho\u1EB7c \u0111\u1EB7t n\u1ED9i dung \u0111\xF3 v\xE0o trong ch\xEDnh \`topbar\`. (\`logo\` KH\xD4NG n\u1EB1m trong s\u1ED1 n\xE0y \u2014 n\xF3 lu\xF4n \u0111\u01B0\u1EE3c v\u1EBD.)`
64
+ );
65
+ }
66
+ }
67
+ const logoInRail = hasSidebar && logo !== void 0 && topbarSpan !== "full";
68
+ const resolvedTopbar = topbar !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
69
+ !logoInRail && logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
70
+ /* @__PURE__ */ jsx("div", { className: "app-topbar-custom", children: topbar })
71
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
72
+ !logoInRail && logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
41
73
  topbarLeft !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-left", children: topbarLeft }),
42
74
  /* @__PURE__ */ jsx("div", { className: "app-topbar-spacer" }),
43
75
  topbarRight !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-right", children: topbarRight })
44
76
  ] });
45
- const rail = /* @__PURE__ */ jsx("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: sidebar });
77
+ const rail = hasSidebar ? /* @__PURE__ */ jsxs("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: [
78
+ logoInRail && /* @__PURE__ */ jsx("div", { className: "app-sidebar-logo", children: logo }),
79
+ sidebar
80
+ ] }) : null;
81
+ const navRailRegion = navRail === void 0 ? null : /* @__PURE__ */ jsx(
82
+ "aside",
83
+ {
84
+ className: "app-nav-rail",
85
+ "aria-label": navRailLabel ?? t("layout.appShell.navRailLabel"),
86
+ children: navRail
87
+ }
88
+ );
46
89
  const bar = !hasTopbarContent && !hasDrawer ? null : /* @__PURE__ */ jsxs("header", { className: "app-topbar ui-scale-fixed", "aria-label": t("layout.appShell.headerLabel"), children: [
47
90
  hasDrawer && /* @__PURE__ */ jsxs(Sheet, { open: drawerOpen, onOpenChange: setDrawerOpen, children: [
48
91
  /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
@@ -71,7 +114,10 @@ function AppShell({
71
114
  {
72
115
  className: "app-mobile-nav-body px-[var(--app-shell-mobile-nav-inset)]",
73
116
  onClick: handleDrawerClick,
74
- children: drawerNav
117
+ children: railInDrawer ? /* @__PURE__ */ jsxs("div", { className: "app-mobile-nav-columns", children: [
118
+ /* @__PURE__ */ jsx("div", { className: "app-mobile-nav-rail", children: navRail }),
119
+ /* @__PURE__ */ jsx(NavSurfaceProvider, { surface: "drawer", children: /* @__PURE__ */ jsx("div", { className: "app-mobile-nav-sections", children: sidebar }) })
120
+ ] }) : /* @__PURE__ */ jsx(NavSurfaceProvider, { surface: "drawer", children: drawerNav })
75
121
  }
76
122
  )
77
123
  ]
@@ -84,13 +130,23 @@ function AppShell({
84
130
  "div",
85
131
  {
86
132
  className: "app-root",
87
- "data-collapsed": sidebarCollapsed ? "true" : void 0,
133
+ "data-collapsed": hasSidebar && sidebarCollapsed ? "true" : void 0,
134
+ "data-sidebar": hasSidebar ? void 0 : "none",
88
135
  "data-responsive-navigation": responsiveNavigation,
136
+ "data-navigation": navigationMode,
89
137
  "data-topbar": hasTopbarContent ? void 0 : "none",
90
138
  "data-topbar-span": topbarSpan === "full" ? "full" : void 0,
139
+ "data-nav-rail": navRail !== void 0 ? "" : void 0,
91
140
  children: [
92
- topbarSpan === "full" ? bar : rail,
93
- topbarSpan === "full" ? rail : bar,
141
+ topbarSpan === "full" ? /* @__PURE__ */ jsxs(Fragment, { children: [
142
+ bar,
143
+ navRailRegion,
144
+ rail
145
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
146
+ navRailRegion,
147
+ rail,
148
+ bar
149
+ ] }),
94
150
  /* @__PURE__ */ jsxs("main", { className: "app-main", "aria-label": t("layout.appShell.mainLabel"), tabIndex: 0, children: [
95
151
  breadcrumb !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-breadcrumb", children: breadcrumb }),
96
152
  children
@@ -101,5 +157,6 @@ function AppShell({
101
157
  );
102
158
  }
103
159
  export {
104
- AppShell
160
+ AppShell,
161
+ useAppShellNavigationMode
105
162
  };
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { AspectRatio } from "../ui/aspect-ratio.js";
3
2
  export {
4
3
  AspectRatio
@@ -1,4 +1,3 @@
1
- "use client";
2
1
  import { jsx } from "react/jsx-runtime";
3
2
  import { cn } from "../../lib/utils.js";
4
3
  import { Separator } from "../ui/separator.js";
@@ -1,9 +1,21 @@
1
1
  import type { ElementType } from "react";
2
- import type { BreadcrumbProp } from "../../props/vocabulary/navigation.prop.js";
2
+ import type { BreadcrumbItemRenderProp, BreadcrumbProp, BreadcrumbSeparatorProp } from "../../props/vocabulary/navigation.prop.js";
3
3
  export type BreadcrumbProps = {
4
4
  items: BreadcrumbProp;
5
5
  linkComponent?: ElementType;
6
6
  /** Override the `<nav>` landmark's accessible name. Defaults to a localized "Breadcrumb". */
7
7
  ariaLabel?: string;
8
+ /**
9
+ * Ant Design `separator`. Defaults to the chevron glyph. A string (`"/"`) or any node replaces
10
+ * it; `""` removes it. It is always `aria-hidden` — the trail's structure is carried by the
11
+ * `<ol>`/`<li>`, never by the glyph, so a screen reader never hears "slash" between segments.
12
+ */
13
+ separator?: BreadcrumbSeparatorProp;
14
+ /**
15
+ * Ant Design `itemRender`. Replaces the anchor/text of ONE segment while this component keeps
16
+ * owning the `<nav>`, the `<ol>`/`<li>`, the separators and `aria-current` — the parts that make
17
+ * the trail a landmark. Use it to hand the trail a router `<Link>` (Inertia, react-router).
18
+ */
19
+ itemRender?: BreadcrumbItemRenderProp;
8
20
  };
9
- export declare function Breadcrumb({ items, linkComponent: LinkComponent, ariaLabel, }: BreadcrumbProps): import("react").JSX.Element;
21
+ export declare function Breadcrumb({ items, linkComponent: LinkComponent, ariaLabel, separator, itemRender, }: BreadcrumbProps): import("react").JSX.Element;