@antadesign/anta 0.3.33 → 0.3.35

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 (205) hide show
  1. package/LICENSE.md +14 -1
  2. package/README.md +9 -0
  3. package/dist/anta_helpers.d.ts +46 -30
  4. package/dist/anta_helpers.js +66 -25
  5. package/dist/bundle.css +1 -1
  6. package/dist/bundle.js +2 -1353
  7. package/dist/components/Banner.d.ts +25 -40
  8. package/dist/components/Banner.js +15 -17
  9. package/dist/components/Breadcrumbs.d.ts +0 -1
  10. package/dist/components/Breadcrumbs.js +0 -1
  11. package/dist/components/Button.d.ts +2 -3
  12. package/dist/components/Button.js +1 -0
  13. package/dist/components/ButtonCopy.js +3 -2
  14. package/dist/components/Calendar.js +13 -13
  15. package/dist/components/Card.d.ts +9 -17
  16. package/dist/components/Card.js +50 -46
  17. package/dist/components/Dialog.d.ts +1 -0
  18. package/dist/components/Dialog.js +16 -10
  19. package/dist/components/Expander.d.ts +6 -21
  20. package/dist/components/Expander.js +24 -23
  21. package/dist/components/Icon.d.ts +8 -14
  22. package/dist/components/Input.d.ts +77 -96
  23. package/dist/components/Input.js +23 -27
  24. package/dist/components/InputAutocomplete.d.ts +29 -10
  25. package/dist/components/InputAutocomplete.js +25 -8
  26. package/dist/components/InputDate.d.ts +0 -1
  27. package/dist/components/InputDate.js +2 -3
  28. package/dist/components/InputTime.d.ts +10 -4
  29. package/dist/components/InputTime.js +20 -16
  30. package/dist/components/Loader.d.ts +2 -2
  31. package/dist/components/Menu.d.ts +5 -4
  32. package/dist/components/Menu.js +13 -8
  33. package/dist/components/MenuItem.js +1 -14
  34. package/dist/components/MenuItemCopy.js +2 -2
  35. package/dist/components/Panel.d.ts +3 -1
  36. package/dist/components/Panel.js +17 -11
  37. package/dist/components/Progress.d.ts +21 -23
  38. package/dist/components/Progress.js +13 -9
  39. package/dist/components/RadioGroup.js +6 -8
  40. package/dist/components/{select-parts.css → Select.css} +1 -1
  41. package/dist/components/Select.d.ts +53 -36
  42. package/dist/components/Select.js +53 -98
  43. package/dist/components/SelectFaceted.d.ts +7 -4
  44. package/dist/components/SelectFaceted.js +21 -10
  45. package/dist/components/Slider.d.ts +28 -11
  46. package/dist/components/Slider.js +20 -20
  47. package/dist/components/Steps.css +1 -1
  48. package/dist/components/Steps.d.ts +0 -1
  49. package/dist/components/Steps.js +1 -12
  50. package/dist/components/Tabs.d.ts +17 -20
  51. package/dist/components/Tabs.js +7 -9
  52. package/dist/components/Text.d.ts +55 -36
  53. package/dist/components/Text.js +35 -22
  54. package/dist/components/Title.d.ts +19 -27
  55. package/dist/components/Title.js +2 -1
  56. package/dist/components/Toaster.js +9 -2
  57. package/dist/components/Tooltip.d.ts +10 -15
  58. package/dist/components/copy-props.d.ts +14 -3
  59. package/dist/components/copy-props.js +14 -3
  60. package/dist/components/select-tree.d.ts +24 -0
  61. package/dist/components/select-tree.js +35 -0
  62. package/dist/element-base.d.ts +10 -0
  63. package/dist/element-base.js +15 -0
  64. package/dist/elements/a-avatar.css +1 -1
  65. package/dist/elements/a-avatar.js +2 -28
  66. package/dist/elements/a-banner.css +1 -1
  67. package/dist/elements/a-banner.d.ts +4 -1
  68. package/dist/elements/a-banner.js +22 -112
  69. package/dist/elements/a-breadcrumbs.d.ts +1 -0
  70. package/dist/elements/a-breadcrumbs.js +1 -0
  71. package/dist/elements/a-button.css +1 -1
  72. package/dist/elements/a-button.d.ts +10 -7
  73. package/dist/elements/a-button.js +18 -1
  74. package/dist/elements/a-calendar.d.ts +14 -13
  75. package/dist/elements/a-calendar.js +29 -24
  76. package/dist/elements/a-card.css +1 -1
  77. package/dist/elements/a-card.d.ts +0 -9
  78. package/dist/elements/a-card.js +0 -184
  79. package/dist/elements/a-checkbox.css +1 -1
  80. package/dist/elements/a-copy.css +1 -1
  81. package/dist/elements/a-copy.d.ts +1 -5
  82. package/dist/elements/a-copy.js +129 -108
  83. package/dist/elements/a-dialog.css +1 -1
  84. package/dist/elements/a-dialog.d.ts +1 -1
  85. package/dist/elements/a-dialog.js +68 -194
  86. package/dist/elements/a-expander.css +1 -1
  87. package/dist/elements/a-expander.d.ts +4 -30
  88. package/dist/elements/a-expander.js +85 -344
  89. package/dist/elements/a-icon.d.ts +5 -23
  90. package/dist/elements/a-icon.js +1 -2
  91. package/dist/elements/a-input-date.d.ts +1 -0
  92. package/dist/elements/a-input-date.js +1 -0
  93. package/dist/elements/a-input-time.css +1 -1
  94. package/dist/elements/a-input-time.d.ts +2 -1
  95. package/dist/elements/a-input-time.js +101 -168
  96. package/dist/elements/a-input.css +1 -1
  97. package/dist/elements/a-input.d.ts +10 -8
  98. package/dist/elements/a-input.js +155 -230
  99. package/dist/elements/a-loader.d.ts +5 -8
  100. package/dist/elements/a-loader.js +1 -2
  101. package/dist/elements/a-menu-item.css +1 -1
  102. package/dist/elements/a-menu-item.d.ts +5 -3
  103. package/dist/elements/a-menu-item.js +5 -1
  104. package/dist/elements/a-menu.css +1 -1
  105. package/dist/elements/a-menu.d.ts +5 -7
  106. package/dist/elements/a-menu.js +383 -299
  107. package/dist/elements/a-panel.css +1 -1
  108. package/dist/elements/a-panel.js +19 -37
  109. package/dist/elements/a-progress.css +1 -1
  110. package/dist/elements/a-progress.d.ts +0 -22
  111. package/dist/elements/a-progress.js +0 -100
  112. package/dist/elements/a-radio-group.d.ts +1 -1
  113. package/dist/elements/a-radio-group.js +6 -4
  114. package/dist/elements/a-select-faceted.d.ts +1 -0
  115. package/dist/elements/a-select-faceted.js +1 -0
  116. package/dist/elements/a-select.d.ts +1 -0
  117. package/dist/elements/a-select.js +1 -0
  118. package/dist/elements/a-slider.css +1 -1
  119. package/dist/elements/a-slider.d.ts +11 -3
  120. package/dist/elements/a-slider.js +244 -242
  121. package/dist/elements/a-steps.d.ts +1 -0
  122. package/dist/elements/a-steps.js +1 -0
  123. package/dist/elements/a-switch.css +1 -1
  124. package/dist/elements/a-tab.css +1 -1
  125. package/dist/elements/a-tabpanel.d.ts +2 -2
  126. package/dist/elements/a-tabpanel.js +13 -3
  127. package/dist/elements/a-tabs.css +1 -1
  128. package/dist/elements/a-tabs.d.ts +1 -1
  129. package/dist/elements/a-tabs.js +6 -4
  130. package/dist/elements/a-tag.css +1 -1
  131. package/dist/elements/a-tag.d.ts +1 -0
  132. package/dist/elements/a-tag.js +1 -0
  133. package/dist/elements/a-text.css +1 -1
  134. package/dist/elements/a-text.d.ts +6 -43
  135. package/dist/elements/a-text.js +110 -193
  136. package/dist/elements/a-title.css +1 -1
  137. package/dist/elements/a-title.d.ts +1 -0
  138. package/dist/elements/a-title.js +1 -0
  139. package/dist/elements/a-toast.css +1 -1
  140. package/dist/elements/a-toast.d.ts +10 -45
  141. package/dist/elements/a-toast.js +80 -66
  142. package/dist/elements/a-toaster.css +1 -1
  143. package/dist/elements/a-toaster.js +9 -44
  144. package/dist/elements/a-tooltip.css +1 -1
  145. package/dist/elements/a-tooltip.d.ts +1 -1
  146. package/dist/elements/a-tooltip.js +142 -136
  147. package/dist/elements/copy-behavior.d.ts +1 -1
  148. package/dist/elements/copy-behavior.js +21 -21
  149. package/dist/elements/index.d.ts +9 -3
  150. package/dist/elements/index.js +6 -6
  151. package/dist/elements/input-focus-modality.d.ts +15 -0
  152. package/dist/elements/input-focus-modality.js +44 -0
  153. package/dist/elements/input-trailing-actions.d.ts +5 -0
  154. package/dist/elements/input-trailing-actions.js +38 -0
  155. package/dist/elements/shadow-aria.d.ts +2 -0
  156. package/dist/elements/shadow-aria.js +2 -1
  157. package/dist/elements/value-input.d.ts +3 -0
  158. package/dist/elements/value-input.js +12 -0
  159. package/dist/general_types.d.ts +103 -96
  160. package/dist/index.d.ts +1 -1
  161. package/dist/input-events.d.ts +4 -0
  162. package/dist/input-events.js +15 -0
  163. package/dist/jsx-runtime.d.ts +70 -23
  164. package/dist/jsx-runtime.js +26 -19
  165. package/dist/native-event-props.d.ts +2 -0
  166. package/dist/native-event-props.js +10 -0
  167. package/dist/reset.css +1 -1
  168. package/dist/theme-antithesis.css +10 -1
  169. package/dist/theme-antune.css +1 -1
  170. package/docs/accessibility.md +17 -3
  171. package/docs/changelog.md +384 -2
  172. package/docs/comparison.md +2 -2
  173. package/docs/components/avatar.md +5 -0
  174. package/docs/components/banner.md +117 -187
  175. package/docs/components/breadcrumbs.md +9 -6
  176. package/docs/components/button.md +22 -0
  177. package/docs/components/card.md +74 -28
  178. package/docs/components/checkbox.md +9 -10
  179. package/docs/components/dialog.md +83 -32
  180. package/docs/components/expander.md +198 -435
  181. package/docs/components/icon.md +11 -17
  182. package/docs/components/input-autocomplete.md +152 -52
  183. package/docs/components/input-date.md +175 -148
  184. package/docs/components/input-time.md +81 -38
  185. package/docs/components/input.md +343 -349
  186. package/docs/components/loader.md +2 -1
  187. package/docs/components/menu.md +35 -6
  188. package/docs/components/panel.md +18 -0
  189. package/docs/components/progress.md +83 -49
  190. package/docs/components/radio.md +39 -43
  191. package/docs/components/select-faceted.md +54 -7
  192. package/docs/components/select.md +390 -386
  193. package/docs/components/slider.md +136 -19
  194. package/docs/components/steps.md +6 -3
  195. package/docs/components/switch.md +8 -9
  196. package/docs/components/tabs.md +110 -104
  197. package/docs/components/text.md +110 -86
  198. package/docs/components/title.md +47 -33
  199. package/docs/components/toaster.md +242 -84
  200. package/docs/components/tooltip.md +204 -113
  201. package/docs/install-config.md +461 -96
  202. package/docs/packages/plot.md +228 -143
  203. package/docs/theming.md +29 -13
  204. package/package.json +43 -4
  205. package/theme-antithesis-license.md +66 -0
