@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
@@ -2,9 +2,10 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as SelectPrimitive from "@radix-ui/react-select";
5
- import { ChevronDown, ChevronUp, X } from "lucide-react";
5
+ import { ChevronDown, ChevronUp, Loader2, X } from "lucide-react";
6
6
  import { cn } from "../../lib/utils.js";
7
- import { controlTriggerClass } from "../../lib/control-styles.js";
7
+ import { controlSurfaceTriggerClass } from "../../lib/control-styles.js";
8
+ import { controlSurfaceAttrs, resolveAllowClear, resolveAriaInvalid } from "./control-surface.js";
8
9
  import { useInertHiddenBackground } from "../general/inert-background.js";
9
10
  import {
10
11
  mergeAriaIds,
@@ -65,65 +66,84 @@ function SelectGroup(props) {
65
66
  function SelectValue(props) {
66
67
  return /* @__PURE__ */ jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
67
68
  }
68
- const SelectTrigger = React.forwardRef(({ className, children, size = "md", width = "full", showIndicator = true, ...props }, ref) => {
69
- const field = React.useContext(SelectFieldA11yContext);
70
- const ownsName = props["aria-label"] !== void 0 || props["aria-labelledby"] !== void 0;
71
- const fieldOwnsName = field?.["aria-label"] !== void 0 || field?.["aria-labelledby"] !== void 0;
72
- const nameFallback = useFieldNameFallback({
73
- "aria-label": ownsName ? props["aria-label"] : field?.["aria-label"],
74
- "aria-labelledby": ownsName ? props["aria-labelledby"] : field?.["aria-labelledby"]
75
- });
76
- const fieldA11y = field || nameFallback["aria-labelledby"] !== void 0 ? {
77
- id: props.id ?? field?.id,
78
- ...ownsName ? {} : fieldOwnsName ? {
79
- "aria-label": field?.["aria-label"],
80
- "aria-labelledby": field?.["aria-labelledby"]
81
- } : nameFallback,
82
- "aria-describedby": mergeAriaIds(props["aria-describedby"], field?.["aria-describedby"]),
83
- "aria-errormessage": mergeAriaIds(
84
- props["aria-errormessage"],
85
- field?.["aria-errormessage"]
86
- ),
87
- "aria-required": props["aria-required"] ?? field?.["aria-required"],
88
- "aria-invalid": props["aria-invalid"] ?? field?.["aria-invalid"],
89
- "data-field": props["data-field"] ?? field?.["data-field"]
90
- } : void 0;
91
- const dataValue = (props["data-value"] ?? field?.value) || void 0;
92
- return /* @__PURE__ */ jsxs(
93
- SelectPrimitive.Trigger,
94
- {
95
- ref,
96
- "data-slot": "select-trigger",
97
- "data-size": size,
98
- "data-width": width,
99
- className: cn(
100
- controlTriggerClass,
101
- // `bounded` deliberately emits NO width utility: its width is owned by the
102
- // `[data-width="bounded"]` rule in control.css. A utility here would win the layer order
103
- // and make that rule — and therefore the token — dead, the way `w-full` did to
104
- // `.ui-app-setting-picker-icon` (gh#366, gh#371).
105
- width === "auto" && "w-auto",
106
- width === "full" && "w-full",
107
- "aria-invalid:border-destructive data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground whitespace-nowrap transition-[color,box-shadow] outline-none *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center",
108
- className
69
+ const SelectTrigger = React.forwardRef(
70
+ ({
71
+ className,
72
+ children,
73
+ size = "md",
74
+ variant,
75
+ status,
76
+ width = "full",
77
+ showIndicator = true,
78
+ ...props
79
+ }, ref) => {
80
+ const field = React.useContext(SelectFieldA11yContext);
81
+ const ownsName = props["aria-label"] !== void 0 || props["aria-labelledby"] !== void 0;
82
+ const fieldOwnsName = field?.["aria-label"] !== void 0 || field?.["aria-labelledby"] !== void 0;
83
+ const nameFallback = useFieldNameFallback({
84
+ "aria-label": ownsName ? props["aria-label"] : field?.["aria-label"],
85
+ "aria-labelledby": ownsName ? props["aria-labelledby"] : field?.["aria-labelledby"]
86
+ });
87
+ const fieldA11y = field || nameFallback["aria-labelledby"] !== void 0 ? {
88
+ id: props.id ?? field?.id,
89
+ ...ownsName ? {} : fieldOwnsName ? {
90
+ "aria-label": field?.["aria-label"],
91
+ "aria-labelledby": field?.["aria-labelledby"]
92
+ } : nameFallback,
93
+ "aria-describedby": mergeAriaIds(
94
+ props["aria-describedby"],
95
+ field?.["aria-describedby"]
109
96
  ),
110
- ...props,
111
- ...fieldA11y,
112
- "data-value": dataValue,
113
- children: [
114
- children,
115
- showIndicator ? /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(
116
- ChevronDown,
117
- {
118
- "data-slot": "select-chevron",
119
- className: "ui-select-chevron",
120
- "aria-hidden": "true"
121
- }
122
- ) }) : null
123
- ]
124
- }
125
- );
126
- });
97
+ "aria-errormessage": mergeAriaIds(
98
+ props["aria-errormessage"],
99
+ field?.["aria-errormessage"]
100
+ ),
101
+ "aria-required": props["aria-required"] ?? field?.["aria-required"],
102
+ "aria-invalid": resolveAriaInvalid(
103
+ props["aria-invalid"] ?? field?.["aria-invalid"],
104
+ status
105
+ ),
106
+ "data-field": props["data-field"] ?? field?.["data-field"]
107
+ } : { "aria-invalid": resolveAriaInvalid(props["aria-invalid"], status) };
108
+ const dataValue = (props["data-value"] ?? field?.value) || void 0;
109
+ return /* @__PURE__ */ jsxs(
110
+ SelectPrimitive.Trigger,
111
+ {
112
+ ref,
113
+ "data-slot": "select-trigger",
114
+ "data-size": size,
115
+ "data-variant": controlSurfaceAttrs({ variant })["data-variant"],
116
+ "data-status": status,
117
+ "data-width": width,
118
+ className: cn(
119
+ controlSurfaceTriggerClass,
120
+ // `bounded` deliberately emits NO width utility: its width is owned by the
121
+ // `[data-width="bounded"]` rule in control.css. A utility here would win the layer order
122
+ // and make that rule — and therefore the token — dead, the way `w-full` did to
123
+ // `.ui-app-setting-picker-icon` (gh#366, gh#371).
124
+ width === "auto" && "w-auto",
125
+ width === "full" && "w-full",
126
+ "aria-invalid:border-destructive data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground whitespace-nowrap transition-[color,box-shadow] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center",
127
+ className
128
+ ),
129
+ ...props,
130
+ ...fieldA11y,
131
+ "data-value": dataValue,
132
+ children: [
133
+ children,
134
+ showIndicator ? /* @__PURE__ */ jsx(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx(
135
+ ChevronDown,
136
+ {
137
+ "data-slot": "select-chevron",
138
+ className: "ui-select-chevron",
139
+ "aria-hidden": "true"
140
+ }
141
+ ) }) : null
142
+ ]
143
+ }
144
+ );
145
+ }
146
+ );
127
147
  SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
