@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
@@ -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";
@@ -69,6 +69,6 @@ interface PopoverContentProps extends React.ComponentPropsWithRef<"div">, Popove
69
69
  }
70
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;
71
71
  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;
72
+ export declare const PopoverTitle: ({ className, id, ...props }: React.HTMLAttributes<HTMLDivElement>) => React.JSX.Element;
73
+ export declare const PopoverDescription: ({ className, id, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => React.JSX.Element;
74
74
  export {};
@@ -48,6 +48,11 @@ function Popover({
48
48
  const triggerRef = React.useRef(null);
49
49
  const anchorRef = React.useRef(null);
50
50
  const contentId = React.useId();
51
+ const titleId = React.useId();
52
+ const descriptionId = React.useId();
53
+ const triggerId = React.useId();
54
+ const [hasTitle, registerTitle] = React.useState(false);
55
+ const [hasDescription, registerDescription] = React.useState(false);
51
56
  const isOpen = open ?? uncontrolledOpen;
52
57
  const setOpen = React.useCallback(
53
58
  (next) => {
@@ -67,9 +72,27 @@ function Popover({
67
72
  triggerRef,
68
73
  anchorRef,
69
74
  anchored,
70
- setAnchored
75
+ setAnchored,
76
+ titleId,
77
+ descriptionId,
78
+ hasTitle,
79
+ hasDescription,
80
+ registerTitle,
81
+ registerDescription,
82
+ triggerId
71
83
  }),
72
- [isOpen, setOpen, contentId, modal, anchored]
84
+ [
85
+ isOpen,
86
+ setOpen,
87
+ contentId,
88
+ modal,
89
+ anchored,
90
+ titleId,
91
+ descriptionId,
92
+ hasTitle,
93
+ hasDescription,
94
+ triggerId
95
+ ]
73
96
  );
74
97
  return /* @__PURE__ */ jsx(PopoverRootContext.Provider, { value, children });
75
98
  }
@@ -83,6 +106,7 @@ function PopoverTrigger({ asChild, onClick, ref, ...props }) {
83
106
  "data-slot": "popover-trigger",
84
107
  "aria-haspopup": "dialog",
85
108
  "aria-expanded": root.open,
109
+ id: props.id ?? root.triggerId,
86
110
  "aria-controls": root.open ? root.contentId : void 0,
87
111
  "data-state": root.open ? "open" : "closed",
88
112
  ...props,
@@ -186,6 +210,8 @@ function PopoverContent({
186
210
  "data-state": isExiting ? "closed" : "open",
187
211
  "data-flush": flush ? "" : void 0,
188
212
  ...props,
213
+ "aria-labelledby": props["aria-labelledby"] ?? (props["aria-label"] ? void 0 : root.hasTitle ? root.titleId : root.triggerId),
214
+ "aria-describedby": props["aria-describedby"] ?? (root.hasDescription ? root.descriptionId : void 0),
189
215
  ref: mergeRefs(ref, racRef, contentRef),
190
216
  className: cn(
191
217
  "ui-popover-content origin-[var(--radix-popover-content-transform-origin)]",
@@ -213,18 +239,42 @@ function PopoverContent({
213
239
  );
214
240
  }
215
241
  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 });
242
+ const PopoverTitle = ({ className, id, ...props }) => {
243
+ const root = usePopoverRoot("PopoverTitle");
244
+ React.useEffect(() => {
245
+ root.registerTitle(true);
246
+ return () => root.registerTitle(false);
247
+ }, [root]);
248
+ return /* @__PURE__ */ jsx(
249
+ "div",
250
+ {
251
+ "data-slot": "popover-title",
252
+ id: id ?? root.titleId,
253
+ className: cn("font-medium", className),
254
+ ...props
255
+ }
256
+ );
257
+ };
217
258
  const PopoverDescription = ({
218
259
  className,
260
+ id,
219
261
  ...props
220
- }) => /* @__PURE__ */ jsx(
221
- "p",
222
- {
223
- "data-slot": "popover-description",
224
- className: cn("text-muted-foreground", className),
225
- ...props
226
- }
227
- );
262
+ }) => {
263
+ const root = usePopoverRoot("PopoverDescription");
264
+ React.useEffect(() => {
265
+ root.registerDescription(true);
266
+ return () => root.registerDescription(false);
267
+ }, [root]);
268
+ return /* @__PURE__ */ jsx(
269
+ "p",
270
+ {
271
+ "data-slot": "popover-description",
272
+ id: id ?? root.descriptionId,
273
+ className: cn("text-muted-foreground", className),
274
+ ...props
275
+ }
276
+ );
277
+ };
228
278
  export {
229
279
  Popover,
230
280
  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
  }