@godxjp/ui 20.0.0 → 20.2.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 (273) hide show
  1. package/README.md +8 -2
  2. package/dist/app/app-provider.js +37 -21
  3. package/dist/app/index.d.ts +2 -0
  4. package/dist/app/index.js +2 -0
  5. package/dist/app/storage.d.ts +17 -0
  6. package/dist/app/storage.js +28 -0
  7. package/dist/app/theme-axes.d.ts +2 -0
  8. package/dist/app/theme-axes.js +45 -0
  9. package/dist/components/charts/chart-cartesian.d.ts +2 -1
  10. package/dist/components/charts/chart-cartesian.js +52 -3
  11. package/dist/components/charts/chart-category-axis.d.ts +55 -0
  12. package/dist/components/charts/chart-category-axis.js +93 -0
  13. package/dist/components/charts/chart-frame.d.ts +10 -1
  14. package/dist/components/charts/chart-frame.js +19 -3
  15. package/dist/components/charts/compact-bar-trend.d.ts +1 -1
  16. package/dist/components/charts/compact-bar-trend.js +2 -0
  17. package/dist/components/charts/pie-chart.d.ts +1 -1
  18. package/dist/components/charts/pie-chart.js +12 -1
  19. package/dist/components/charts/recharts-peer.d.ts +49 -0
  20. package/dist/components/charts/recharts-peer.js +45 -0
  21. package/dist/components/data-display/card.d.ts +12 -1
  22. package/dist/components/data-display/card.js +22 -4
  23. package/dist/components/data-display/code-block.js +6 -2
  24. package/dist/components/data-display/data-table.d.ts +39 -4
  25. package/dist/components/data-display/data-table.js +802 -270
  26. package/dist/components/data-display/descriptions.d.ts +27 -6
  27. package/dist/components/data-display/descriptions.js +58 -17
  28. package/dist/components/data-display/index.d.ts +2 -0
  29. package/dist/components/data-display/index.js +2 -0
  30. package/dist/components/data-display/list-row.d.ts +10 -1
  31. package/dist/components/data-display/list-row.js +7 -1
  32. package/dist/components/data-display/popover.d.ts +9 -3
  33. package/dist/components/data-display/popover.js +65 -11
  34. package/dist/components/data-display/range-timeline.d.ts +38 -0
  35. package/dist/components/data-display/range-timeline.js +161 -0
  36. package/dist/components/data-display/scroll-area.js +13 -2
  37. package/dist/components/data-display/service-launcher-card.js +14 -12
  38. package/dist/components/data-display/table.d.ts +71 -3
  39. package/dist/components/data-display/table.js +56 -18
  40. package/dist/components/data-display/tree-list.js +4 -9
  41. package/dist/components/data-entry/calendar.d.ts +2 -2
  42. package/dist/components/data-entry/calendar.js +23 -3
  43. package/dist/components/data-entry/cascader.d.ts +1 -1
  44. package/dist/components/data-entry/cascader.js +188 -24
  45. package/dist/components/data-entry/color-picker.d.ts +1 -1
  46. package/dist/components/data-entry/color-picker.js +17 -5
  47. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  48. package/dist/components/data-entry/control-appearance.js +39 -0
  49. package/dist/components/data-entry/control-surface.d.ts +61 -0
  50. package/dist/components/data-entry/control-surface.js +39 -0
  51. package/dist/components/data-entry/date-picker.d.ts +1 -1
  52. package/dist/components/data-entry/date-picker.js +344 -113
  53. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  54. package/dist/components/data-entry/date-range-picker.js +278 -140
  55. package/dist/components/data-entry/form-field.d.ts +1 -1
  56. package/dist/components/data-entry/form-field.js +39 -4
  57. package/dist/components/data-entry/form.d.ts +4 -0
  58. package/dist/components/data-entry/form.js +4 -2
  59. package/dist/components/data-entry/index.d.ts +7 -3
  60. package/dist/components/data-entry/index.js +10 -1
  61. package/dist/components/data-entry/input-otp.d.ts +1 -1
  62. package/dist/components/data-entry/input.d.ts +12 -34
  63. package/dist/components/data-entry/input.js +92 -24
  64. package/dist/components/data-entry/month-picker.d.ts +1 -1
  65. package/dist/components/data-entry/month-picker.js +47 -10
  66. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  67. package/dist/components/data-entry/month-range-picker.js +51 -11
  68. package/dist/components/data-entry/number-input.d.ts +7 -0
  69. package/dist/components/data-entry/number-input.js +147 -98
  70. package/dist/components/data-entry/password-input.d.ts +1 -1
  71. package/dist/components/data-entry/radio.d.ts +1 -1
  72. package/dist/components/data-entry/radio.js +61 -13
  73. package/dist/components/data-entry/search-input.d.ts +1 -1
  74. package/dist/components/data-entry/search-input.js +16 -2
  75. package/dist/components/data-entry/search-select.d.ts +2 -2
  76. package/dist/components/data-entry/search-select.js +209 -78
  77. package/dist/components/data-entry/select.d.ts +22 -4
  78. package/dist/components/data-entry/select.js +215 -163
  79. package/dist/components/data-entry/slider.d.ts +9 -1
  80. package/dist/components/data-entry/slider.js +87 -9
  81. package/dist/components/data-entry/switch.d.ts +3 -0
  82. package/dist/components/data-entry/switch.js +29 -3
  83. package/dist/components/data-entry/textarea.d.ts +14 -56
  84. package/dist/components/data-entry/textarea.js +80 -33
  85. package/dist/components/data-entry/time-picker.d.ts +2 -2
  86. package/dist/components/data-entry/time-picker.js +333 -109
  87. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  88. package/dist/components/data-entry/time-range-picker.js +89 -0
  89. package/dist/components/data-entry/transfer.d.ts +1 -1
  90. package/dist/components/data-entry/transfer.js +86 -28
  91. package/dist/components/data-entry/tree-select.d.ts +1 -1
  92. package/dist/components/data-entry/tree-select.js +201 -113
  93. package/dist/components/data-entry/tree-utils.js +7 -14
  94. package/dist/components/data-entry/upload-files.d.ts +2 -0
  95. package/dist/components/data-entry/upload-files.js +31 -0
  96. package/dist/components/data-entry/upload-request.d.ts +4 -0
  97. package/dist/components/data-entry/upload-request.js +53 -0
  98. package/dist/components/data-entry/upload-types.d.ts +28 -0
  99. package/dist/components/data-entry/upload-types.js +2 -0
  100. package/dist/components/data-entry/upload.d.ts +2 -2
  101. package/dist/components/data-entry/upload.js +475 -115
  102. package/dist/components/feedback/dialog.js +19 -19
  103. package/dist/components/feedback/sheet.js +3 -0
  104. package/dist/components/feedback/tooltip.js +3 -0
  105. package/dist/components/general/button.d.ts +2 -1
  106. package/dist/components/general/button.js +7 -1
  107. package/dist/components/general/index.d.ts +1 -0
  108. package/dist/components/general/index.js +2 -0
  109. package/dist/components/general/typography.d.ts +3 -0
  110. package/dist/components/general/typography.js +15 -1
  111. package/dist/components/general/visually-hidden.d.ts +3 -0
  112. package/dist/components/general/visually-hidden.js +9 -0
  113. package/dist/components/layout/app-launcher.d.ts +34 -0
  114. package/dist/components/layout/app-launcher.js +261 -0
  115. package/dist/components/layout/app-shell.d.ts +3 -1
  116. package/dist/components/layout/app-shell.js +34 -14
  117. package/dist/components/layout/auth-shell.d.ts +1 -1
  118. package/dist/components/layout/auth-shell.js +2 -0
  119. package/dist/components/layout/breadcrumb.d.ts +14 -2
  120. package/dist/components/layout/breadcrumb.js +46 -4
  121. package/dist/components/layout/flex.d.ts +1 -1
  122. package/dist/components/layout/flex.js +23 -2
  123. package/dist/components/layout/index.d.ts +3 -0
  124. package/dist/components/layout/index.js +5 -1
  125. package/dist/components/layout/org-switcher.js +20 -1
  126. package/dist/components/layout/page-container.d.ts +1 -1
  127. package/dist/components/layout/page-container.js +5 -3
  128. package/dist/components/layout/responsive-grid.d.ts +16 -2
  129. package/dist/components/layout/responsive-grid.js +29 -2
  130. package/dist/components/layout/sidebar.js +2 -1
  131. package/dist/components/layout/topbar-item.d.ts +3 -0
  132. package/dist/components/layout/topbar-item.js +18 -3
  133. package/dist/components/layout/topbar.d.ts +1 -1
  134. package/dist/components/layout/topbar.js +27 -6
  135. package/dist/components/navigation/dropdown-menu.d.ts +30 -2
  136. package/dist/components/navigation/dropdown-menu.js +73 -11
  137. package/dist/components/navigation/pagination.d.ts +2 -2
  138. package/dist/components/navigation/pagination.js +155 -83
  139. package/dist/components/navigation/steps.d.ts +2 -2
  140. package/dist/components/navigation/steps.js +29 -4
  141. package/dist/components/navigation/tabs.d.ts +5 -33
  142. package/dist/components/navigation/tabs.js +232 -64
  143. package/dist/components/ui/hover-card.js +3 -0
  144. package/dist/components/ui/input-otp.d.ts +26 -28
  145. package/dist/components/ui/input-otp.js +50 -7
  146. package/dist/components/ui/password-input.d.ts +36 -2
  147. package/dist/components/ui/password-input.js +27 -7
  148. package/dist/components/ui/rating.d.ts +25 -0
  149. package/dist/components/ui/rating.js +67 -27
  150. package/dist/components/ui/segmented.d.ts +9 -0
  151. package/dist/components/ui/segmented.js +17 -2
  152. package/dist/components/ui/separator.d.ts +4 -0
  153. package/dist/components/ui/separator.js +13 -0
  154. package/dist/components/ui/tag-input.d.ts +45 -0
  155. package/dist/components/ui/tag-input.js +109 -27
  156. package/dist/form/form-context.d.ts +29 -0
  157. package/dist/form/form-context.js +44 -4
  158. package/dist/form/form-field-array.d.ts +22 -0
  159. package/dist/form/form-field-array.js +50 -0
  160. package/dist/form/form-field-control.d.ts +2 -1
  161. package/dist/form/form-field-control.js +116 -40
  162. package/dist/form/form-root.d.ts +2 -1
  163. package/dist/form/form-root.js +142 -23
  164. package/dist/form/index.d.ts +3 -1
  165. package/dist/form/index.js +12 -1
  166. package/dist/i18n/index.d.ts +1 -1
  167. package/dist/i18n/index.js +3 -1
  168. package/dist/i18n/messages/en.json +59 -6
  169. package/dist/i18n/messages/ja.json +59 -6
  170. package/dist/i18n/messages/vi.json +59 -6
  171. package/dist/i18n/translate.d.ts +19 -0
  172. package/dist/i18n/translate.js +24 -0
  173. package/dist/inertia/index.d.ts +20 -0
  174. package/dist/inertia/index.js +60 -1
  175. package/dist/lib/control-styles.d.ts +25 -3
  176. package/dist/lib/control-styles.js +9 -3
  177. package/dist/lib/datetime/picker-format.d.ts +8 -0
  178. package/dist/lib/datetime/picker-format.js +54 -0
  179. package/dist/lib/overlay-portal.d.ts +18 -0
  180. package/dist/lib/overlay-portal.js +17 -0
  181. package/dist/props/components/app.prop.d.ts +13 -2
  182. package/dist/props/components/charts.prop.d.ts +21 -0
  183. package/dist/props/components/data-display.prop.d.ts +55 -4
  184. package/dist/props/components/data-entry.prop.d.ts +687 -43
  185. package/dist/props/components/form.prop.d.ts +142 -4
  186. package/dist/props/components/general.prop.d.ts +30 -1
  187. package/dist/props/components/index.d.ts +2 -2
  188. package/dist/props/components/layout.prop.d.ts +255 -8
  189. package/dist/props/components/navigation.prop.d.ts +113 -3
  190. package/dist/props/registry.d.ts +376 -10
  191. package/dist/props/registry.js +493 -9
  192. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  193. package/dist/props/vocabulary/index.d.ts +4 -4
  194. package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
  195. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  196. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  197. package/dist/styles/badge-layout.css +2 -1
  198. package/dist/styles/card-layout.css +36 -5
  199. package/dist/styles/chart-layout.css +17 -1
  200. package/dist/styles/control.css +520 -14
  201. package/dist/styles/data-display-layout.css +248 -7
  202. package/dist/styles/data-entry-layout.css +13 -0
  203. package/dist/styles/layout.css +221 -4
  204. package/dist/styles/navigation-layout.css +230 -1
  205. package/dist/styles/shell-layout.css +690 -21
  206. package/dist/styles/table-layout.css +95 -6
  207. package/dist/styles/text-layout.css +5 -0
  208. package/dist/tokens/base.css +1 -0
  209. package/dist/tokens/components/badge.css +1 -0
  210. package/dist/tokens/components/chart.css +6 -0
  211. package/dist/tokens/components/control.css +81 -3
  212. package/dist/tokens/components/data-display.css +9 -0
  213. package/dist/tokens/components/descriptions.css +11 -0
  214. package/dist/tokens/components/flex.css +8 -0
  215. package/dist/tokens/components/navigation.css +55 -0
  216. package/dist/tokens/components/shell.css +100 -5
  217. package/dist/tokens/components/table.css +14 -0
  218. package/dist/tokens/foundation.css +2 -0
  219. package/dist/tokens/semantic/layout.css +9 -0
  220. package/docs/CONSUMER-RULES.md +13 -0
  221. package/docs/DESIGN-AUTHORITY.md +43 -6
  222. package/docs/DEVELOPMENT.md +4 -3
  223. package/docs/FORMS.md +151 -6
  224. package/docs/FRAME-COVERAGE-REPORT.md +29 -16
  225. package/docs/README.md +1 -1
  226. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  227. package/docs/TESTING.md +15 -6
  228. package/docs/charts/cjk-category-axis.tsx +81 -0
  229. package/docs/data-display/card/index.tsx +22 -0
  230. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  231. package/docs/data-display/data-table/index.tsx +23 -0
  232. package/docs/data-display/descriptions.tsx +41 -0
  233. package/docs/data-display/list-row.tsx +6 -6
  234. package/docs/data-display/scroll-area.tsx +31 -25
  235. package/docs/data-display/table.tsx +104 -45
  236. package/docs/data-display/timeline.tsx +41 -0
  237. package/docs/data-entry/date-picker.tsx +85 -0
  238. package/docs/data-entry/date-range-picker.tsx +26 -0
  239. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  240. package/docs/data-entry/form.tsx +74 -4
  241. package/docs/data-entry/input-otp.tsx +24 -0
  242. package/docs/data-entry/input.tsx +46 -1
  243. package/docs/data-entry/month-range-picker.tsx +1 -1
  244. package/docs/data-entry/select.tsx +27 -0
  245. package/docs/data-entry/switch.tsx +41 -0
  246. package/docs/data-entry/textarea.tsx +38 -0
  247. package/docs/data-entry/time-picker.tsx +85 -1
  248. package/docs/data-entry/time-range-picker.tsx +55 -0
  249. package/docs/data-entry/transfer.tsx +17 -0
  250. package/docs/data-entry/upload.tsx +56 -12
  251. package/docs/feedback/tooltip.tsx +1 -1
  252. package/docs/general/activity.tsx +2 -2
  253. package/docs/general/button/index.tsx +14 -1
  254. package/docs/general/typography.tsx +14 -1
  255. package/docs/layout/app-launcher.tsx +195 -0
  256. package/docs/layout/app-shell-arrangements.tsx +5 -5
  257. package/docs/layout/app-shell.tsx +11 -0
  258. package/docs/layout/flex.tsx +50 -0
  259. package/docs/layout/responsive-grid.tsx +21 -1
  260. package/docs/layout/topbar.tsx +5 -9
  261. package/docs/navigation/app-setting-picker.tsx +11 -0
  262. package/docs/navigation/breadcrumb.tsx +48 -0
  263. package/docs/navigation/dropdown-menu.tsx +21 -0
  264. package/docs/navigation/pagination.tsx +52 -0
  265. package/docs/navigation/steps.tsx +37 -0
  266. package/docs/navigation/tabs.tsx +97 -1
  267. package/docs/query/button-refetch.tsx +1 -0
  268. package/docs/showcase/settings-security-mfa.tsx +3 -3
  269. package/package.json +24 -4
  270. package/scripts/_agent-setup.mjs +76 -9
  271. package/scripts/init-guinea-pig.mjs +26 -4
  272. package/scripts/ui-audit.mjs +243 -30
  273. package/scripts/visual-audit.mjs +45 -7
