@godxjp/ui 20.0.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 (250) 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 +12 -1
  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/data-table.d.ts +39 -4
  20. package/dist/components/data-display/data-table.js +802 -270
  21. package/dist/components/data-display/descriptions.d.ts +27 -6
  22. package/dist/components/data-display/descriptions.js +58 -17
  23. package/dist/components/data-display/index.d.ts +2 -0
  24. package/dist/components/data-display/index.js +2 -0
  25. package/dist/components/data-display/list-row.d.ts +10 -1
  26. package/dist/components/data-display/list-row.js +7 -1
  27. package/dist/components/data-display/popover.d.ts +2 -2
  28. package/dist/components/data-display/popover.js +61 -11
  29. package/dist/components/data-display/range-timeline.d.ts +38 -0
  30. package/dist/components/data-display/range-timeline.js +161 -0
  31. package/dist/components/data-display/scroll-area.js +13 -2
  32. package/dist/components/data-display/service-launcher-card.js +10 -10
  33. package/dist/components/data-display/table.d.ts +11 -3
  34. package/dist/components/data-display/table.js +48 -18
  35. package/dist/components/data-display/tree-list.js +4 -9
  36. package/dist/components/data-entry/calendar.d.ts +2 -2
  37. package/dist/components/data-entry/calendar.js +12 -1
  38. package/dist/components/data-entry/cascader.d.ts +1 -1
  39. package/dist/components/data-entry/cascader.js +188 -24
  40. package/dist/components/data-entry/color-picker.d.ts +1 -1
  41. package/dist/components/data-entry/color-picker.js +17 -5
  42. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  43. package/dist/components/data-entry/control-appearance.js +39 -0
  44. package/dist/components/data-entry/control-surface.d.ts +61 -0
  45. package/dist/components/data-entry/control-surface.js +39 -0
  46. package/dist/components/data-entry/date-picker.d.ts +1 -1
  47. package/dist/components/data-entry/date-picker.js +344 -113
  48. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  49. package/dist/components/data-entry/date-range-picker.js +278 -140
  50. package/dist/components/data-entry/form-field.d.ts +1 -1
  51. package/dist/components/data-entry/form-field.js +39 -4
  52. package/dist/components/data-entry/form.d.ts +4 -0
  53. package/dist/components/data-entry/form.js +4 -2
  54. package/dist/components/data-entry/index.d.ts +7 -3
  55. package/dist/components/data-entry/index.js +10 -1
  56. package/dist/components/data-entry/input-otp.d.ts +1 -1
  57. package/dist/components/data-entry/input.d.ts +12 -34
  58. package/dist/components/data-entry/input.js +92 -24
  59. package/dist/components/data-entry/month-picker.d.ts +1 -1
  60. package/dist/components/data-entry/month-picker.js +47 -10
  61. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  62. package/dist/components/data-entry/month-range-picker.js +51 -11
  63. package/dist/components/data-entry/number-input.d.ts +7 -0
  64. package/dist/components/data-entry/number-input.js +147 -98
  65. package/dist/components/data-entry/password-input.d.ts +1 -1
  66. package/dist/components/data-entry/radio.d.ts +1 -1
  67. package/dist/components/data-entry/radio.js +61 -13
  68. package/dist/components/data-entry/search-input.d.ts +1 -1
  69. package/dist/components/data-entry/search-input.js +16 -2
  70. package/dist/components/data-entry/search-select.d.ts +2 -2
  71. package/dist/components/data-entry/search-select.js +209 -78
  72. package/dist/components/data-entry/select.d.ts +22 -4
  73. package/dist/components/data-entry/select.js +215 -163
  74. package/dist/components/data-entry/slider.d.ts +9 -1
  75. package/dist/components/data-entry/slider.js +87 -9
  76. package/dist/components/data-entry/switch.d.ts +3 -0
  77. package/dist/components/data-entry/switch.js +29 -3
  78. package/dist/components/data-entry/textarea.d.ts +14 -56
  79. package/dist/components/data-entry/textarea.js +80 -33
  80. package/dist/components/data-entry/time-picker.d.ts +2 -2
  81. package/dist/components/data-entry/time-picker.js +333 -109
  82. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  83. package/dist/components/data-entry/time-range-picker.js +89 -0
  84. package/dist/components/data-entry/transfer.d.ts +1 -1
  85. package/dist/components/data-entry/transfer.js +86 -28
  86. package/dist/components/data-entry/tree-select.d.ts +1 -1
  87. package/dist/components/data-entry/tree-select.js +201 -113
  88. package/dist/components/data-entry/tree-utils.js +7 -14
  89. package/dist/components/data-entry/upload-files.d.ts +2 -0
  90. package/dist/components/data-entry/upload-files.js +31 -0
  91. package/dist/components/data-entry/upload-request.d.ts +4 -0
  92. package/dist/components/data-entry/upload-request.js +53 -0
  93. package/dist/components/data-entry/upload-types.d.ts +28 -0
  94. package/dist/components/data-entry/upload-types.js +2 -0
  95. package/dist/components/data-entry/upload.d.ts +2 -2
  96. package/dist/components/data-entry/upload.js +475 -115
  97. package/dist/components/feedback/dialog.js +16 -19
  98. package/dist/components/general/button.d.ts +1 -1
  99. package/dist/components/general/button.js +5 -1
  100. package/dist/components/general/index.d.ts +1 -0
  101. package/dist/components/general/index.js +2 -0
  102. package/dist/components/general/typography.d.ts +3 -0
  103. package/dist/components/general/typography.js +15 -1
  104. package/dist/components/general/visually-hidden.d.ts +3 -0
  105. package/dist/components/general/visually-hidden.js +9 -0
  106. package/dist/components/layout/app-launcher.d.ts +34 -0
  107. package/dist/components/layout/app-launcher.js +228 -0
  108. package/dist/components/layout/app-shell.d.ts +2 -0
  109. package/dist/components/layout/app-shell.js +20 -7
  110. package/dist/components/layout/breadcrumb.d.ts +14 -2
  111. package/dist/components/layout/breadcrumb.js +46 -4
  112. package/dist/components/layout/flex.d.ts +1 -1
  113. package/dist/components/layout/flex.js +23 -2
  114. package/dist/components/layout/index.d.ts +3 -0
  115. package/dist/components/layout/index.js +5 -1
  116. package/dist/components/layout/org-switcher.js +20 -1
  117. package/dist/components/layout/page-container.d.ts +1 -1
  118. package/dist/components/layout/page-container.js +5 -3
  119. package/dist/components/layout/responsive-grid.d.ts +16 -2
  120. package/dist/components/layout/responsive-grid.js +29 -2
  121. package/dist/components/layout/topbar-item.d.ts +3 -0
  122. package/dist/components/layout/topbar-item.js +18 -3
  123. package/dist/components/layout/topbar.d.ts +1 -1
  124. package/dist/components/layout/topbar.js +27 -6
  125. package/dist/components/navigation/dropdown-menu.d.ts +30 -2
  126. package/dist/components/navigation/dropdown-menu.js +68 -11
  127. package/dist/components/navigation/pagination.d.ts +2 -2
  128. package/dist/components/navigation/pagination.js +155 -83
  129. package/dist/components/navigation/steps.d.ts +2 -2
  130. package/dist/components/navigation/steps.js +29 -4
  131. package/dist/components/navigation/tabs.d.ts +5 -33
  132. package/dist/components/navigation/tabs.js +232 -64
  133. package/dist/components/ui/input-otp.d.ts +26 -28
  134. package/dist/components/ui/input-otp.js +50 -7
  135. package/dist/components/ui/password-input.d.ts +36 -2
  136. package/dist/components/ui/password-input.js +27 -7
  137. package/dist/components/ui/rating.d.ts +25 -0
  138. package/dist/components/ui/rating.js +67 -27
  139. package/dist/components/ui/segmented.d.ts +9 -0
  140. package/dist/components/ui/segmented.js +17 -2
  141. package/dist/components/ui/separator.d.ts +4 -0
  142. package/dist/components/ui/separator.js +13 -0
  143. package/dist/components/ui/tag-input.d.ts +45 -0
  144. package/dist/components/ui/tag-input.js +109 -27
  145. package/dist/form/form-context.d.ts +29 -0
  146. package/dist/form/form-context.js +44 -4
  147. package/dist/form/form-field-array.d.ts +22 -0
  148. package/dist/form/form-field-array.js +50 -0
  149. package/dist/form/form-field-control.d.ts +2 -1
  150. package/dist/form/form-field-control.js +116 -40
  151. package/dist/form/form-root.d.ts +2 -1
  152. package/dist/form/form-root.js +142 -23
  153. package/dist/form/index.d.ts +3 -1
  154. package/dist/form/index.js +12 -1
  155. package/dist/i18n/messages/en.json +56 -5
  156. package/dist/i18n/messages/ja.json +56 -5
  157. package/dist/i18n/messages/vi.json +56 -5
  158. package/dist/inertia/index.d.ts +20 -0
  159. package/dist/inertia/index.js +60 -1
  160. package/dist/lib/control-styles.d.ts +25 -3
  161. package/dist/lib/control-styles.js +9 -3
  162. package/dist/lib/datetime/picker-format.d.ts +8 -0
  163. package/dist/lib/datetime/picker-format.js +54 -0
  164. package/dist/props/components/charts.prop.d.ts +21 -0
  165. package/dist/props/components/data-display.prop.d.ts +55 -4
  166. package/dist/props/components/data-entry.prop.d.ts +687 -43
  167. package/dist/props/components/form.prop.d.ts +142 -4
  168. package/dist/props/components/general.prop.d.ts +17 -1
  169. package/dist/props/components/index.d.ts +2 -2
  170. package/dist/props/components/layout.prop.d.ts +163 -6
  171. package/dist/props/components/navigation.prop.d.ts +113 -3
  172. package/dist/props/registry.d.ts +376 -10
  173. package/dist/props/registry.js +493 -9
  174. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  175. package/dist/props/vocabulary/index.d.ts +4 -4
  176. package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
  177. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  178. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  179. package/dist/styles/badge-layout.css +2 -1
  180. package/dist/styles/card-layout.css +26 -4
  181. package/dist/styles/chart-layout.css +15 -0
  182. package/dist/styles/control.css +515 -14
  183. package/dist/styles/data-display-layout.css +241 -6
  184. package/dist/styles/data-entry-layout.css +13 -0
  185. package/dist/styles/layout.css +221 -4
  186. package/dist/styles/navigation-layout.css +227 -0
  187. package/dist/styles/shell-layout.css +229 -5
  188. package/dist/styles/table-layout.css +95 -6
  189. package/dist/styles/text-layout.css +5 -0
  190. package/dist/tokens/base.css +1 -0
  191. package/dist/tokens/components/badge.css +1 -0
  192. package/dist/tokens/components/chart.css +6 -0
  193. package/dist/tokens/components/control.css +79 -2
  194. package/dist/tokens/components/data-display.css +9 -0
  195. package/dist/tokens/components/descriptions.css +11 -0
  196. package/dist/tokens/components/flex.css +8 -0
  197. package/dist/tokens/components/navigation.css +55 -0
  198. package/dist/tokens/components/shell.css +50 -2
  199. package/dist/tokens/components/table.css +14 -0
  200. package/dist/tokens/semantic/layout.css +9 -0
  201. package/docs/CONSUMER-RULES.md +13 -0
  202. package/docs/DESIGN-AUTHORITY.md +43 -6
  203. package/docs/DEVELOPMENT.md +4 -3
  204. package/docs/FORMS.md +151 -6
  205. package/docs/FRAME-COVERAGE-REPORT.md +29 -16
  206. package/docs/README.md +1 -1
  207. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  208. package/docs/TESTING.md +15 -6
  209. package/docs/charts/cjk-category-axis.tsx +81 -0
  210. package/docs/data-display/card/index.tsx +22 -0
  211. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  212. package/docs/data-display/data-table/index.tsx +23 -0
  213. package/docs/data-display/descriptions.tsx +41 -0
  214. package/docs/data-display/scroll-area.tsx +31 -25
  215. package/docs/data-display/table.tsx +104 -45
  216. package/docs/data-display/timeline.tsx +41 -0
  217. package/docs/data-entry/date-picker.tsx +85 -0
  218. package/docs/data-entry/date-range-picker.tsx +26 -0
  219. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  220. package/docs/data-entry/form.tsx +74 -4
  221. package/docs/data-entry/input-otp.tsx +24 -0
  222. package/docs/data-entry/input.tsx +46 -1
  223. package/docs/data-entry/month-range-picker.tsx +1 -1
  224. package/docs/data-entry/select.tsx +27 -0
  225. package/docs/data-entry/switch.tsx +41 -0
  226. package/docs/data-entry/textarea.tsx +38 -0
  227. package/docs/data-entry/time-picker.tsx +85 -1
  228. package/docs/data-entry/time-range-picker.tsx +55 -0
  229. package/docs/data-entry/transfer.tsx +17 -0
  230. package/docs/data-entry/upload.tsx +56 -12
  231. package/docs/feedback/tooltip.tsx +1 -1
  232. package/docs/general/activity.tsx +2 -2
  233. package/docs/general/button/index.tsx +14 -1
  234. package/docs/general/typography.tsx +14 -1
  235. package/docs/layout/app-launcher.tsx +151 -0
  236. package/docs/layout/app-shell.tsx +11 -0
  237. package/docs/layout/flex.tsx +50 -0
  238. package/docs/layout/responsive-grid.tsx +21 -1
  239. package/docs/layout/topbar.tsx +5 -9
  240. package/docs/navigation/app-setting-picker.tsx +11 -0
  241. package/docs/navigation/breadcrumb.tsx +48 -0
  242. package/docs/navigation/dropdown-menu.tsx +21 -0
  243. package/docs/navigation/pagination.tsx +52 -0
  244. package/docs/navigation/steps.tsx +37 -0
  245. package/docs/navigation/tabs.tsx +97 -1
  246. package/docs/query/button-refetch.tsx +1 -0
  247. package/package.json +19 -2
  248. package/scripts/_agent-setup.mjs +19 -2
  249. package/scripts/init-guinea-pig.mjs +26 -4
  250. package/scripts/ui-audit.mjs +243 -30