128
148
  const SelectScrollUpButton = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
129
149
  SelectPrimitive.ScrollUpButton,
@@ -169,7 +189,11 @@ const SelectContent = React.forwardRef(({ className, children, position = "poppe
169
189
  "data-slot": "select-viewport",
170
190
  className: cn(
171
191
  "ui-select-viewport",
172
- position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
192
+ position === "popper" && "h-[var(--radix-select-trigger-height)] w-full",
193
+ // The trigger-width floor is a UTILITY, so no `[data-popup-match]` rule in control.css
194
+ // could ever lift it (gh#366). It is therefore WITHHELD whenever the consumer stated a
195
+ // width of their own — which is exactly what antd's `popupMatchSelectWidth` is for.
196
+ position === "popper" && !props["data-popup-match"] && "min-w-[var(--radix-select-trigger-width)]"
173
197
  ),
174
198
  children
175
199
  }
@@ -190,14 +214,25 @@ const SelectLabel = React.forwardRef(({ className, ...props }, ref) => /* @__PUR
190
214
  }
191
215
  ));
192
216
  SelectLabel.displayName = SelectPrimitive.Label.displayName;
193
- const SelectItem = React.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsx(
217
+ const SelectItem = React.forwardRef(({ className, children, selectedIcon, ...props }, ref) => /* @__PURE__ */ jsxs(
194
218
  SelectPrimitive.Item,
195
219
  {
196
220
  ref,
197
221
  "data-slot": "select-item",
198
222
  className: cn("ui-select-item [&_svg:not([class*='text-'])]:text-muted-foreground", className),
199
223
  ...props,
200
- children: /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
224
+ children: [
225
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children }),
226
+ selectedIcon ? /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { asChild: true, children: /* @__PURE__ */ jsx(
227
+ "span",
228
+ {
229
+ "data-slot": "select-item-selected-icon",
230
+ className: "ui-search-select-selected-icon",
231
+ "aria-hidden": "true",
232
+ children: selectedIcon
233
+ }
234
+ ) }) : null
235
+ ]
201
236
  }
202
237
  ));