@@ -1,8 +1,14 @@
1
1
  import * as React from "react";
2
2
  import type { DescriptionsLayoutProp } from "../../props/vocabulary/interaction.prop.js";
3
+ import type { DescriptionsColumnProp, DescriptionsItemsProp, DescriptionsSpanProp } from "../../props/vocabulary/data.prop.js";
3
4
  export type { DescriptionsLayoutProp };
4
5
  export interface DescriptionsProps {
5
- columns?: 1 | 2 | 3;
6
+ /**
7
+ * Column count. A plain `1 | 2 | 3` keeps this library's own responsive ladder exactly as it
8
+ * was; any other number, or antd's `{ sm, md, lg, xl }` responsive object, drives the
9
+ * token-published grid instead (antd `column`).
10
+ */
11
+ columns?: DescriptionsColumnProp;
6
12
  /** Label placement within each item. Default `vertical` (label over value). */
7
13
  layout?: DescriptionsLayoutProp;
8
14
  /**
@@ -10,19 +16,34 @@ export interface DescriptionsProps {
10
16
  * it there would read as a mistake, exactly like `Form`'s own contract.
11
17
  */
12
18
  labelAlign?: "start" | "end";
19
+ /**
20
+ * Draw the grid as a bordered table (antd `bordered`): an outer frame, a rule between every
21
+ * cell, and a shaded label cell. Colour and rhythm come from the `--descriptions-*` tokens.
22
+ */
23
+ bordered?: boolean;
24
+ /**
25
+ * Declarative items (antd `items`) — an alternative to composing `Descriptions.Item` children.
26
+ * Both work; `items` renders first, then any children after it.
27
+ */
28
+ items?: DescriptionsItemsProp;
13
29
  className?: string;
14
- children: React.ReactNode;
30
+ children?: React.ReactNode;
15
31
  }