@@ -12,7 +12,7 @@ import { buttonVariants } from "../general/button.js";
12
12
  import { useTranslation } from "../../i18n/use-translation.js";
13
13
  import { Button } from "../general/button.js";
14
14
  import { Input } from "../data-entry/input.js";
15
- import { Label } from "../data-entry/label.js";
15
+ import { FormField } from "../data-entry/form-field.js";
16
16
  function useOverlayOpenState({ open, defaultOpen, onOpenChange }) {
17
17
  const [uncontrolled, setUncontrolled] = React.useState(defaultOpen ?? false);
18
18
  const isOpen = open ?? uncontrolled;
@@ -407,24 +407,21 @@ function AlertDialog({
407
407
  /* @__PURE__ */ jsx(AlertDialogTitle, { children: title }),
408
408
  description ? /* @__PURE__ */ jsx(AlertDialogDescription, { children: description }) : null
409
409
  ] }),
410
- needsPhrase && /* @__PURE__ */ jsxs("div", { className: "ui-stack-xs", children: [
411
- /* @__PURE__ */ jsx(Label, { htmlFor: inputId, children: t("common.typeToConfirm", { phrase }) }),
412
- /* @__PURE__ */ jsx(
413
- Input,
414
- {
415
- id: inputId,
416
- value: typed,
417
- onChange: (e) => {
418
- setTyped(e.target.value);
419
- },
420
- autoComplete: "off",
421
- spellCheck: false,
422
- placeholder: phrase,
423
- "aria-required": "true",
424
- disabled: busy
425
- }
426
- )
427
- ] }),
410
+ needsPhrase && /* @__PURE__ */ jsx(FormField, { id: inputId, label: t("common.typeToConfirm", { phrase }), children: /* @__PURE__ */ jsx(
411
+ Input,
412
+ {
413
+ id: inputId,
414
+ value: typed,
415
+ onChange: (e) => {
416
+ setTyped(e.target.value);
417
+ },
418
+ autoComplete: "off",
419
+ spellCheck: false,
420
+ placeholder: phrase,
421
+ "aria-required": "true",
422
+ disabled: busy
423
+ }
424
+ ) }),
428
425
  stepUpFailed && /* @__PURE__ */ jsx("p", { id: stepErrorId, role: "alert", className: "ui-dialog-step-up-error", children: t("feedback.alert.stepUpFailed") }),