@@ -1,7 +1,6 @@
1
1
  import type { BaseProps, OptionPresentationProps, ToneScope } from '../general_types';
2
2
  import type { IconShape } from '../elements/a-icon.shapes';
3
3
  import { type MenuProps } from './Menu';
4
- import './select-parts.css';
5
4
  /** The type an option `value` may take: `string`, `number`, or `boolean`. Selection
6
5
  * compares values with `===`. Object-shaped values are out of scope; give the option a
7
6
  * stable primitive `value` and read the object back off `attrs.option` (or, in
@@ -36,7 +35,8 @@ export interface SelectOption<V extends OptionValue = string> extends OptionPres
36
35
  /** Tooltip for this option's row — a string or any node. In a `multiple`
37
36
  * select with `selectAll`, a row with no `tooltip` falls back to a default
38
37
  * hint for the Alt/Option-click "select only this" accelerator; set `tooltip`
39
- * to override that, or `''` to suppress it. */
38
+ * to override that, or `''` to suppress it. Hovering a row reveals the default
39
+ * shortcut hint; moving to another row restarts its delay. */
40
40
  tooltip?: React.ReactNode;
41
41
  /** Additional application data. Read it in `renderOption`. */
42
42
  [key: string]: unknown;
@@ -96,9 +96,9 @@ export interface EmptyState {
96
96
  export interface TriggerState<V extends OptionValue = string> {
97
97
  /** Whether the menu is open — use it for `aria-expanded` and a chevron. */
98
98
  open: boolean;
99
- /** The current selection: a single value (single), an array (`multiple`), or
100
- * `undefined` when nothing is chosen. */
101
- value: V | V[] | undefined;
99
+ /** The current selection: a value or `null` in single mode, an array in
100
+ * multiple mode. An empty array means no multiple selection. */
101
+ value: V | V[] | null;
102
102
  /** The resolved option objects for the current selection (empty when none).
103
103
  * `selected.length` is the multi-select count. */
104
104
  selected: SelectOption<V>[];
@@ -169,9 +169,18 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
169
169
  icon?: IconShape;
170
170
  /** Content before the default trigger's value, such as a key prefix
171
171
  * before the value. It replaces the icon derived from `icon`. Include an
172
- * `<Icon>` in this content when both are needed. Ignored by `renderTrigger`. */
172
+ * `<Icon>` in this content when both are needed. Hidden from assistive
173
+ * technologies. Include any meaningful prefix in `label` or `aria-label`.
174
+ * Ignored by `renderTrigger`. */
173
175
  leading?: React.ReactNode;
174
- /** Field label, above the trigger. */
176
+ /** Dim the default trigger's leading content and chevron at rest. They brighten
177
+ * on hover or focus. Ignored by `renderTrigger`.
178
+ * @defaultValue true */
179
+ dimActions?: boolean;
180
+ /** Visible field label and accessible name for the default trigger. If omitted,
181
+ * provide `aria-label` or `aria-labelledby` that identifies the field.
182
+ * Leading content and the chevron are hidden from assistive technologies and
183
+ * do not label the trigger. */
175
184
  label?: string;
176
185
  /** Helper text under the field. */
177
186
  hint?: string;
@@ -196,10 +205,14 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
196
205
  * option's own `toneScope` wins.
197
206
  * @defaultValue 'all' */
198
207
  toneScope?: ToneScope;
199
- /** Add a search field at the top of the menu that filters the options as you
200
- * type. `true` uses the built-in matcher — a case-insensitive substring of the
201
- * option's **value / label / hint**. Pass a **function** `(option, query) =>
202
- * boolean` for custom matching (called per option; return `true` to keep it). */
208
+ /** Add a search field that filters option values, labels, and hints.
209
+ * `true` uses case-insensitive substring matching. A space in the trimmed
210
+ * query matches a run of whitespace. Built-in row text highlights matches.
211
+ * A custom `(option, query) => boolean` receives the trimmed query and returns
212
+ * whether to keep the option, without automatic highlighting. It runs once
213
+ * per option on each render, including for an empty query. Rows, empty content,
214
+ * and filtered Select all use the same results. A query flattens groups and
215
+ * submenus into grouped results. Closing the popup resets the query. */
203
216
  filter?: boolean | ((option: SelectOption<V>, query: string) => boolean);
204
217
  /** `multiple` only: shows a "Select all" row that toggles every enabled option,
205
218
  * or only the visible options when a filter query is active. Its checkbox is
@@ -211,7 +224,7 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
211
224
  * @defaultValue Select all */
212
225
  selectAllLabel?: string;
213
226
  /** Add a "Clear" row pinned in the menu **footer** that empties the selection
214
- * (single → none, multiple → `[]`). Shown only while something is selected, so
227
+ * (single → `null`, multiple → `[]`). Shown only while something is selected, so
215
228
  * it never scrolls away in a long or filtered list. */
216
229
  clearable?: boolean;
217
230
  /** Label for the `clearable` footer row.
@@ -234,15 +247,15 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
234
247
  * A, B, C` (labels comma-joined) in place of the bare `3 selected`. Applies
235
248
  * to the multi-count case only: `All` stays `All`, a single pick stays its
236
249
  * own label, and an empty selection stays the `placeholder`. The list flows
237
- * into the Button label, so it ellipsizes at the field's width when long
250
+ * into the default trigger's value, so it ellipsizes at the field's width when long
238
251
  * (`3 selected: Engineering, Des… `). `renderSummary` overrides this. */
239
252
  verbose?: boolean;
240
253
  /** `multiple` only: build the trigger's selection summary text yourself,
241
254
  * replacing the built-in "`All` / one label / `N selected`" logic. Receives
242
255
  * the resolved selected options (`selected.length` is the count) and runs only
243
256
  * while something is selected — an empty selection still shows the
244
- * `placeholder`. Return a **string**: it flows into the default trigger's
245
- * Button label, so a long summary ellipsizes at the field's width just
257
+ * `placeholder`. Return a **string**: it becomes the default trigger's
258
+ * value, so a long summary ellipsizes at the field's width just
246
259
  * like a long value (`Engineering, Design, … `). Return `undefined` to fall
247
260
  * back to the default for that case (e.g. customize only the count, keeping
248
261
  * the single-label case built-in). For rich content (chips, multiple nodes)
@@ -271,7 +284,7 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
271
284
  }
272
285
  /**
273
286
  * `<Select>` props. `selection` discriminates the value shape: single mode
274
- * (`value: string`) or `multiple` (`value: string[]`).
287
+ * (`value: V | null`) or `multiple` (`value: V[]`).
275
288
  */
276
289
  export type SelectProps<V extends OptionValue = string> = SelectCommonProps<V> & ({
277
290
  /** Selection mode. `'single'` (the default) keeps `value` a single value and
@@ -279,27 +292,31 @@ export type SelectProps<V extends OptionValue = string> = SelectCommonProps<V> &
279
292
  * array value.
280
293
  * @defaultValue single */
281
294
  selection?: 'single';
282
- /** Controlled value: the selected option's `value`. Update it through
283
- * `onValueChange`. Leave it undefined for uncontrolled use. */
284
- value?: V;
285
- /** Initial selected option value for uncontrolled use. */
286
- defaultValue?: V;
287
- /** Fires after the selection changes, with the new value and a
288
- * `{ value, option }` snapshot. Select has no discrete element state, so
289
- * there is no cancelable `onStateChange` (see the Input event-model note). */
290
- onValueChange?: (value: V, attrs: SelectChangeAttrs<V>) => void;
295
+ /** Controlled option value. Use `null` for an empty selection; clearing
296
+ * to `null` keeps the Select controlled. Omit or pass `undefined` for
297
+ * uncontrolled use. Empty strings, `0`, and `false` remain option values. */
298
+ value?: V | null;
299
+ /** Initial option value for uncontrolled use. `null` starts empty. */
300
+ defaultValue?: V | null;
301
+ /** Reports the new value and a `{ value, option }` snapshot after a pick.
302
+ * Clear reports `null` with `{ all: true, selected: false }`.
303
+ * Narrow on `'all' in attrs` before reading `option`.
304
+ * Update `value` to accept a controlled change. There is no cancelable
305
+ * `onStateChange`; see the Input event-model note. */
306
+ onValueChange?: (value: V | null, attrs: SelectChangeAttrs<V>) => void;
291
307
  } | {
292
308
  /** Multi-select: checkboxes on every row, the menu stays open while
293
309
  * toggling, the field shows an "N selected" count, and `value` is an array. */
294
310
  selection: 'multiple';
295
- /** Controlled values — the `value`s of the selected options (see the
296
- * single-select `value` note). */
311
+ /** Controlled option values. Use `[]` for an empty selection. Omit or
312
+ * pass `undefined` for uncontrolled use. */
297
313
  value?: V[];
298
314
  /** Initial values (option `value`s) for the uncontrolled case. */
299
315
  defaultValue?: V[];
300
- /** Fires after any toggle, with the new value array and a `{ value, option,
301
- * selected }` snapshot of the row that changed (or `{ all: true }` for the
302
- * Select-all row). */
316
+ /** Reports the new value array and a `{ value, option, selected }` snapshot
317
+ * after a row toggle. Select all and Clear report `{ all: true, selected }`
318
+ * without a single option. Narrow on `'all' in attrs` before reading `option`.
319
+ * Update `value` to accept a controlled change. */
303
320
  onValueChange?: (value: V[], attrs: SelectChangeAttrs<V>) => void;
304
321
  });
305
322
  /** Rolled-up selection of a group / submenu subtree: `'none'` / `'all'` of the
@@ -337,8 +354,8 @@ export type SelectedItem<V extends OptionValue = string> = SelectedOption<V> | S
337
354
  *
338
355
  * A pure function of `(options, values)` — it needs no `Select` instance and reads
339
356
  * nothing off the change event, so it behaves identically in controlled and
340
- * uncontrolled code. Pass the current `value` (a string, an array, or `undefined`)
341
- * and render a grouped summary, drive section indicators, or diff picks.
357
+ * uncontrolled code. Pass the current `value` (an option value, an array,
358
+ * `null`, or `undefined`) and render a grouped summary, drive section indicators, or diff picks.
342
359
  *
343
360
  * A value that appears under more than one section marks the leaf in *every* place it
344
361
  * occurs (selection is value-keyed), mirroring how the menu itself renders it.
@@ -350,12 +367,12 @@ export type SelectedItem<V extends OptionValue = string> = SelectedOption<V> | S
350
367
  * // { value: 'eng-fe', label: 'Frontend', selected: false }, … ] }
351
368
  * ```
352
369
  */
353
- export declare function optionsWithSelection<V extends OptionValue = string>(options: SelectItem<V>[], values: V | V[] | undefined): SelectedItem<V>[];
370
+ export declare function optionsWithSelection<V extends OptionValue = string>(options: SelectItem<V>[], values: V | V[] | null | undefined): SelectedItem<V>[];
354
371
  /**
355
372
  * `<Select>` lets people choose one or more options from a dropdown. It uses a
356
- * `<Button>` as its trigger and a `<Menu>` for its options. `selection` sets behavior:
357
- * `'single'` (default; `value` is a string, menu closes on pick) or `'multiple'`
358
- * (checkboxes, `value` is a string array, menu stays open while toggling, the
373
+ * `<Input button>` as its trigger and a `<Menu>` for its options. `selection` sets behavior:
374
+ * `'single'` (default; an option value or `null`, menu closes on pick) or `'multiple'`
375
+ * (checkboxes, an option-value array, menu stays open while toggling, the
359
376
  * field shows an "N selected" count). For single-select, `indicator` picks the
360
377
  * per-row mark: `'none'` (tint only, default), `'check'` (trailing checkmark), or
361
378
  * `'radio'` (leading radio).
@@ -2,15 +2,14 @@ import { Fragment, jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
2
  import { useState } from "../jsx-runtime";
3
3
  import { ISOLATE_HINT, ISOLATE_HINT_DELAY, optionPresentationAttrs } from "../anta_helpers";
4
4
  import { normalizeOpt, matchQueryRegex, matchesQuery, highlight } from "./select-options";
5
+ import { prepareSelectOptions } from "./select-tree";
5
6
  import { Input } from "./Input";
6
- import { Button } from "./Button";
7
7
  import { Icon } from "./Icon";
8
8
  import { Menu } from "./Menu";
9
9
  import { MenuItem } from "./MenuItem";
10
10
  import { MenuGroup } from "./MenuGroup";
11
11
  import { MenuSeparator } from "./MenuSeparator";
12
12
  import { Tooltip } from "./Tooltip";
13
- import "./select-parts.css";
14
13
  function optionsWithSelection(options, values) {
15
14
  const set = new Set(values == null ? [] : Array.isArray(values) ? values : [values]);
16
15
  const state = (on, total) => on === 0 ? "none" : on === total ? "all" : "some";
@@ -48,6 +47,7 @@ const Select = (props) => {
48
47
  placeholder,
49
48
  icon,
50
49
  leading,
50
+ dimActions = true,
51
51
  label,
52
52
  hint,
53
53
  size,
@@ -73,30 +73,22 @@ const Select = (props) => {
73
73
  ...rest
74
74
  } = props;
75
75
  const multiple = selection === "multiple";
76
- const statusColor = status && status !== "neutral" ? `var(--text-2-${status})` : void 0;
77
76
  const mark = multiple ? "checkbox" : indicator ?? "none";
78
77
  const menuItemIndicator = mark === "none" ? void 0 : mark;
79
78
  const emit = onValueChange;
80
79
  const controlled = value !== void 0;
81
- const [internal, setInternal] = useState(defaultValue);
80
+ const [internal, setInternal] = useState(defaultValue ?? (multiple ? [] : null));
82
81
  const currentRaw = controlled ? value : internal;
83
82
  const [open, setOpen] = useState(false);
84
83
  const [query, setQuery] = useState("");
85
84
  const popupLabel = `${label ?? rest["aria-label"] ?? "Select"} options`;
86
- const isSubmenu = (it) => typeof it === "object" && Array.isArray(it.submenu);
87
- const isGroup = (it) => typeof it === "object" && Array.isArray(it.options);
88
- const collectLeaves = (items, group, disabled2, out) => {
89
- for (const raw of items) {
90
- if (typeof raw !== "string" && isSubmenu(raw)) collectLeaves(raw.submenu, raw.label, disabled2 || !!raw.disabled, out);
91
- else if (typeof raw !== "string" && isGroup(raw)) collectLeaves(raw.options, raw.label, disabled2 || !!raw.disabled, out);
92
- else {
93
- const o = normalizeOpt(raw);
94
- out.push({ opt: o, disabled: disabled2 || !!o.disabled, group });
95
- }
96
- }
97
- };
98
- const allLeaves = [];
99
- collectLeaves(options, void 0, false, allLeaves);
85
+ const filtering = filter !== void 0 && filter !== false;
86
+ const q = query.trim();
87
+ const queryRegex = filtering && typeof filter !== "function" ? matchQueryRegex(q) : null;
88
+ const prune = typeof filter === "function" || filtering && !!q;
89
+ const matches = (o) => typeof filter === "function" ? filter(o, q) : matchesQuery(o, queryRegex);
90
+ const { tree, allLeaves, visibleLeaves } = prepareSelectOptions(options, prune ? matches : void 0);
91
+ const flattening = filtering && !!q;
100
92
  const seenValues = /* @__PURE__ */ new Set();
101
93
  for (const l of allLeaves) {
102
94
  const key = String(l.opt.value);
@@ -105,13 +97,6 @@ const Select = (props) => {
105
97
  seenValues.add(key);
106
98
  }
107
99
  const byValue = new Map(allLeaves.map((l) => [l.opt.value, l.opt]));
108
- const filtering = filter !== void 0 && filter !== false;
109
- const q = query.trim();
110
- const queryRe = filtering && typeof filter !== "function" ? matchQueryRegex(q) : null;
111
- const matches = (o) => typeof filter === "function" ? filter(o, q) : matchesQuery(o, queryRe);
112
- const prune = typeof filter === "function" || filtering && !!q;
113
- const visibleLeaves = prune ? allLeaves.filter((l) => matches(l.opt)) : allLeaves;
114
- const flattening = filtering && !!q;
115
100
  const selectedValues = Array.isArray(currentRaw) ? currentRaw : currentRaw != null ? [currentRaw] : [];
116
101
  const isSelected = (v) => selectedValues.includes(v);
117
102
  const selectedOptions = selectedValues.map((v) => byValue.get(v)).filter(Boolean);
@@ -160,7 +145,7 @@ const Select = (props) => {
160
145
  emit?.(next, { all: true, selected: !allSelected });
161
146
  };
162
147
  const clear = () => {
163
- const next = multiple ? [] : void 0;
148
+ const next = multiple ? [] : null;
164
149
  if (!controlled) setInternal(next);
165
150
  emit?.(next, { all: true, selected: false });
166
151
  };
@@ -180,8 +165,8 @@ const Select = (props) => {
180
165
  selectionIndicator: menuItemIndicator,
181
166
  ...ariaSelectable,
182
167
  indicator: customMark ?? void 0,
183
- label: custom ? void 0 : highlight(o.label ?? String(o.value), queryRe),
184
- hint: custom ? void 0 : o.hint ? highlight(o.hint, queryRe) : o.hint,
168
+ label: custom ? void 0 : highlight(o.label ?? String(o.value), queryRegex),
169
+ hint: custom ? void 0 : o.hint ? highlight(o.hint, queryRegex) : o.hint,
185
170
  icon: custom ? void 0 : o.icon,
186
171
  tone: o.tone ?? tone,
187
172
  toneScope: o.toneScope ?? toneScope,
@@ -199,78 +184,65 @@ const Select = (props) => {
199
184
  String(o.value)
200
185
  );
201
186
  };
202
- const renderTree = (items, disabled2) => {
203
- const out = [];
204
- items.forEach((raw, i) => {
205
- if (typeof raw !== "string" && isSubmenu(raw)) {
206
- const dis = disabled2 || !!raw.disabled;
207
- const inner = renderTree(raw.submenu, dis);
208
- if (inner.length)
209
- out.push(
210
- /* @__PURE__ */ jsx(
211
- MenuItem,
212
- {
213
- submenu: true,
214
- label: raw.label,
215
- icon: raw.icon,
216
- disabled: dis || void 0,
217
- "data-menu-open": multiple ? "" : void 0,
218
- children: /* @__PURE__ */ jsx(Menu, { children: inner })
219
- },
220
- `sub-${i}-${raw.label}`
221
- )
222
- );
223
- return;
224
- }
225
- if (typeof raw !== "string" && isGroup(raw)) {
226
- const dis = disabled2 || !!raw.disabled;
227
- const inner = renderTree(raw.options, dis);
228
- if (inner.length) out.push(/* @__PURE__ */ jsx(MenuGroup, { label: raw.label, children: inner }, `grp-${i}-${raw.label}`));
229
- return;
230
- }
231
- const o = normalizeOpt(raw);
232
- if (typeof filter === "function" && !matches(o)) return;
233
- out.push(renderOptionRow(o, disabled2 || !!o.disabled));
234
- });
235
- return out;
236
- };
187
+ const renderTree = (nodes) => nodes.map((node) => {
188
+ if (node.kind === "option") return renderOptionRow(node.opt, node.disabled);
189
+ const inner = renderTree(node.children);
190
+ if (node.kind === "group") return /* @__PURE__ */ jsx(MenuGroup, { label: node.source.label, children: inner }, node.key);
191
+ return /* @__PURE__ */ jsx(
192
+ MenuItem,
193
+ {
194
+ submenu: true,
195
+ label: node.source.label,
196
+ icon: node.source.icon,
197
+ disabled: node.disabled || void 0,
198
+ "data-menu-open": multiple ? "" : void 0,
199
+ children: /* @__PURE__ */ jsx(Menu, { children: inner })
200
+ },
201
+ node.key
202
+ );
203
+ });
237
204
  const renderFlat = () => {
238
- const shown = allLeaves.filter((l) => matches(l.opt));
239
205
  const out = [];
240
- for (let i = 0; i < shown.length; ) {
241
- const label2 = shown[i].group;
206
+ for (let i = 0; i < visibleLeaves.length; ) {
207
+ const label2 = visibleLeaves[i].group;
242
208
  if (label2 === void 0) {
243
- out.push(renderOptionRow(shown[i].opt, shown[i].disabled));
209
+ out.push(renderOptionRow(visibleLeaves[i].opt, visibleLeaves[i].disabled));
244
210
  i++;
245
211
  continue;
246
212
  }
247
213
  const rows = [];
248
214
  const start = i;
249
- while (i < shown.length && shown[i].group === label2) {
250
- rows.push(renderOptionRow(shown[i].opt, shown[i].disabled));
215
+ while (i < visibleLeaves.length && visibleLeaves[i].group === label2) {
216
+ rows.push(renderOptionRow(visibleLeaves[i].opt, visibleLeaves[i].disabled));
251
217
  i++;
252
218
  }
253
219
  out.push(/* @__PURE__ */ jsx(MenuGroup, { label: label2, children: rows }, `flat-${start}-${label2}`));
254
220
  }
255
221
  return out;
256
222
  };
257
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
258
- renderTrigger ? renderTrigger({ open, value: currentRaw, selected: selectedOptions, disabled: !!disabled, icon }) : /* @__PURE__ */ jsxs(
259
- Button,
223
+ const triggerLeading = leading ?? (icon ? /* @__PURE__ */ jsx(Icon, { shape: icon }) : void 0);
224
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
225
+ renderTrigger ? renderTrigger({ open, value: currentRaw, selected: selectedOptions, disabled: !!disabled, icon }) : /* @__PURE__ */ jsx(
226
+ Input,
260
227
  {
228
+ button: true,
229
+ dimActions,
230
+ label,
231
+ hint,
232
+ value: display,
233
+ placeholder,
234
+ leading: triggerLeading != null ? /* @__PURE__ */ jsx("a-select-leading", { "aria-hidden": "true", children: triggerLeading }) : void 0,
261
235
  disabled,
262
236
  size,
237
+ status,
238
+ statusIcon,
263
239
  round,
264
- "aria-label": typeof label === "string" || typeof label === "number" ? String(label) : void 0,
265
- "aria-invalid": status === "critical" ? "true" : void 0,
240
+ className,
241
+ style,
266
242
  "aria-haspopup": filtering ? "dialog" : "menu",
267
243
  "aria-expanded": open ? "true" : "false",
268
- ...rest,
269
- children: [
270
- (leading ?? icon) && /* @__PURE__ */ jsx("a-select-leading", { "aria-hidden": "true", children: leading ?? /* @__PURE__ */ jsx(Icon, { shape: icon }) }),
271
- /* @__PURE__ */ jsx("a-button-label", { "data-placeholder": !display ? "" : void 0, children: display || placeholder }),
272
- /* @__PURE__ */ jsx("a-select-chevron", { open: open ? "" : void 0, "aria-hidden": "true", style: statusColor ? { color: statusColor } : void 0, children: /* @__PURE__ */ jsx(Icon, { shape: "chevron-down" }) })
273
- ]
244
+ trailing: /* @__PURE__ */ jsx("a-select-chevron", { open: open ? "" : void 0, "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, { shape: "chevron-down" }) }),
245
+ ...rest
274
246
  }
275
247
  ),
276
248
  /* @__PURE__ */ jsxs(
@@ -315,7 +287,7 @@ const Select = (props) => {
315
287
  ),
316
288
  /* @__PURE__ */ jsx(MenuSeparator, {})
317
289
  ] }),
318
- visibleLeaves.length === 0 ? renderEmpty?.({ query: q }) : flattening ? renderFlat() : renderTree(options, false),
290
+ visibleLeaves.length === 0 ? renderEmpty?.({ query: q }) : flattening ? renderFlat() : renderTree(tree),
319
291
  clearable && selectedValues.length > 0 && // Pinned in the footer so it never scrolls away in a long / filtered list.
320
292
  /* @__PURE__ */ jsxs(Fragment, { children: [
321
293
  /* @__PURE__ */ jsx(MenuSeparator, { slot: "footer" }),
@@ -334,23 +306,6 @@ const Select = (props) => {
334
306
  }
335
307
  )
336
308
  ] });
337
- if (renderTrigger) return content;
338
- const statusGlyph = {
339
- brand: "circle-small-solid",
340
- info: "info",
341
- success: "circle-check",
342
- warning: "warning-triangle",
343
- critical: "warning-diamond"
344
- };
345
- const glyph = statusIcon === void 0 ? status ? statusGlyph[status] : void 0 : statusIcon;
346
- return /* @__PURE__ */ jsxs("a-select-field", { size, status, disabled: disabled ? "" : void 0, class: className, style, children: [
347
- label != null && /* @__PURE__ */ jsx("a-select-label", { children: label }),
348
- content,
349
- hint != null && /* @__PURE__ */ jsxs("a-select-hint", { children: [
350
- glyph && /* @__PURE__ */ jsx(Icon, { shape: glyph, "aria-hidden": "true" }),
351
- hint
352
- ] })
353
- ] });
354
309
  };
355
310
  export {
356
311
  Select,
@@ -2,7 +2,6 @@ import type { BaseProps, ToneScope } from '../general_types';
2
2
  import type { IconShape } from '../elements/a-icon.shapes';
3
3
  import type { OptionState, OptionValue, SelectItem, SelectOption } from './Select';
4
4
  import { type MenuProps } from './Menu';
5
- import './select-parts.css';
6
5
  interface FacetBase {
7
6
  /** The key for this facet's value in the record. `onValueChange` reports it as
8
7
  * `attrs.facet`. It must be unique across `facets`. */
@@ -12,9 +11,13 @@ interface FacetBase {
12
11
  /** Leading icon on the facet's row. */
13
12
  icon?: IconShape;
14
13
  }
15
- /** A per-facet option-list filter (like `Select`'s `filter`): `true` uses the
16
- * built-in case-insensitive substring match on an option's value / label /
17
- * hint; a function `(option, query) => boolean` does custom matching. */
14
+ /** Filter the options within a facet. `true` uses case-insensitive substring
15
+ * matching on the option's value, label, and hint, with trimmed, flexible
16
+ * whitespace. A custom `(option, query) => boolean` receives the original query,
17
+ * including leading and trailing whitespace, in both per-facet and global
18
+ * search. Custom predicates also run for an empty per-facet query. A whitespace-only
19
+ * global query does not activate global results. `false` hides the facet's search
20
+ * field; global search still matches its options with the built-in matcher. */
18
21
  export type FacetFilter = boolean | ((option: SelectOption<OptionValue>, query: string) => boolean);
19
22
  /** Pick **one** option. Value: the chosen option's `value` (or `undefined` when
20
23
  * cleared). Re-picking the selected option clears it. Options are `Select`'s
@@ -10,7 +10,6 @@ import { MenuSeparator } from "./MenuSeparator";
10
10
  import { Tag } from "./Tag";
11
11
  import { Input } from "./Input";
12
12
  import { Tooltip } from "./Tooltip";
13
- import "./select-parts.css";
14
13
  const leavesOf = (items) => {
15
14
  const out = [];
16
15
  for (const it of items) {
@@ -23,7 +22,11 @@ const leavesOf = (items) => {
23
22
  return out;
24
23
  };
25
24
  const isEmpty = (v) => v == null || v === "" || Array.isArray(v) && v.length === 0;
26
- const defaultMatch = (o, query) => matchesQuery(o, matchQueryRegex(query));
25
+ const prepareMatch = (query) => {
26
+ const queryRe = matchQueryRegex(query);
27
+ return (option) => matchesQuery(option, queryRe);
28
+ };
29
+ const matcherFor = (filter, query, preparedMatch) => typeof filter === "function" ? (option) => filter(option, query) : preparedMatch ?? prepareMatch(query);
27
30
  const SelectFaceted = (props) => {
28
31
  const {
29
32
  facets,
@@ -95,10 +98,11 @@ const SelectFaceted = (props) => {
95
98
  const clearAll = () => commit({}, { all: true });
96
99
  const visibleLeavesOf = (facet) => {
97
100
  const leaves = leavesByKey.get(facet.key) ?? [];
98
- if (!facet.filter) return leaves;
101
+ const filter = facet.filter;
102
+ if (!filter) return leaves;
99
103
  const q = queries[facet.key] ?? "";
100
- const match = typeof facet.filter === "function" ? facet.filter : defaultMatch;
101
- return leaves.filter((o) => match(o, q));
104
+ if (typeof filter !== "function" && !q.trim()) return leaves;
105
+ return leaves.filter(matcherFor(filter, q));
102
106
  };
103
107
  const filterHeader = (facet) => facet.filter ? /* @__PURE__ */ jsx("a-select-header", { slot: "header", "data-menu-open": "", children: /* @__PURE__ */ jsx(
104
108
  Input,
@@ -109,7 +113,10 @@ const SelectFaceted = (props) => {
109
113
  placeholder: "Filter\u2026",
110
114
  "aria-label": `Filter ${facet.label}`,
111
115
  "aria-autocomplete": "list",
112
- onInput: (e) => setQueries((s) => ({ ...s, [facet.key]: e.currentTarget.value }))
116
+ onInput: (e) => {
117
+ const query = e.currentTarget.value;
118
+ setQueries((s) => ({ ...s, [facet.key]: query }));
119
+ }
113
120
  }
114
121
  ) }) : null;
115
122
  const optionRow = (facet, opt, keyPrefix = "") => {
@@ -191,9 +198,10 @@ const SelectFaceted = (props) => {
191
198
  ] });
192
199
  };
193
200
  const renderFlatResults = () => {
201
+ const match = prepareMatch(rootQuery);
194
202
  const groups = facets.filter((f) => f.kind === "single" || f.kind === "multiple").map((facet) => {
195
- const match = typeof facet.filter === "function" ? facet.filter : defaultMatch;
196
- return { facet, matched: (leavesByKey.get(facet.key) ?? []).filter((o) => match(o, rootQuery)) };
203
+ const matched = (leavesByKey.get(facet.key) ?? []).filter(matcherFor(facet.filter, rootQuery, match));
204
+ return { facet, matched };
197
205
  }).filter((g) => g.matched.length > 0);
198
206
  return groups.map(({ facet, matched }) => /* @__PURE__ */ jsx(MenuGroup, { label: facet.label, children: matched.map((opt) => optionRow(facet, opt, `${facet.key}:`)) }, facet.key));
199
207
  };
@@ -207,14 +215,17 @@ const SelectFaceted = (props) => {
207
215
  return (
208
216
  // `data-menu-open` keeps the menu open through typing; the value commits on
209
217
  // Enter / blur, not per keystroke.
210
- /* @__PURE__ */ jsx("div", { "data-menu-open": "", style: { padding: "4px" }, children: /* @__PURE__ */ jsx(
218
+ /* @__PURE__ */ jsx("a-select-faceted-text", { "data-menu-open": "", children: /* @__PURE__ */ jsx(
211
219
  Input,
212
220
  {
213
221
  size: "small",
214
222
  value: draft,
215
223
  placeholder: facet.placeholder,
216
224
  "aria-label": facet.label,
217
- onInput: (e) => setDrafts((d) => ({ ...d, [facet.key]: e.currentTarget.value })),
225
+ onInput: (e) => {
226
+ const draft2 = e.currentTarget.value;
227
+ setDrafts((d) => ({ ...d, [facet.key]: draft2 }));
228
+ },
218
229
  onKeyDown: (e) => {
219
230
  if (e.key === "Enter") {
220
231
  e.preventDefault();
@@ -20,18 +20,27 @@ export interface SliderProps extends BaseProps, DOMEventHandlers {
20
20
  /** Visible field label, shown above the rail. A string supplies the slider's
21
21
  * accessible name; give a rich label an explicit `aria-label`. */
22
22
  label?: React.ReactNode;
23
- /** Controlled value. A pair of numbers selects a range. Update it from `onValueChange`. */
23
+ /** Controlled numeric value. A pair selects a range, ordered low to high.
24
+ * Omit or pass `undefined` for uncontrolled use; `0` stays controlled.
25
+ * Runtime `null` is treated as omission; it is not a controlled empty value.
26
+ * Takes precedence over `defaultValue`, including on form reset. Values are
27
+ * clamped to the bounds and rounded to a step measured from `min`.
28
+ * Releasing control retains the last applied value. There is no empty numeric state. */
24
29
  value?: number | SliderRangeValue;
25
- /** Initial uncontrolled value.
26
- * @defaultValue 0 */
30
+ /** Initial uncontrolled value and form-reset baseline. Changes while pristine
31
+ * update the value; after interaction they affect the next reset. Without a
32
+ * default, scalar reset uses `min` and range reset uses `[min, max]`.
33
+ * @defaultValue min */
27
34
  defaultValue?: number | SliderRangeValue;
28
- /** Lowest permitted value.
35
+ /** Lowest permitted value and step origin. Nonfinite values use 0.
29
36
  * @defaultValue 0 */
30
37
  min?: number;
31
- /** Highest permitted value.
38
+ /** Highest permitted value. A lower bound than `min` collapses the range to
39
+ * `min`. Nonfinite values use 100.
32
40
  * @defaultValue 100 */
33
41
  max?: number;
34
- /** Smallest keyboard and drag increment.
42
+ /** Smallest keyboard and drag increment. Nonpositive and nonfinite values
43
+ * use 1. Page keys move by at least one step, or one tenth of the range.
35
44
  * @defaultValue 1 */
36
45
  step?: number;
37
46
  /** Form field name. A range submits two values under this name. */
@@ -43,8 +52,8 @@ export interface SliderProps extends BaseProps, DOMEventHandlers {
43
52
  * @defaultValue 'neutral' */
44
53
  tone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
45
54
  /** Color of the thumb stroke. Pass a named tone or a literal CSS color for a
46
- * one-off custom tone. Omit it to keep the thumb neutral.
47
- * @defaultValue 'neutral' */
55
+ * one-off custom tone. An explicit `neutral` keeps the thumb neutral in every theme.
56
+ * @defaultValue 'neutral' (the Antithesis theme follows `tone`) */
48
57
  thumbTone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
49
58
  /** Size variant. small=24px, medium=28px, large=32px tall.
50
59
  * @defaultValue 'medium' */
@@ -81,9 +90,17 @@ export interface SliderProps extends BaseProps, DOMEventHandlers {
81
90
  trackClick?: 'drag-only' | 'jump';
82
91
  /** Fill the rail outside the selected value or range. */
83
92
  inverted?: boolean;
84
- /** Fires on every keyboard or pointer value change. */
93
+ /** Reports each distinct requested value during a drag and each keyboard step.
94
+ * `onInput` runs first. The snapshot contains the requested value and effective
95
+ * constraints; the element's `value` remains the applied value. Controlled
96
+ * sliders accept by updating `value` and reject by leaving it unchanged.
97
+ * Events are notifications; `preventDefault()` does not veto a value request. */
85
98
  onValueChange?: (event: any, attrs: SliderChangeAttrs<SliderValue>) => void;
86
- /** Fires after a drag ends and after each keyboard value change. */
99
+ /** Reports the final requested value after a drag, cancellation, or capture loss,
100
+ * and after each keyboard step. `onChange` runs first. A drag ending at its
101
+ * starting value is silent. Controlled requests can commit without being accepted.
102
+ * Uncontrolled form reset emits both callbacks when it changes the value;
103
+ * state restoration and application updates are silent. */
87
104
  onValueCommit?: (event: any, attrs: SliderChangeAttrs<SliderValue>) => void;
88
105
  }
89
106
  type TypedSliderProps<T extends SliderValue> = Omit<SliderProps, 'value' | 'defaultValue' | 'onValueChange' | 'onValueCommit'> & {
@@ -97,5 +114,5 @@ type TypedSliderProps<T extends SliderValue> = Omit<SliderProps, 'value' | 'defa
97
114
  * starts a relative drag by default, so the thumb never jumps to the press point.
98
115
  * Requires `@antadesign/anta/elements` on the client.
99
116
  */
100
- export declare const Slider: <T extends SliderValue = number>({ label, value, defaultValue, min: minProp, max: maxProp, step: stepProp, name, disabled, tone, thumbTone, size, trackSize, thumbSize, thumbFill, round, valueDisplay, valuePrefix, valueSuffix, markers, trackClick, inverted, onInput, onChange, onValueChange, onValueCommit, className, style, children, tabIndex, ...rest }: TypedSliderProps<T>) => any;
117
+ export declare const Slider: <T extends SliderValue = number>({ label, value, defaultValue, min: minProp, max: maxProp, step: stepProp, name, disabled, tone, thumbTone, size, trackSize, thumbSize, thumbFill, round, valueDisplay, valuePrefix, valueSuffix, markers, trackClick, inverted, onInput, onChange, onValueChange, onValueCommit, onKeyDown, onPointerDown, onPointerMove, className, style, children, tabIndex, ...rest }: TypedSliderProps<T>) => any;
101
118
  export {};