16
- export declare function Descriptions({ columns, layout, labelAlign, className, children, }: DescriptionsProps): React.JSX.Element;
32
+ export declare function Descriptions({ columns, layout, labelAlign, bordered, items, className, children, }: DescriptionsProps): React.JSX.Element;
17
33
  export declare namespace Descriptions {
18
- var Item: ({ label, mono, span, className, children, }: DescriptionsItemProps) => React.JSX.Element;
34
+ export { DescriptionsItem as Item };
19
35
  }
20
36
  export interface DescriptionsItemProps {
21
37
  label: React.ReactNode;
22
38
  /** Use mono spacing for IDs, paths, JSON. */
23
39
  mono?: boolean;
24
- /** Span full row(s) when value is long. */
25
- span?: 2 | 3;
40
+ /**
41
+ * Span full row(s) when the value is long. `2` / `3` keep the ladder they have always painted;
42
+ * `"filled"` takes the whole remaining row (antd), and a responsive `{ sm, md, lg, xl }` object
43
+ * spans a different number of columns per step.
44
+ */
45
+ span?: DescriptionsSpanProp;
26
46
  className?: string;
27
47
  children: React.ReactNode;
28
48
  }
49
+ declare function DescriptionsItem({ label, mono, span, className, children }: DescriptionsItemProps): React.JSX.Element;
@@ -4,45 +4,85 @@ import * as React from "react";
4
4
  import { cn } from "../../lib/utils.js";