429
426
  /* @__PURE__ */ jsxs(DialogFooter, { children: [
430
427
  /* @__PURE__ */ jsx(DialogCancel, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", disabled: busy, children: resolvedCancel }) }),
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  declare const buttonVariants: (props?: ({
3
- variant?: "dashed" | "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
3
+ variant?: "bare" | "dashed" | "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
4
4
  size?: "default" | "icon" | "icon-lg" | "icon-sm" | "icon-xs" | "lg" | "md" | "sm" | "xs" | null | undefined;
5
5
  shape?: "default" | "pill" | "sharp" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
@@ -20,7 +20,11 @@ const buttonVariants = cva("ui-button", {
20
20
  dashed: "ui-button--dashed border border-dashed bg-background hover:bg-accent hover:text-accent-foreground",
21
21
  secondary: "ui-button--secondary bg-secondary text-secondary-foreground hover:bg-secondary/80",
22
22
  ghost: "ui-button--ghost hover:bg-accent hover:text-accent-foreground",
23
- link: "ui-button--link text-primary underline-offset-4 hover:underline"
23
+ link: "ui-button--link text-primary underline-offset-4 hover:underline",
24
+ // NO utilities, deliberately: `bare` is the absence of geometry, and every property it has
25
+ // to unset (the size tier's height and inline inset) is declared in the components layer.
26
+ // A utility here would be the only thing that could out-rank it. See `.ui-button--bare`.
27
+ bare: "ui-button--bare"
24
28
  },
25
29
  size: {
26
30
  default: "ui-button--default-size",
@@ -8,3 +8,4 @@ export { Reveal } from "./reveal.js";
8
8
  export type { RevealProp, RevealProps } from "./reveal.js";
9
9
  export { Activity } from "./activity.js";
10
10
  export type { ActivityProp, ActivityProps } from "./activity.js";
11
+ export { VisuallyHidden } from "./visually-hidden.js";
@@ -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
  };
@@ -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
+ /** Same rail boundary as shell-layout.css; SSR starts in docked mode. */
5
+ export declare function useAppShellNavigationMode(): "drawer" | "docked";
4
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;
@@ -2,10 +2,14 @@
2
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";
8
9
  import { NavSurfaceProvider } from "./nav-surface.js";
10
+ function useAppShellNavigationMode() {
11
+ return useMediaQuery("(width <= 56.25rem)") ? "drawer" : "docked";
12
+ }
9
13
  function AppShell({
10
14
  sidebar,
11
15
  topbar,
@@ -26,11 +30,13 @@ function AppShell({
26
30
  onMobileNavOpenChange
27
31
  }) {
28
32
  const { t } = useTranslation();
33
+ const navigationMode = useAppShellNavigationMode();
34
+ const hasSidebar = sidebar !== void 0 && sidebar !== null && sidebar !== false;
29
35
  const drawerNav = mobileNav !== void 0 ? mobileNav : navRail !== void 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
30
36
  navRail,
31
37
  sidebar
32
38
  ] }) : sidebar;
33
- const hasDrawer = responsiveNavigation === "drawer" && drawerNav != null;
39
+ const hasDrawer = responsiveNavigation === "drawer" && drawerNav != null && drawerNav !== false;
34
40
  const railInDrawer = mobileNav === void 0 && navRail !== void 0;
35
41
  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
36
42
  const drawerOpen = mobileNavOpen ?? uncontrolledOpen;
@@ -38,7 +44,11 @@ function AppShell({
38
44
  const handleDrawerClick = (event) => {
39
45
  const target = event.target;
40
46
  const hit = target.closest("a[href], button, [role='menuitem']");
41
- 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) {
42
52
  setDrawerOpen(false);
43
53
  }
44
54
  };
@@ -54,7 +64,7 @@ function AppShell({
54
64
  );
55
65
  }
56
66
  }
57
- const logoInRail = logo !== void 0 && topbarSpan !== "full";
67
+ const logoInRail = hasSidebar && logo !== void 0 && topbarSpan !== "full";
58
68
  const resolvedTopbar = topbar !== void 0 ? /* @__PURE__ */ jsxs("div", { className: "app-topbar-rail", children: [
59
69
  !logoInRail && logo !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-logo", children: logo }),
60
70
  /* @__PURE__ */ jsx("div", { className: "app-topbar-custom", children: topbar })
@@ -64,10 +74,10 @@ function AppShell({
64
74
  /* @__PURE__ */ jsx("div", { className: "app-topbar-spacer" }),
65
75
  topbarRight !== void 0 && /* @__PURE__ */ jsx("div", { className: "app-topbar-right", children: topbarRight })
66
76
  ] });
67
- const rail = /* @__PURE__ */ jsxs("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: [
77
+ const rail = hasSidebar ? /* @__PURE__ */ jsxs("aside", { className: "app-sidebar", "aria-label": t("layout.appShell.sidebarLabel"), children: [
68
78
  logoInRail && /* @__PURE__ */ jsx("div", { className: "app-sidebar-logo", children: logo }),
69
79
  sidebar
70
- ] });
80
+ ] }) : null;
71
81
  const navRailRegion = navRail === void 0 ? null : /* @__PURE__ */ jsx(
72
82
  "aside",
73
83
  {
@@ -120,8 +130,10 @@ function AppShell({
120
130
  "div",
121
131
  {
122
132
  className: "app-root",
123
- "data-collapsed": sidebarCollapsed ? "true" : void 0,
133
+ "data-collapsed": hasSidebar && sidebarCollapsed ? "true" : void 0,
134
+ "data-sidebar": hasSidebar ? void 0 : "none",
124
135
  "data-responsive-navigation": responsiveNavigation,
136
+ "data-navigation": navigationMode,
125
137
  "data-topbar": hasTopbarContent ? void 0 : "none",
126
138
  "data-topbar-span": topbarSpan === "full" ? "full" : void 0,
127
139
  "data-nav-rail": navRail !== void 0 ? "" : void 0,
@@ -145,5 +157,6 @@ function AppShell({
145
157
  );
146
158
  }
147
159
  export {
148
- AppShell
160
+ AppShell,
161
+ useAppShellNavigationMode
149
162
  };
@@ -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;
@@ -1,21 +1,63 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { ChevronRight } from "lucide-react";
3
+ import { ChevronDown, ChevronRight } from "lucide-react";
4
4
  import { useTranslation } from "../../i18n/use-translation.js";
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger
10
+ } from "../navigation/dropdown-menu.js";
5
11
  function Breadcrumb({
6
12
  items,
7
13
  linkComponent: LinkComponent = "a",
8
- ariaLabel
14
+ ariaLabel,
15
+ separator,
16
+ itemRender
9
17
  }) {
10
18
  const { t } = useTranslation();
19
+ const separatorNode = separator === void 0 ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) : separator;
11
20
  return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel ?? t("navigation.breadcrumb.ariaLabel"), className: "ui-breadcrumb", children: /* @__PURE__ */ jsx("ol", { className: "ui-breadcrumb-list", children: items.map((item, index) => {
12
21
  const isLast = index === items.length - 1;
13
22
  return /* @__PURE__ */ jsxs("li", { className: "ui-breadcrumb-item", children: [
14
- item.to && !isLast ? /* @__PURE__ */ jsx(LinkComponent, { href: item.to, to: item.to, className: "ui-breadcrumb-link", children: item.label }) : /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-current", "aria-current": isLast ? "page" : void 0, children: item.label }),
15
- !isLast ? /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true" }) : null
23
+ renderBreadcrumbSegment({ item, index, isLast, items, itemRender, LinkComponent }),
24
+ !isLast ? /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-separator", "aria-hidden": "true", children: separatorNode }) : null
16
25
  ] }, item.to ?? index);
17
26
  }) }) });
18
27
  }
28
+ function renderBreadcrumbSegment({
29
+ item,
30
+ index,
31
+ isLast,
32
+ items,
33
+ itemRender,
34
+ LinkComponent
35
+ }) {
36
+ if (itemRender) return itemRender(item, { index, isLast, items });
37
+ if (item.menu) {
38
+ const { items: menuItems, onSelect } = item.menu;
39
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
40
+ /* @__PURE__ */ jsxs(DropdownMenuTrigger, { className: "ui-breadcrumb-menu-trigger ui-focus-ring", children: [
41
+ item.label,
42
+ /* @__PURE__ */ jsx(ChevronDown, { className: "ui-breadcrumb-menu-icon", "aria-hidden": "true" })
43
+ ] }),
44
+ /* @__PURE__ */ jsx(DropdownMenuContent, { placement: "bottomStart", children: menuItems.map((entry) => /* @__PURE__ */ jsx(
45
+ DropdownMenuItem,
46
+ {
47
+ disabled: entry.disabled,
48
+ onSelect: onSelect ? () => onSelect(entry.value) : void 0,
49
+ asChild: entry.to !== void 0,
50
+ children: entry.to !== void 0 ? /* @__PURE__ */ jsx(LinkComponent, { href: entry.to, to: entry.to, children: entry.label }) : entry.label
51
+ },
52
+ entry.value
53
+ )) })
54
+ ] });
55
+ }
56
+ if (item.to && !isLast) {
57
+ return /* @__PURE__ */ jsx(LinkComponent, { href: item.to, to: item.to, className: "ui-breadcrumb-link", children: item.label });
58
+ }
59
+ return /* @__PURE__ */ jsx("span", { className: "ui-breadcrumb-current", "aria-current": isLast ? "page" : void 0, children: item.label });
60
+ }
19
61
  export {
20
62
  Breadcrumb
21
63
  };
@@ -1,3 +1,3 @@
1
1
  import type { FlexProp } from "../../props/components/layout.prop.js";
2
2
  export type { FlexAlignProp, FlexDirectionProp, FlexJustifyProp, FlexProp, FlexProp as FlexProps, } from "../../props/components/layout.prop.js";
3
- export declare function Flex({ as: Element, direction, gap, gapRaw, pad, padRaw, align, justify, wrap, hideBelow, hideFrom, fill, width, className, style, children, ...props }: FlexProp): import("react").JSX.Element;
3
+ export declare function Flex({ as: Element, direction, grow, shrink, surface, bleed, reveal, gap, gapRaw, pad, padRaw, align, justify, wrap, hideBelow, hideFrom, fill, width, className, style, children, ...props }: FlexProp): import("react").JSX.Element;