203
238
  SelectItem.displayName = SelectPrimitive.Item.displayName;
@@ -224,105 +259,90 @@ function groupDataOptions(options) {
224
259
  }
225
260
  return order.map((key) => ({ heading: key || void 0, items: buckets.get(key) ?? [] }));
226
261
  }
227
- function DataSelect({
228
- options = [],
229
- loadOptions,
230
- showSearch,
231
- value,
232
- defaultValue,
233
- onValueChange,
234
- renderOption,
235
- labelRender,
236
- selectedLabel,
237
- selectedIcon,
238
- placeholder,
239
- searchPlaceholder,
240
- emptyMessage,
241
- loadingMessage,
242
- errorMessage,
243
- clearLabel,
244
- clearable,
245
- disabled,
246
- readOnly,
247
- size,
248
- open,
249
- onOpenChange,
250
- search,
251
- onSearchChange,
252
- filterOption,
253
- renderError,
254
- renderLoadMore,
255
- name,
256
- id,
257
- className,
258
- "data-testid": dataTestId,
259
- "data-field": dataField,
260
- ...rest
261
- }) {
262
- const ariaProps = Object.fromEntries(
263
- Object.entries(rest).filter(([key]) => key.startsWith("aria-"))
264
- );
262
+ function DataSelect(props) {
265
263
  const { t } = useTranslation();
266
- const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
267
- const currentValue = value ?? uncontrolledValue;
268
- const identity = useFieldIdentity({ id, name, "data-field": dataField });
269
- const resolvedName = name ?? identity.name;
270
- const resolvedField = dataField ?? identity["data-field"];
271
- const searchable = showSearch ?? Boolean(loadOptions);
264
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(
265
+ typeof props.defaultValue === "string" ? props.defaultValue : void 0
266
+ );
267
+ const identity = useFieldIdentity({
268
+ id: props.id,
269
+ name: props.name,
270
+ "data-field": props["data-field"]
271
+ });
272
+ const resolvedName = props.name ?? identity.name;
273
+ const resolvedField = props["data-field"] ?? identity["data-field"];
274
+ const options = props.options ?? [];
272
275
  const hasOptions = options.length > 0;
273
- if (searchable) {
276
+ const searchable = props.showSearch ?? (Boolean(props.loadOptions) || props.mode === "multiple");
277
+ if (props.mode === "multiple" || searchable) {
274
278
  return /* @__PURE__ */ jsx(
275
279
  SearchSelect,
276
280
  {
277
- value,
278
- defaultValue,
279
- onValueChange,
281
+ ...props,
280
282
  options,
281
- loadOptions,
282
- renderOption,
283
- labelRender,
284
- selectedLabel,
285
- selectedIcon,
286
- placeholder,
287
- searchPlaceholder,
288
- emptyMessage,
289
- loadingMessage,
290
- errorMessage,
291
- clearLabel,
292
- clearable,
293
- disabled: disabled || !loadOptions && !hasOptions,
294
- readOnly,
295
- size,
296
- open,
297
- onOpenChange,
298
- search,
299
- onSearchChange,
300
- filterOption,
301
- renderError,
302
- renderLoadMore,
283
+ disabled: props.disabled || !props.loadOptions && !hasOptions,
303
284
  name: resolvedName,
304
- id,
305
- className,
306
- "data-testid": dataTestId,
307
- "data-field": resolvedField,
308
- ...ariaProps
285
+ "data-field": resolvedField
309
286
  }
310
287
  );
311
288
  }
312
- const optionTestId = (optionValue) => dataTestId ? `${dataTestId}-option-${optionValue}` : void 0;
313
- const renderItem = (option) => /* @__PURE__ */ jsx(
314
- SelectItem,
315
- {
316
- value: option.value,
317
- disabled: option.disabled,
318
- "data-testid": optionTestId(option.value),
319
- children: renderOption ? renderOption(option) : option.label
320
- },
321
- option.value
289
+ const {
290
+ renderOption,
291
+ optionRender,
292
+ menuItemSelectedIcon,
293
+ placeholder,
294
+ clearLabel,
295
+ clearable,
296
+ disabled,
297
+ readOnly,
298
+ size,
299
+ status,
300
+ variant,
301
+ loading,
302
+ open,
303
+ defaultOpen,
304
+ onOpenChange,
305
+ notFoundContent,
306
+ popupMatchSelectWidth,
307
+ allowClear,
308
+ onClear,
309
+ value,
310
+ defaultValue,
311
+ onValueChange,
312
+ id,
313
+ className,
314
+ "data-testid": dataTestId,
315
+ ...rest
316
+ } = props;
317
+ const currentValue = value ?? uncontrolledValue;
318
+ const ariaProps = Object.fromEntries(
319
+ Object.entries(rest).filter(([key]) => key.startsWith("aria-"))
322
320
  );
321
+ const optionTestId = (optionValue) => dataTestId ? `${dataTestId}-option-${optionValue}` : void 0;
322
+ let flatIndex = 0;
323
+ const renderItem = (option) => {
324
+ const index = flatIndex++;
325
+ return /* @__PURE__ */ jsx(
326
+ SelectItem,
327
+ {
328
+ value: option.value,
329
+ disabled: option.disabled,
330
+ "data-testid": optionTestId(option.value),
331
+ selectedIcon: menuItemSelectedIcon,
332
+ children: optionRender ? optionRender(option, { index }) : renderOption ? renderOption(option) : option.label
333
+ },
334
+ option.value
335
+ );
336
+ };
323
337
  const isControlled = value !== void 0;
324
- const canClear = clearable !== false && isControlled && !disabled && !readOnly;
338
+ const clearControl = resolveAllowClear(
339
+ allowClear,
340
+ clearable,
341
+ clearLabel ?? t("dataEntry.searchSelect.clear")
342
+ );
343
+ const canClear = clearControl.enabled && isControlled && !disabled && !readOnly && !loading;
325
344
  const showClear = canClear && Boolean(value);
345
+ const showEmptyPopup = !hasOptions && notFoundContent !== void 0;
326
346
  const select = /* @__PURE__ */ jsxs(
327
347
  SelectPrimitive.Root,
328
348
  {
@@ -336,8 +356,11 @@ function DataSelect({
336
356
  options.find((option) => option.value === next)
337
357
  );
338
358
  },
339
- disabled: disabled || !hasOptions,
359
+ disabled: disabled || !hasOptions && !showEmptyPopup,
340
360
  name: resolvedName,
361
+ open,
362
+ defaultOpen,
363
+ onOpenChange,
341
364
  children: [
342
365
  /* @__PURE__ */ jsx(
343
366
  SelectTrigger,
@@ -346,33 +369,62 @@ function DataSelect({
346
369
  "data-testid": dataTestId,
347
370
  "data-field": resolvedField,
348
371
  "data-value": currentValue || void 0,
349
- className: cn(showClear && "ui-control-trigger-affixed", canClear ? void 0 : className),
350
- showIndicator: !showClear,
372
+ size,
373
+ variant,
374
+ status,
375
+ "aria-busy": loading || void 0,
376
+ className: cn(
377
+ (showClear || loading) && "ui-control-trigger-affixed",
378
+ canClear || loading ? void 0 : className
379
+ ),
380
+ showIndicator: !showClear && !loading,
351
381
  ...ariaProps,
352
382
  children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
353
383
  }
354
384
  ),
355
- /* @__PURE__ */ jsx(SelectContent, { children: groupDataOptions(options).map(
356
- (group) => group.heading ? /* @__PURE__ */ jsxs(SelectGroup, { children: [
357
- /* @__PURE__ */ jsx(SelectLabel, { children: group.heading }),
358
- group.items.map(renderItem)
359
- ] }, group.heading) : /* @__PURE__ */ jsx(React.Fragment, { children: group.items.map(renderItem) }, "__ungrouped")
360
- ) })
385
+ /* @__PURE__ */ jsxs(
386
+ SelectContent,
387
+ {
388
+ "data-popup-match": popupMatchSelectWidth === void 0 || popupMatchSelectWidth === true ? void 0 : popupMatchSelectWidth === false ? "content" : "fixed",
389
+ style: typeof popupMatchSelectWidth === "number" ? {
390
+ "--select-content-inline-size": `${popupMatchSelectWidth}px`
391
+ } : void 0,
392
+ children: [
393
+ showEmptyPopup ? /* @__PURE__ */ jsx("div", { "data-slot": "select-empty", className: "ui-select-empty", children: notFoundContent }) : null,
394
+ groupDataOptions(options).map(
395
+ (group) => group.heading ? /* @__PURE__ */ jsxs(SelectGroup, { children: [
396
+ /* @__PURE__ */ jsx(SelectLabel, { children: group.heading }),
397
+ group.items.map(renderItem)
398
+ ] }, group.heading) : /* @__PURE__ */ jsx(React.Fragment, { children: group.items.map(renderItem) }, "__ungrouped")
399
+ )
400
+ ]
401
+ }
402
+ )
361
403
  ]
362
404
  }
363
405
  );
364
- if (!canClear) return select;
406
+ if (!canClear && !loading) return select;
365
407
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
366
408
  select,
367
- showClear ? /* @__PURE__ */ jsx("div", { className: "ui-control-affix", children: /* @__PURE__ */ jsx(
409
+ loading ? /* @__PURE__ */ jsx("div", { className: "ui-control-affix", children: /* @__PURE__ */ jsx(
410
+ Loader2,
411
+ {
412
+ "data-slot": "select-loading",
413
+ className: "ui-control-affix-icon ui-control-affix-indicator animate-spin",
414
+ "aria-hidden": "true"
415
+ }
416
+ ) }) : showClear ? /* @__PURE__ */ jsx("div", { className: "ui-control-affix", children: /* @__PURE__ */ jsx(
368
417
  "button",
369
418
  {
370
419
  type: "button",
371
- "aria-label": clearLabel ?? t("dataEntry.searchSelect.clear"),
420
+ "aria-label": clearControl.label,
372
421
  "data-testid": dataTestId ? `${dataTestId}-clear` : void 0,
373
422
  className: "ui-control-affix-action",
374
- onClick: () => onValueChange?.("", void 0),
375
- children: /* @__PURE__ */ jsx(X, { className: "ui-control-affix-icon", "aria-hidden": "true" })
423
+ onClick: () => {
424
+ onValueChange?.("", void 0);
425
+ onClear?.();
426
+ },
427
+ children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-control-affix-icon", "aria-hidden": "true" })
376
428
  }
377
429
  ) }) : null
378
430
  ] });
@@ -1,5 +1,13 @@
1
1
  import * as React from "react";
2
2
  import * as SliderPrimitive from "@radix-ui/react-slider";
3
+ import type { SliderTooltipProp } from "../../props/components/data-entry.prop.js";
3
4
  export type { SliderProp, SliderProp as SliderProps } from "../../props/components/data-entry.prop.js";
4
5
  /** Numeric range slider (Radix Slider). */
5
- export declare const Slider: React.ForwardRefExoticComponent<Omit<SliderPrimitive.SliderProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
6
+ export declare const Slider: React.ForwardRefExoticComponent<Omit<SliderPrimitive.SliderProps & React.RefAttributes<HTMLSpanElement>, "ref"> & {
7
+ range?: boolean;
8
+ marks?: import("../../props/components/data-entry.prop.js").SliderMarksProp;
9
+ dots?: boolean;
10
+ included?: boolean;
11
+ reverse?: boolean;
12
+ tooltip?: SliderTooltipProp;
13
+ } & React.RefAttributes<HTMLSpanElement>>;
@@ -3,6 +3,26 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as SliderPrimitive from "@radix-ui/react-slider";
5
5
  import { cn } from "../../lib/utils.js";
6
+ function fraction(value, min, max, reverse) {
7
+ if (max === min) return 0;
8
+ const raw = (value - min) / (max - min);
9
+ return reverse ? 1 - raw : raw;
10
+ }
11
+ function markEntries(marks) {
12
+ if (!marks) return [];
13
+ return Object.entries(marks).map(([key, label]) => [Number(key), label]).filter(([at]) => Number.isFinite(at)).sort((a, b) => a[0] - b[0]);
14
+ }
15
+ function dotStops(min, max, step) {
16
+ if (!Number.isFinite(step) || step <= 0) return [];
17
+ const stops = [];
18
+ for (let at = min; at <= max; at += step) stops.push(at);
19
+ return stops;
20
+ }
21
+ function tooltipContent(tooltip, value) {
22
+ if (!tooltip || tooltip === true) return value;
23
+ if (tooltip.formatter === null) return null;
24
+ return tooltip.formatter ? tooltip.formatter(value) : value;
25
+ }
6
26
  const Slider = React.forwardRef(
7
27
  ({
8
28
  className,
@@ -10,38 +30,96 @@ const Slider = React.forwardRef(
10
30
  value,
11
31
  min = 0,
12
32
  max = 100,
33
+ step = 1,
34
+ range,
35
+ marks,
36
+ dots = false,
37
+ included = true,
38
+ reverse = false,
39
+ tooltip = false,
40
+ inverted,
41
+ orientation = "horizontal",
13
42
  "aria-label": ariaLabel,
14
43
  "aria-labelledby": ariaLabelledby,
15
44
  ...props
16
45
  }, ref) => {
17
- const values = React.useMemo(
18
- () => Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : [min, max],
19
- [defaultValue, max, min, value]
20
- );
46
+ const values = React.useMemo(() => {
47
+ const given = Array.isArray(value) ? value : Array.isArray(defaultValue) ? defaultValue : null;
48
+ if (range === true) {
49
+ if (given) return given.length >= 2 ? given.slice(0, 2) : [given[0] ?? min, max];
50
+ return [min, max];
51
+ }
52
+ if (range === false) return given ? given.slice(0, 1) : [min];
53
+ return given ?? [min, max];
54
+ }, [defaultValue, max, min, range, value]);
21
55
  const thumbLabel = (index) => ariaLabel != null && values.length > 1 ? `${ariaLabel} ${index + 1}` : ariaLabel;
56
+ const ticks = markEntries(marks);
57
+ const stops = dots ? dotStops(min, max, typeof step === "number" ? step : 1) : [];
58
+ const vertical = orientation === "vertical";
59
+ const showTooltip = tooltip !== false && tooltip != null;
60
+ const offsetStyle = (at) => ({
61
+ [vertical ? "--slider-mark-offset-block" : "--slider-mark-offset-inline"]: `${fraction(at, min, max, reverse) * 100}%`
62
+ });
22
63
  return /* @__PURE__ */ jsxs(
23
64
  SliderPrimitive.Root,
24
65
  {
25
66
  ref,
26
67
  "data-slot": "slider",
68
+ "data-has-marks": ticks.length > 0 ? "true" : void 0,
27
69
  className: cn("ui-slider", className),
28
- defaultValue,
70
+ defaultValue: defaultValue ?? (range === true ? [min, max] : void 0),
29
71
  min,
30
72
  max,
73
+ step,
31
74
  value,
75
+ orientation,
76
+ inverted: inverted ?? reverse,
32
77
  ...props,
33
78
  children: [
34
- /* @__PURE__ */ jsx(SliderPrimitive.Track, { "data-slot": "slider-track", className: "ui-slider-track", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { "data-slot": "slider-range", className: "ui-slider-range" }) }),
35
- values.map((_, index) => /* @__PURE__ */ jsx(
79
+ /* @__PURE__ */ jsxs(SliderPrimitive.Track, { "data-slot": "slider-track", className: "ui-slider-track", children: [
80
+ included ? /* @__PURE__ */ jsx(SliderPrimitive.Range, { "data-slot": "slider-range", className: "ui-slider-range" }) : null,
81
+ stops.map((at) => /* @__PURE__ */ jsx(
82
+ "span",
83
+ {
84
+ "data-slot": "slider-dot",
85
+ "data-active": included && at <= (values[values.length - 1] ?? min) ? "true" : void 0,
86
+ className: "ui-slider-dot",
87
+ style: offsetStyle(at),
88
+ "aria-hidden": "true"
89
+ },
90
+ `dot-${at}`
91
+ ))
92
+ ] }),
93
+ values.map((thumbValue, index) => /* @__PURE__ */ jsx(
36
94
  SliderPrimitive.Thumb,
37
95
  {
38
96
  "data-slot": "slider-thumb",
39
97
  className: "ui-slider-thumb",
40
98
  "aria-label": thumbLabel(index),
41
- "aria-labelledby": ariaLabelledby
99
+ "aria-labelledby": ariaLabelledby,
100
+ children: showTooltip ? /* @__PURE__ */ jsx(
101
+ "span",
102
+ {
103
+ "data-slot": "slider-tooltip",
104
+ "data-open": tooltip !== true && tooltip.open ? "true" : void 0,
105
+ className: "ui-slider-tooltip",
106
+ "aria-hidden": "true",
107
+ children: tooltipContent(tooltip, thumbValue)
108
+ }
109
+ ) : null
42
110
  },
43
111
  index
44
- ))
112
+ )),
113
+ ticks.length > 0 ? /* @__PURE__ */ jsx("span", { "data-slot": "slider-marks", className: "ui-slider-marks", "aria-hidden": "true", children: ticks.map(([at, label]) => /* @__PURE__ */ jsx(
114
+ "span",
115
+ {
116
+ "data-slot": "slider-mark",
117
+ className: "ui-slider-mark",
118
+ style: offsetStyle(at),
119
+ children: label
120
+ },
121
+ `mark-${at}`
122
+ )) }) : null
45
123
  ]
46
124
  }
47
125
  );
@@ -3,4 +3,7 @@ import * as SwitchPrimitive from "@radix-ui/react-switch";
3
3
  export type { SwitchProp, SwitchProp as SwitchProps } from "../../props/components/data-entry.prop.js";
4
4
  export declare const Switch: React.ForwardRefExoticComponent<Omit<SwitchPrimitive.SwitchProps & React.RefAttributes<HTMLButtonElement>, "ref"> & {
5
5
  size?: "sm" | "md";
6
+ loading?: boolean;
7
+ checkedChildren?: React.ReactNode;
8
+ unCheckedChildren?: React.ReactNode;
6
9
  } & React.RefAttributes<HTMLButtonElement>>;