5
5
  const DescriptionsLayoutContext = React.createContext({
6
6
  layout: "vertical",
7
- labelAlign: "start"
7
+ labelAlign: "start",
8
+ bordered: false
8
9
  });
10
+ const BREAKPOINT_LADDER = ["sm", "md", "lg", "xl"];
11
+ function responsiveVars(name, base, steps) {
12
+ const vars = { [`${name}-base`]: base };
13
+ for (const step of BREAKPOINT_LADDER) {
14
+ const value = steps[step];
15
+ if (value !== void 0) vars[`${name}-${step}`] = value;
16
+ }
17
+ return vars;
18
+ }
19
+ const LEGACY_COLUMN_CLASS = {
20
+ 1: "grid-cols-1",
21
+ 2: "grid-cols-1 sm:grid-cols-2",
22
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3"
23
+ };
9
24
  function Descriptions({
10
25
  columns = 2,
11
26
  layout = "vertical",
12
27
  labelAlign = "start",
28
+ bordered = false,
29
+ items,
13
30
  className,
14
31
  children
15
32
  }) {
16
- const colsClass = columns === 1 ? "grid-cols-1" : columns === 3 ? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3" : "grid-cols-1 sm:grid-cols-2";
17
- const context = React.useMemo(() => ({ layout, labelAlign }), [layout, labelAlign]);
18
- return /* @__PURE__ */ jsx(DescriptionsLayoutContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
33
+ const legacyColumns = typeof columns === "number" ? LEGACY_COLUMN_CLASS[columns] : void 0;
34
+ const responsiveColumns = legacyColumns === void 0 ? typeof columns === "number" ? { sm: Math.min(columns, 2), lg: columns } : columns : void 0;
35
+ const context = React.useMemo(
36
+ () => ({ layout, labelAlign, bordered }),
37
+ [layout, labelAlign, bordered]
38
+ );
39
+ return /* @__PURE__ */ jsx(DescriptionsLayoutContext.Provider, { value: context, children: /* @__PURE__ */ jsxs(
19
40
  "dl",
20
41
  {
21
42
  "data-slot": "descriptions",
22
- "data-columns": columns,
43
+ "data-columns": typeof columns === "number" ? columns : void 0,
44
+ "data-columns-responsive": responsiveColumns ? "" : void 0,
45
+ "data-bordered": bordered ? "" : void 0,
46
+ style: responsiveColumns ? responsiveVars("--descriptions-column-count", 1, responsiveColumns) : void 0,
23
47
  className: cn(
24
48
  "grid gap-x-[var(--descriptions-column-gap)] gap-y-[var(--descriptions-row-gap)]",
25
- colsClass,
49
+ legacyColumns,
26
50
  className
27
51
  ),
28
- children
52
+ children: [
53
+ items?.map((item, index) => /* @__PURE__ */ jsx(
54
+ DescriptionsItem,
55
+ {
56
+ label: item.label,
57
+ mono: item.mono,
58
+ span: item.span,
59
+ className: item.className,
60
+ children: item.children ?? item.value
61
+ },
62
+ item.key ?? index
63
+ )),
64
+ children
65
+ ]
29
66
  }
30
67
  ) });
31
68
  }
32
- Descriptions.Item = function DescriptionsItem({
33
- label,
34
- mono,
35
- span,
36
- className,
37
- children
38
- }) {
69
+ const LEGACY_SPAN_CLASS = {
70
+ 2: "sm:col-span-2",
71
+ 3: "sm:col-span-2 lg:col-span-3"
72
+ };
73
+ function DescriptionsItem({ label, mono, span, className, children }) {
39
74
  const { layout, labelAlign } = React.useContext(DescriptionsLayoutContext);
40
- const spanClass = span === 2 ? "sm:col-span-2" : span === 3 ? "sm:col-span-2 lg:col-span-3" : "";
75
+ const legacySpan = typeof span === "number" ? LEGACY_SPAN_CLASS[span] : void 0;
76
+ const responsiveSpan = span !== void 0 && span !== "filled" && legacySpan === void 0 ? typeof span === "number" ? { sm: span } : span : void 0;
41
77
  const endAlignedLabel = layout === "horizontal" && labelAlign === "end";
42
78
  return /* @__PURE__ */ jsxs(
43
79
  "div",
44
80
  {
45
81
  "data-slot": "descriptions-item",
82
+ "data-layout": layout,
83
+ "data-span": span === "filled" ? "filled" : void 0,
84
+ "data-span-responsive": responsiveSpan ? "" : void 0,
85
+ style: responsiveSpan ? responsiveVars("--descriptions-item-span", 1, responsiveSpan) : void 0,
46
86
  className: cn(
47
87
  layout === "horizontal" ? (
48
88
  // Label beside value — a token-aligned label column so the values line up. The
@@ -54,7 +94,7 @@ Descriptions.Item = function DescriptionsItem({
54
94
  // FormField / Form so the label→value gap is consistent everywhere.
55
95
  "grid gap-[var(--field-label-gap)]"
56
96
  ),
57
- spanClass,
97
+ legacySpan,
58
98
  className
59
99
  ),
60
100
  children: [
@@ -86,7 +126,8 @@ Descriptions.Item = function DescriptionsItem({
86
126
  ]
87
127
  }
88
128
  );
89
- };
129
+ }
130
+ Descriptions.Item = DescriptionsItem;
90
131
  export {
91
132
  Descriptions
92
133
  };
@@ -41,3 +41,5 @@ export { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious
41
41
  export type { CarouselApi } from "./carousel.js";
42
42
  export { PermissionMatrix } from "./permission-matrix.js";
43
43
  export type { PermissionMatrixGrantsProp, PermissionMatrixPermissionProp, PermissionMatrixProp, PermissionMatrixProps, PermissionMatrixRoleProp, } from "./permission-matrix.js";
44
+ export { RangeTimeline } from "./range-timeline.js";
45
+ export type { RangeTimelineProps, RangeTimelineRow } from "./range-timeline.js";
@@ -54,6 +54,7 @@ import {
54
54
  useCarousel
55
55
  } from "./carousel.js";
56
56
  import { PermissionMatrix } from "./permission-matrix.js";
57
+ import { RangeTimeline } from "./range-timeline.js";
57
58
  export {
58
59
  Accordion,
59
60
  AccordionContent,
@@ -102,6 +103,7 @@ export {
102
103
  Progress,
103
104
  Prose,
104
105
  QrCode,
106
+ RangeTimeline,
105
107
  ScrollArea,
106
108
  ScrollBar,
107
109
  ServiceCatalogCta,
@@ -13,7 +13,16 @@ export type ListRowDensity = ListRowDensityProp;
13
13
  * justify-between border-b …">`.
14
14
  */
15
15
  export interface ListRowProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
16
- /** Render element — `div` (default) or `li` when the parent is a `<ul>`/`<ol>`. */
16
+ /**
17
+ * Render element — `div` (default) or `li` when the parent is a `<ul>`/`<ol>`.
18
+ *
19
+ * With `asChild`, the child owns the row element, so `as` steps out and becomes the
20
+ * LIST ITEM around it: `<li data-slot="list-row-item"><a data-slot="list-row">`. That is
21
+ * the only reading under which both props can hold at once, and it is the shape a list
22
+ * of links needs — the alternative, wrapping the row yourself, moves every row into a
23
+ * wrapper of its own and the row-to-row divider (keyed on `:not(:last-child)` among
24
+ * siblings) stops matching entirely.
25
+ */
17
26
  as?: "div" | "li";
18
27
  /** Use the supplied link as the entire row. Do not nest interactive trailing controls. */
19
28
  asChild?: boolean;
@@ -22,6 +22,7 @@ const ListRow = React.forwardRef(
22
22
  ...props
23
23
  }, ref) => {
24
24
  const { t } = useTranslation();
25
+ const item = asChild && as !== "div" ? as : null;
25
26
  const Comp = asChild ? Slot : as;
26
27
  const truncate = overflow !== "wrap";
27
28
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -33,7 +34,7 @@ const ListRow = React.forwardRef(
33
34
  ] }),
34
35
  trailing != null ? /* @__PURE__ */ jsx("span", { "data-slot": "list-row-trailing", children: trailing }) : null
35
36
  ] });
36
- return /* @__PURE__ */ jsx(
37
+ const row = /* @__PURE__ */ jsx(
37
38
  Comp,
38
39
  {
39
40
  ref,
@@ -47,6 +48,11 @@ const ListRow = React.forwardRef(
47
48
  children: asChild && React.isValidElement(children) ? React.cloneElement(children, void 0, content) : content
48
49
  }
49
50
  );
51
+ if (item === null) {
52
+ return row;
53
+ }
54
+ const Item = item;
55
+ return /* @__PURE__ */ jsx(Item, { "data-slot": "list-row-item", children: row });
50
56
  }
51
57
  );
52
58
  ListRow.displayName = "ListRow";
@@ -34,6 +34,12 @@ type PopoverContentFlush = {
34
34
  flush?: FlushProp;
35
35
  };
36
36
  interface PopoverContentProps extends React.ComponentPropsWithRef<"div">, PopoverContentFlush {
37
+ /**
38
+ * Render THIS panel somewhere other than the default. Almost always unnecessary: mounting the
39
+ * whole tree in a shadow root is what `OverlayPortalProvider` is for, and it moves every overlay
40
+ * at once. Reach for this only to place one panel differently from the rest.
41
+ */
42
+ portalContainer?: Element;
37
43
  /** Cạnh của trigger mà panel bám vào. */
38
44
  side?: Side;
39
45
  /** Canh panel theo cạnh của trigger. */
@@ -67,8 +73,8 @@ interface PopoverContentProps extends React.ComponentPropsWithRef<"div">, Popove
67
73
  */
68
74
  onCloseAutoFocus?: (event: Event) => void;
69
75
  }
70
- export declare function PopoverContent({ className, style, children, ref, flush, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, sticky: _sticky, hideWhenDetached: _hideWhenDetached, forceMount: _forceMount, onOpenAutoFocus, onCloseAutoFocus, ...props }: PopoverContentProps): React.JSX.Element;
76
+ export declare function PopoverContent({ className, style, children, ref, flush, side, align, sideOffset, alignOffset, avoidCollisions, collisionPadding, sticky: _sticky, hideWhenDetached: _hideWhenDetached, forceMount: _forceMount, onOpenAutoFocus, onCloseAutoFocus, portalContainer, ...props }: PopoverContentProps): React.JSX.Element;
71
77
  export declare const PopoverHeader: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
72
- export declare const PopoverTitle: ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
73
- export declare const PopoverDescription: ({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => React.JSX.Element;
78
+ export declare const PopoverTitle: ({ className, id, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
79
+ export declare const PopoverDescription: ({ className, id, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => React.JSX.Element;
74
80
  export {};
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
+ import { useOverlayPortalContainer } from "../../lib/overlay-portal.js";
3
4
  import * as React from "react";
4
5
  import { chain, mergeRefs } from "@react-aria/utils";
5
6
  import { Popover as AriaPopover } from "react-aria-components";
@@ -48,6 +49,11 @@ function Popover({
48
49
  const triggerRef = React.useRef(null);
49
50
  const anchorRef = React.useRef(null);
50
51
  const contentId = React.useId();
52
+ const titleId = React.useId();
53
+ const descriptionId = React.useId();
54
+ const triggerId = React.useId();
55
+ const [hasTitle, registerTitle] = React.useState(false);
56
+ const [hasDescription, registerDescription] = React.useState(false);
51
57
  const isOpen = open ?? uncontrolledOpen;
52
58
  const setOpen = React.useCallback(
53
59
  (next) => {
@@ -67,9 +73,27 @@ function Popover({
67
73
  triggerRef,
68
74
  anchorRef,
69
75
  anchored,
70
- setAnchored
76
+ setAnchored,
77
+ titleId,
78
+ descriptionId,
79
+ hasTitle,
80
+ hasDescription,
81
+ registerTitle,
82
+ registerDescription,
83
+ triggerId
71
84
  }),
72
- [isOpen, setOpen, contentId, modal, anchored]
85
+ [
86
+ isOpen,
87
+ setOpen,
88
+ contentId,
89
+ modal,
90
+ anchored,
91
+ titleId,
92
+ descriptionId,
93
+ hasTitle,
94
+ hasDescription,
95
+ triggerId
96
+ ]
73
97
  );
74
98
  return /* @__PURE__ */ jsx(PopoverRootContext.Provider, { value, children });
75
99
  }
@@ -83,6 +107,7 @@ function PopoverTrigger({ asChild, onClick, ref, ...props }) {
83
107
  "data-slot": "popover-trigger",
84
108
  "aria-haspopup": "dialog",
85
109
  "aria-expanded": root.open,
110
+ id: props.id ?? root.triggerId,
86
111
  "aria-controls": root.open ? root.contentId : void 0,
87
112
  "data-state": root.open ? "open" : "closed",
88
113
  ...props,
@@ -118,6 +143,7 @@ function PopoverContent({
118
143
  forceMount: _forceMount,
119
144
  onOpenAutoFocus,
120
145
  onCloseAutoFocus,
146
+ portalContainer,
121
147
  ...props
122
148
  }) {
123
149
  const root = usePopoverRoot("PopoverContent");
@@ -152,9 +178,11 @@ function PopoverContent({
152
178
  document.addEventListener("pointerdown", onPointerDown);
153
179
  return () => document.removeEventListener("pointerdown", onPointerDown);
154
180
  }, [open, setOpen, triggerRef]);
181
+ const overlayPortalContainer = useOverlayPortalContainer(portalContainer);
155
182
  return /* @__PURE__ */ jsx(
156
183
  AriaPopover,
157
184
  {
185
+ UNSTABLE_portalContainer: overlayPortalContainer,
158
186
  isOpen: root.open,
159
187
  onOpenChange: root.setOpen,
160
188
  isNonModal: root.isNonModal,
@@ -186,6 +214,8 @@ function PopoverContent({
186
214
  "data-state": isExiting ? "closed" : "open",
187
215
  "data-flush": flush ? "" : void 0,
188
216
  ...props,
217
+ "aria-labelledby": props["aria-labelledby"] ?? (props["aria-label"] ? void 0 : root.hasTitle ? root.titleId : root.triggerId),
218
+ "aria-describedby": props["aria-describedby"] ?? (root.hasDescription ? root.descriptionId : void 0),
189
219
  ref: mergeRefs(ref, racRef, contentRef),
190
220
  className: cn(
191
221
  "ui-popover-content origin-[var(--radix-popover-content-transform-origin)]",
@@ -213,18 +243,42 @@ function PopoverContent({
213
243
  );
214
244
  }
215
245
  const PopoverHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { "data-slot": "popover-header", className: cn("ui-popover-header", className), ...props });
216
- const PopoverTitle = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { "data-slot": "popover-title", className: cn("font-medium", className), ...props });
246
+ const PopoverTitle = ({ className, id, ...props }) => {
247
+ const root = usePopoverRoot("PopoverTitle");
248
+ React.useEffect(() => {
249
+ root.registerTitle(true);
250
+ return () => root.registerTitle(false);
251
+ }, [root]);
252
+ return /* @__PURE__ */ jsx(
253
+ "div",
254
+ {
255
+ "data-slot": "popover-title",
256
+ id: id ?? root.titleId,
257
+ className: cn("font-medium", className),
258
+ ...props
259
+ }
260
+ );
261
+ };
217
262
  const PopoverDescription = ({
218
263
  className,
264
+ id,
219
265
  ...props
220
- }) => /* @__PURE__ */ jsx(
221
- "p",
222
- {
223
- "data-slot": "popover-description",
224
- className: cn("text-muted-foreground", className),
225
- ...props
226
- }
227
- );
266
+ }) => {
267
+ const root = usePopoverRoot("PopoverDescription");
268
+ React.useEffect(() => {
269
+ root.registerDescription(true);
270
+ return () => root.registerDescription(false);
271
+ }, [root]);
272
+ return /* @__PURE__ */ jsx(
273
+ "p",
274
+ {
275
+ "data-slot": "popover-description",
276
+ id: id ?? root.descriptionId,
277
+ className: cn("text-muted-foreground", className),
278
+ ...props
279
+ }
280
+ );
281
+ };
228
282
  export {
229
283
  Popover,
230
284
  PopoverAnchor,
@@ -0,0 +1,38 @@
1
+ import * as React from "react";
2
+ export type RangeTimelineRow = {
3
+ id: string;
4
+ label: React.ReactNode;
5
+ start: number;
6
+ end: number;
7
+ startLabel: string;
8
+ endLabel: string;
9
+ };
10
+ export type RangeTimelineProps = React.HTMLAttributes<HTMLElement> & {
11
+ label: string;
12
+ columns: {
13
+ label: string;
14
+ units: number;
15
+ }[];
16
+ bands?: {
17
+ label: string;
18
+ units: number;
19
+ }[];
20
+ rows: RangeTimelineRow[];
21
+ today?: number | null;
22
+ onRangeChange?: (id: string, edge: "start" | "end", delta: number) => void;
23
+ };
24
+ /** A horizontal range axis. Units and labels are data; the design system owns all geometry. */
25
+ export declare const RangeTimeline: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
26
+ label: string;
27
+ columns: {
28
+ label: string;
29
+ units: number;
30
+ }[];
31
+ bands?: {
32
+ label: string;
33
+ units: number;
34
+ }[];
35
+ rows: RangeTimelineRow[];
36
+ today?: number | null;
37
+ onRangeChange?: (id: string, edge: "start" | "end", delta: number) => void;
38
+ } & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1,161 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { useTranslation } from "../../i18n/use-translation.js";
5
+ import { GripVertical } from "lucide-react";
6
+ import { Button } from "../general/button.js";
7
+ import { Text } from "../general/typography.js";
8
+ import { cn } from "../../lib/utils.js";
9
+ const RangeTimeline = React.forwardRef(
10
+ function RangeTimeline2({ label, columns, bands, rows, today, onRangeChange, className, ...props }, ref) {
11
+ const { t } = useTranslation();
12
+ const units = Math.max(
13
+ 1,
14
+ columns.reduce((sum, column) => sum + column.units, 0)
15
+ );
16
+ const track = React.useRef(null);
17
+ const drag = React.useRef(null);
18
+ const [preview, setPreview] = React.useState(null);
19
+ const deltaAt = (x) => drag.current ? Math.round((x - drag.current.x) * units * drag.current.direction / drag.current.width) : 0;
20
+ const cancel = () => {
21
+ drag.current = null;
22
+ setPreview(null);
23
+ };
24
+ const complete = (event) => {
25
+ const current = drag.current;
26
+ if (!current) return;
27
+ const row = rows.find((row2) => row2.id === current.id);
28
+ const delta = deltaAt(event.clientX);
29
+ cancel();
30
+ if (!row) return;
31
+ const bounded = current.edge === "start" ? Math.min(delta, row.end - row.start) : Math.max(delta, row.start - row.end);
32
+ if (bounded) onRangeChange?.(row.id, current.edge, bounded);
33
+ };
34
+ return /* @__PURE__ */ jsx(
35
+ "section",
36
+ {
37
+ ...props,
38
+ ref,
39
+ className: cn("ui-range-timeline", className),
40
+ "aria-label": label,
41
+ tabIndex: 0,
42
+ children: /* @__PURE__ */ jsxs(
43
+ "div",
44
+ {
45
+ className: "ui-range-timeline-canvas",
46
+ style: { "--range-timeline-columns": Math.max(1, columns.length) },
47
+ children: [
48
+ bands && bands.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
49
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", "aria-hidden": "true" }),
50
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", children: bands.map((band, index) => /* @__PURE__ */ jsx(
51
+ "div",
52
+ {
53
+ className: "ui-range-timeline-column",
54
+ style: { flex: band.units },
55
+ children: /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", children: band.label })
56
+ },
57
+ index
58
+ )) })
59
+ ] }),
60
+ /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
61
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: /* @__PURE__ */ jsx(Text, { weight: "bold", children: label }) }),
62
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", ref: track, children: columns.map((column, index) => /* @__PURE__ */ jsx(
63
+ "div",
64
+ {
65
+ className: "ui-range-timeline-column",
66
+ style: { flex: column.units },
67
+ children: /* @__PURE__ */ jsx(Text, { size: "xs", children: column.label })
68
+ },
69
+ index
70
+ )) })
71
+ ] }),
72
+ rows.map((row) => {
73
+ const delta = preview?.id === row.id ? preview.delta : 0;
74
+ const start = Math.min(row.end, row.start + (preview?.edge === "start" ? delta : 0));
75
+ const end = Math.max(row.start, row.end + (preview?.edge === "end" ? delta : 0));
76
+ const left = Math.max(0, start), right = Math.min(units, end + 1);
77
+ return /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-row", children: [
78
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: row.label }),
79
+ /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-track", children: [
80
+ today != null && today >= 0 && today < units && /* @__PURE__ */ jsx(
81
+ "span",
82
+ {
83
+ "aria-hidden": "true",
84
+ className: "ui-range-timeline-today",
85
+ style: { insetInlineStart: `${(today + 0.5) / units * 100}%` }
86
+ }
87
+ ),
88
+ right <= left && /* @__PURE__ */ jsx(Text, { tone: "muted", children: t("rangeTimeline.outsideRange") }),
89
+ right > left && /* @__PURE__ */ jsx(
90
+ "div",
91
+ {
92
+ className: "ui-range-timeline-bar",
93
+ style: {
94
+ insetInlineStart: `${left / units * 100}%`,
95
+ inlineSize: `${(right - left) / units * 100}%`
96
+ },
97
+ children: onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
98
+ (edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
99
+ ).map((edge) => /* @__PURE__ */ jsx(
100
+ Button,
101
+ {
102
+ variant: "ghost",
103
+ size: "icon-xs",
104
+ className: "ui-range-timeline-handle",
105
+ "data-edge": edge,
106
+ "aria-label": edge === "start" ? row.startLabel : row.endLabel,
107
+ onPointerDown: (event) => {
108
+ const width = track.current?.getBoundingClientRect().width ?? 0;
109
+ if (!width || event.button !== 0) return;
110
+ event.currentTarget.setPointerCapture(event.pointerId);
111
+ drag.current = {
112
+ id: row.id,
113
+ edge,
114
+ x: event.clientX,
115
+ width,
116
+ direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
117
+ };
118
+ },
119
+ onPointerMove: (event) => {
120
+ if (drag.current)
121
+ setPreview({
122
+ id: drag.current.id,
123
+ edge: drag.current.edge,
124
+ delta: deltaAt(event.clientX)
125
+ });
126
+ },
127
+ onPointerUp: complete,
128
+ onPointerCancel: cancel,
129
+ onLostPointerCapture: cancel,
130
+ onKeyDown: (event) => {
131
+ if (event.key === "Escape") {
132
+ cancel();
133
+ return;
134
+ }
135
+ const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
136
+ if (!step) return;
137
+ event.preventDefault();
138
+ const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
139
+ const delta2 = step * direction;
140
+ if (edge === "start" ? row.start + delta2 <= row.end : row.end + delta2 >= row.start)
141
+ onRangeChange(row.id, edge, delta2);
142
+ },
143
+ children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
144
+ },
145
+ edge
146
+ ))
147
+ }
148
+ )
149
+ ] })
150
+ ] }, row.id);
151
+ })
152
+ ]
153
+ }
154
+ )
155
+ }
156
+ );
157
+ }
158
+ );
159
+ export {
160
+ RangeTimeline
161
+ };
@@ -113,7 +113,16 @@ function useBottomAnchor(viewport, enabled, offset, onAnchoredChange) {
113
113
  }, [viewport, enabled, offset]);
114
114
  }
115
115
  const ScrollArea = React.forwardRef(
116
- ({ className, children, viewportRef, anchor = "none", anchorOffset, onAnchoredChange, ...props }, ref) => {
116
+ ({
117
+ className,
118
+ children,
119
+ viewportRef,
120
+ anchor = "none",
121
+ anchorOffset,
122
+ onAnchoredChange,
123
+ orientation = "vertical",
124
+ ...props
125
+ }, ref) => {
117
126
  const [viewport, setViewport] = React.useState(null);
118
127
  const attachViewport = React.useCallback(
119
128
  (node) => {
@@ -139,11 +148,13 @@ const ScrollArea = React.forwardRef(
139
148
  tabIndex: 0,
140
149
  "data-slot": "scroll-area-viewport",
141
150
  "data-anchor": anchor,
151
+ "data-orientation": orientation,
142
152
  className: "size-full rounded-[inherit]",
143
153
  children
144
154
  }
145
155
  ),
146
- /* @__PURE__ */ jsx(ScrollBar, {}),
156
+ orientation !== "horizontal" && /* @__PURE__ */ jsx(ScrollBar, { orientation: "vertical" }),
157
+ orientation !== "vertical" && /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" }),
147
158
  /* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, {})
148
159
  ]
149
160
  }