@antadesign/anta 0.3.34 → 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 (184) 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 -1333
  7. package/dist/components/Banner.d.ts +25 -40
  8. package/dist/components/Banner.js +15 -17
  9. package/dist/components/Button.js +1 -0
  10. package/dist/components/ButtonCopy.js +3 -2
  11. package/dist/components/Calendar.js +13 -13
  12. package/dist/components/Card.d.ts +9 -17
  13. package/dist/components/Card.js +50 -46
  14. package/dist/components/Dialog.d.ts +1 -0
  15. package/dist/components/Dialog.js +16 -10
  16. package/dist/components/Expander.d.ts +6 -21
  17. package/dist/components/Expander.js +24 -23
  18. package/dist/components/Icon.d.ts +8 -14
  19. package/dist/components/Input.d.ts +77 -96
  20. package/dist/components/Input.js +23 -27
  21. package/dist/components/InputAutocomplete.d.ts +29 -10
  22. package/dist/components/InputAutocomplete.js +25 -8
  23. package/dist/components/InputDate.js +2 -2
  24. package/dist/components/InputTime.d.ts +10 -4
  25. package/dist/components/InputTime.js +20 -16
  26. package/dist/components/Loader.d.ts +2 -2
  27. package/dist/components/Menu.d.ts +5 -4
  28. package/dist/components/Menu.js +13 -8
  29. package/dist/components/MenuItem.js +1 -14
  30. package/dist/components/MenuItemCopy.js +2 -2
  31. package/dist/components/Panel.d.ts +3 -1
  32. package/dist/components/Panel.js +17 -11
  33. package/dist/components/Progress.d.ts +21 -23
  34. package/dist/components/Progress.js +13 -9
  35. package/dist/components/RadioGroup.js +6 -8
  36. package/dist/components/{select-parts.css → Select.css} +1 -1
  37. package/dist/components/Select.d.ts +53 -35
  38. package/dist/components/Select.js +53 -97
  39. package/dist/components/SelectFaceted.d.ts +7 -3
  40. package/dist/components/SelectFaceted.js +21 -9
  41. package/dist/components/Slider.d.ts +28 -11
  42. package/dist/components/Slider.js +20 -20
  43. package/dist/components/Steps.css +1 -1
  44. package/dist/components/Steps.js +1 -11
  45. package/dist/components/Tabs.d.ts +17 -20
  46. package/dist/components/Tabs.js +5 -8
  47. package/dist/components/Text.d.ts +55 -36
  48. package/dist/components/Text.js +35 -22
  49. package/dist/components/Title.d.ts +16 -26
  50. package/dist/components/Title.js +2 -1
  51. package/dist/components/Toaster.js +9 -2
  52. package/dist/components/Tooltip.d.ts +10 -15
  53. package/dist/components/copy-props.d.ts +14 -3
  54. package/dist/components/copy-props.js +14 -3
  55. package/dist/components/select-tree.d.ts +24 -0
  56. package/dist/components/select-tree.js +35 -0
  57. package/dist/element-base.d.ts +10 -0
  58. package/dist/element-base.js +15 -0
  59. package/dist/elements/a-banner.css +1 -1
  60. package/dist/elements/a-banner.d.ts +4 -1
  61. package/dist/elements/a-banner.js +22 -112
  62. package/dist/elements/a-button.d.ts +2 -1
  63. package/dist/elements/a-button.js +18 -1
  64. package/dist/elements/a-calendar.d.ts +14 -13
  65. package/dist/elements/a-calendar.js +29 -24
  66. package/dist/elements/a-card.css +1 -1
  67. package/dist/elements/a-card.d.ts +0 -9
  68. package/dist/elements/a-card.js +0 -184
  69. package/dist/elements/a-checkbox.css +1 -1
  70. package/dist/elements/a-copy.css +1 -1
  71. package/dist/elements/a-copy.d.ts +1 -5
  72. package/dist/elements/a-copy.js +129 -108
  73. package/dist/elements/a-dialog.css +1 -1
  74. package/dist/elements/a-dialog.d.ts +1 -1
  75. package/dist/elements/a-dialog.js +66 -194
  76. package/dist/elements/a-expander.css +1 -1
  77. package/dist/elements/a-expander.d.ts +4 -30
  78. package/dist/elements/a-expander.js +85 -344
  79. package/dist/elements/a-icon.d.ts +5 -23
  80. package/dist/elements/a-icon.js +1 -2
  81. package/dist/elements/a-input-time.css +1 -1
  82. package/dist/elements/a-input-time.d.ts +2 -1
  83. package/dist/elements/a-input-time.js +101 -168
  84. package/dist/elements/a-input.css +1 -1
  85. package/dist/elements/a-input.d.ts +10 -8
  86. package/dist/elements/a-input.js +155 -230
  87. package/dist/elements/a-loader.d.ts +5 -8
  88. package/dist/elements/a-loader.js +1 -2
  89. package/dist/elements/a-menu-item.css +1 -1
  90. package/dist/elements/a-menu-item.d.ts +5 -3
  91. package/dist/elements/a-menu-item.js +5 -1
  92. package/dist/elements/a-menu.css +1 -1
  93. package/dist/elements/a-menu.d.ts +5 -7
  94. package/dist/elements/a-menu.js +383 -299
  95. package/dist/elements/a-panel.css +1 -1
  96. package/dist/elements/a-panel.js +19 -37
  97. package/dist/elements/a-progress.css +1 -1
  98. package/dist/elements/a-progress.d.ts +0 -22
  99. package/dist/elements/a-progress.js +0 -100
  100. package/dist/elements/a-radio-group.d.ts +1 -1
  101. package/dist/elements/a-radio-group.js +6 -4
  102. package/dist/elements/a-select-faceted.d.ts +1 -1
  103. package/dist/elements/a-select-faceted.js +1 -1
  104. package/dist/elements/a-select.d.ts +1 -1
  105. package/dist/elements/a-select.js +1 -1
  106. package/dist/elements/a-slider.css +1 -1
  107. package/dist/elements/a-slider.d.ts +11 -3
  108. package/dist/elements/a-slider.js +244 -242
  109. package/dist/elements/a-switch.css +1 -1
  110. package/dist/elements/a-tab.css +1 -1
  111. package/dist/elements/a-tabs.css +1 -1
  112. package/dist/elements/a-tabs.d.ts +1 -1
  113. package/dist/elements/a-tabs.js +6 -4
  114. package/dist/elements/a-tag.css +1 -1
  115. package/dist/elements/a-text.css +1 -1
  116. package/dist/elements/a-text.d.ts +6 -43
  117. package/dist/elements/a-text.js +110 -193
  118. package/dist/elements/a-title.css +1 -1
  119. package/dist/elements/a-toast.css +1 -1
  120. package/dist/elements/a-toast.d.ts +10 -45
  121. package/dist/elements/a-toast.js +80 -66
  122. package/dist/elements/a-toaster.css +1 -1
  123. package/dist/elements/a-toaster.js +9 -44
  124. package/dist/elements/a-tooltip.css +1 -1
  125. package/dist/elements/a-tooltip.d.ts +1 -1
  126. package/dist/elements/a-tooltip.js +142 -136
  127. package/dist/elements/copy-behavior.d.ts +1 -1
  128. package/dist/elements/copy-behavior.js +21 -21
  129. package/dist/elements/index.d.ts +3 -3
  130. package/dist/elements/index.js +3 -7
  131. package/dist/elements/input-focus-modality.d.ts +15 -0
  132. package/dist/elements/input-focus-modality.js +44 -0
  133. package/dist/elements/input-trailing-actions.d.ts +5 -0
  134. package/dist/elements/input-trailing-actions.js +38 -0
  135. package/dist/elements/shadow-aria.d.ts +2 -0
  136. package/dist/elements/shadow-aria.js +2 -1
  137. package/dist/elements/value-input.d.ts +3 -0
  138. package/dist/elements/value-input.js +12 -0
  139. package/dist/general_types.d.ts +103 -96
  140. package/dist/index.d.ts +1 -1
  141. package/dist/input-events.d.ts +4 -0
  142. package/dist/input-events.js +15 -0
  143. package/dist/jsx-runtime.d.ts +70 -23
  144. package/dist/jsx-runtime.js +26 -19
  145. package/dist/native-event-props.d.ts +2 -0
  146. package/dist/native-event-props.js +10 -0
  147. package/dist/reset.css +1 -1
  148. package/dist/theme-antithesis.css +10 -1
  149. package/dist/theme-antune.css +1 -1
  150. package/docs/accessibility.md +17 -3
  151. package/docs/changelog.md +348 -2
  152. package/docs/comparison.md +2 -2
  153. package/docs/components/avatar.md +5 -0
  154. package/docs/components/banner.md +117 -187
  155. package/docs/components/button.md +22 -0
  156. package/docs/components/card.md +74 -28
  157. package/docs/components/checkbox.md +9 -10
  158. package/docs/components/dialog.md +83 -32
  159. package/docs/components/expander.md +198 -435
  160. package/docs/components/icon.md +11 -17
  161. package/docs/components/input-autocomplete.md +152 -52
  162. package/docs/components/input-date.md +175 -148
  163. package/docs/components/input-time.md +81 -38
  164. package/docs/components/input.md +343 -349
  165. package/docs/components/loader.md +2 -1
  166. package/docs/components/menu.md +35 -6
  167. package/docs/components/panel.md +18 -0
  168. package/docs/components/progress.md +83 -49
  169. package/docs/components/radio.md +39 -43
  170. package/docs/components/select-faceted.md +54 -7
  171. package/docs/components/select.md +390 -386
  172. package/docs/components/slider.md +136 -19
  173. package/docs/components/steps.md +2 -1
  174. package/docs/components/switch.md +8 -9
  175. package/docs/components/tabs.md +110 -104
  176. package/docs/components/text.md +110 -86
  177. package/docs/components/title.md +47 -33
  178. package/docs/components/toaster.md +242 -84
  179. package/docs/components/tooltip.md +204 -113
  180. package/docs/install-config.md +183 -26
  181. package/docs/packages/plot.md +170 -148
  182. package/docs/theming.md +7 -0
  183. package/package.json +41 -3
  184. package/theme-antithesis-license.md +66 -0
@@ -35,7 +35,8 @@ export interface SelectOption<V extends OptionValue = string> extends OptionPres
35
35
  /** Tooltip for this option's row — a string or any node. In a `multiple`
36
36
  * select with `selectAll`, a row with no `tooltip` falls back to a default
37
37
  * hint for the Alt/Option-click "select only this" accelerator; set `tooltip`
38
- * 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. */
39
40
  tooltip?: React.ReactNode;
40
41
  /** Additional application data. Read it in `renderOption`. */
41
42
  [key: string]: unknown;
@@ -95,9 +96,9 @@ export interface EmptyState {
95
96
  export interface TriggerState<V extends OptionValue = string> {
96
97
  /** Whether the menu is open — use it for `aria-expanded` and a chevron. */
97
98
  open: boolean;
98
- /** The current selection: a single value (single), an array (`multiple`), or
99
- * `undefined` when nothing is chosen. */
100
- 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;
101
102
  /** The resolved option objects for the current selection (empty when none).
102
103
  * `selected.length` is the multi-select count. */
103
104
  selected: SelectOption<V>[];
@@ -168,9 +169,18 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
168
169
  icon?: IconShape;
169
170
  /** Content before the default trigger's value, such as a key prefix
170
171
  * before the value. It replaces the icon derived from `icon`. Include an
171
- * `<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`. */
172
175
  leading?: React.ReactNode;
173
- /** 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. */
174
184
  label?: string;
175
185
  /** Helper text under the field. */
176
186
  hint?: string;
@@ -195,10 +205,14 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
195
205
  * option's own `toneScope` wins.
196
206
  * @defaultValue 'all' */
197
207
  toneScope?: ToneScope;
198
- /** Add a search field at the top of the menu that filters the options as you
199
- * type. `true` uses the built-in matcher — a case-insensitive substring of the
200
- * option's **value / label / hint**. Pass a **function** `(option, query) =>
201
- * 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. */
202
216
  filter?: boolean | ((option: SelectOption<V>, query: string) => boolean);
203
217
  /** `multiple` only: shows a "Select all" row that toggles every enabled option,
204
218
  * or only the visible options when a filter query is active. Its checkbox is
@@ -210,7 +224,7 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
210
224
  * @defaultValue Select all */
211
225
  selectAllLabel?: string;
212
226
  /** Add a "Clear" row pinned in the menu **footer** that empties the selection
213
- * (single → none, multiple → `[]`). Shown only while something is selected, so
227
+ * (single → `null`, multiple → `[]`). Shown only while something is selected, so
214
228
  * it never scrolls away in a long or filtered list. */
215
229
  clearable?: boolean;
216
230
  /** Label for the `clearable` footer row.
@@ -233,15 +247,15 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
233
247
  * A, B, C` (labels comma-joined) in place of the bare `3 selected`. Applies
234
248
  * to the multi-count case only: `All` stays `All`, a single pick stays its
235
249
  * own label, and an empty selection stays the `placeholder`. The list flows
236
- * 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
237
251
  * (`3 selected: Engineering, Des… `). `renderSummary` overrides this. */
238
252
  verbose?: boolean;
239
253
  /** `multiple` only: build the trigger's selection summary text yourself,
240
254
  * replacing the built-in "`All` / one label / `N selected`" logic. Receives
241
255
  * the resolved selected options (`selected.length` is the count) and runs only
242
256
  * while something is selected — an empty selection still shows the
243
- * `placeholder`. Return a **string**: it flows into the default trigger's
244
- * 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
245
259
  * like a long value (`Engineering, Design, … `). Return `undefined` to fall
246
260
  * back to the default for that case (e.g. customize only the count, keeping
247
261
  * the single-label case built-in). For rich content (chips, multiple nodes)
@@ -270,7 +284,7 @@ export interface SelectCommonProps<V extends OptionValue = string> extends Omit<
270
284
  }
271
285
  /**
272
286
  * `<Select>` props. `selection` discriminates the value shape: single mode
273
- * (`value: string`) or `multiple` (`value: string[]`).
287
+ * (`value: V | null`) or `multiple` (`value: V[]`).
274
288
  */
275
289
  export type SelectProps<V extends OptionValue = string> = SelectCommonProps<V> & ({
276
290
  /** Selection mode. `'single'` (the default) keeps `value` a single value and
@@ -278,27 +292,31 @@ export type SelectProps<V extends OptionValue = string> = SelectCommonProps<V> &
278
292
  * array value.
279
293
  * @defaultValue single */
280
294
  selection?: 'single';
281
- /** Controlled value: the selected option's `value`. Update it through
282
- * `onValueChange`. Leave it undefined for uncontrolled use. */
283
- value?: V;
284
- /** Initial selected option value for uncontrolled use. */
285
- defaultValue?: V;
286
- /** Fires after the selection changes, with the new value and a
287
- * `{ value, option }` snapshot. Select has no discrete element state, so
288
- * there is no cancelable `onStateChange` (see the Input event-model note). */
289
- 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;
290
307
  } | {
291
308
  /** Multi-select: checkboxes on every row, the menu stays open while
292
309
  * toggling, the field shows an "N selected" count, and `value` is an array. */
293
310
  selection: 'multiple';
294
- /** Controlled values — the `value`s of the selected options (see the
295
- * single-select `value` note). */
311
+ /** Controlled option values. Use `[]` for an empty selection. Omit or
312
+ * pass `undefined` for uncontrolled use. */
296
313
  value?: V[];
297
314
  /** Initial values (option `value`s) for the uncontrolled case. */
298
315
  defaultValue?: V[];
299
- /** Fires after any toggle, with the new value array and a `{ value, option,
300
- * selected }` snapshot of the row that changed (or `{ all: true }` for the
301
- * 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. */
302
320
  onValueChange?: (value: V[], attrs: SelectChangeAttrs<V>) => void;
303
321
  });
304
322
  /** Rolled-up selection of a group / submenu subtree: `'none'` / `'all'` of the
@@ -336,8 +354,8 @@ export type SelectedItem<V extends OptionValue = string> = SelectedOption<V> | S
336
354
  *
337
355
  * A pure function of `(options, values)` — it needs no `Select` instance and reads
338
356
  * nothing off the change event, so it behaves identically in controlled and
339
- * uncontrolled code. Pass the current `value` (a string, an array, or `undefined`)
340
- * 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.
341
359
  *
342
360
  * A value that appears under more than one section marks the leaf in *every* place it
343
361
  * occurs (selection is value-keyed), mirroring how the menu itself renders it.
@@ -349,12 +367,12 @@ export type SelectedItem<V extends OptionValue = string> = SelectedOption<V> | S
349
367
  * // { value: 'eng-fe', label: 'Frontend', selected: false }, … ] }
350
368
  * ```
351
369
  */
352
- 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>[];
353
371
  /**
354
372
  * `<Select>` lets people choose one or more options from a dropdown. It uses a
355
- * `<Button>` as its trigger and a `<Menu>` for its options. `selection` sets behavior:
356
- * `'single'` (default; `value` is a string, menu closes on pick) or `'multiple'`
357
- * (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
358
376
  * field shows an "N selected" count). For single-select, `indicator` picks the
359
377
  * per-row mark: `'none'` (tint only, default), `'check'` (trailing checkmark), or
360
378
  * `'radio'` (leading radio).
@@ -2,8 +2,8 @@ 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";
@@ -47,6 +47,7 @@ const Select = (props) => {
47
47
  placeholder,
48
48
  icon,
49
49
  leading,
50
+ dimActions = true,
50
51
  label,
51
52
  hint,
52
53
  size,
@@ -72,30 +73,22 @@ const Select = (props) => {
72
73
  ...rest
73
74
  } = props;
74
75
  const multiple = selection === "multiple";
75
- const statusColor = status && status !== "neutral" ? `var(--text-2-${status})` : void 0;
76
76
  const mark = multiple ? "checkbox" : indicator ?? "none";
77
77
  const menuItemIndicator = mark === "none" ? void 0 : mark;
78
78
  const emit = onValueChange;
79
79
  const controlled = value !== void 0;
80
- const [internal, setInternal] = useState(defaultValue);
80
+ const [internal, setInternal] = useState(defaultValue ?? (multiple ? [] : null));
81
81
  const currentRaw = controlled ? value : internal;
82
82
  const [open, setOpen] = useState(false);
83
83
  const [query, setQuery] = useState("");
84
84
  const popupLabel = `${label ?? rest["aria-label"] ?? "Select"} options`;
85
- const isSubmenu = (it) => typeof it === "object" && Array.isArray(it.submenu);
86
- const isGroup = (it) => typeof it === "object" && Array.isArray(it.options);
87
- const collectLeaves = (items, group, disabled2, out) => {
88
- for (const raw of items) {
89
- if (typeof raw !== "string" && isSubmenu(raw)) collectLeaves(raw.submenu, raw.label, disabled2 || !!raw.disabled, out);
90
- else if (typeof raw !== "string" && isGroup(raw)) collectLeaves(raw.options, raw.label, disabled2 || !!raw.disabled, out);
91
- else {
92
- const o = normalizeOpt(raw);
93
- out.push({ opt: o, disabled: disabled2 || !!o.disabled, group });
94
- }
95
- }
96
- };
97
- const allLeaves = [];
98
- 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;
99
92
  const seenValues = /* @__PURE__ */ new Set();
100
93
  for (const l of allLeaves) {
101
94
  const key = String(l.opt.value);
@@ -104,13 +97,6 @@ const Select = (props) => {
104
97
  seenValues.add(key);
105
98
  }
106
99
  const byValue = new Map(allLeaves.map((l) => [l.opt.value, l.opt]));
107
- const filtering = filter !== void 0 && filter !== false;
108
- const q = query.trim();
109
- const queryRe = filtering && typeof filter !== "function" ? matchQueryRegex(q) : null;
110
- const matches = (o) => typeof filter === "function" ? filter(o, q) : matchesQuery(o, queryRe);
111
- const prune = typeof filter === "function" || filtering && !!q;
112
- const visibleLeaves = prune ? allLeaves.filter((l) => matches(l.opt)) : allLeaves;
113
- const flattening = filtering && !!q;
114
100
  const selectedValues = Array.isArray(currentRaw) ? currentRaw : currentRaw != null ? [currentRaw] : [];
115
101
  const isSelected = (v) => selectedValues.includes(v);
116
102
  const selectedOptions = selectedValues.map((v) => byValue.get(v)).filter(Boolean);
@@ -159,7 +145,7 @@ const Select = (props) => {
159
145
  emit?.(next, { all: true, selected: !allSelected });
160
146
  };
161
147
  const clear = () => {
162
- const next = multiple ? [] : void 0;
148
+ const next = multiple ? [] : null;
163
149
  if (!controlled) setInternal(next);
164
150
  emit?.(next, { all: true, selected: false });
165
151
  };
@@ -179,8 +165,8 @@ const Select = (props) => {
179
165
  selectionIndicator: menuItemIndicator,
180
166
  ...ariaSelectable,
181
167
  indicator: customMark ?? void 0,
182
- label: custom ? void 0 : highlight(o.label ?? String(o.value), queryRe),
183
- 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,
184
170
  icon: custom ? void 0 : o.icon,
185
171
  tone: o.tone ?? tone,
186
172
  toneScope: o.toneScope ?? toneScope,
@@ -198,78 +184,65 @@ const Select = (props) => {
198
184
  String(o.value)
199
185
  );
200
186
  };
201
- const renderTree = (items, disabled2) => {
202
- const out = [];
203
- items.forEach((raw, i) => {
204
- if (typeof raw !== "string" && isSubmenu(raw)) {
205
- const dis = disabled2 || !!raw.disabled;
206
- const inner = renderTree(raw.submenu, dis);
207
- if (inner.length)
208
- out.push(
209
- /* @__PURE__ */ jsx(
210
- MenuItem,
211
- {
212
- submenu: true,
213
- label: raw.label,
214
- icon: raw.icon,
215
- disabled: dis || void 0,
216
- "data-menu-open": multiple ? "" : void 0,
217
- children: /* @__PURE__ */ jsx(Menu, { children: inner })
218
- },
219
- `sub-${i}-${raw.label}`
220
- )
221
- );
222
- return;
223
- }
224
- if (typeof raw !== "string" && isGroup(raw)) {
225
- const dis = disabled2 || !!raw.disabled;
226
- const inner = renderTree(raw.options, dis);
227
- if (inner.length) out.push(/* @__PURE__ */ jsx(MenuGroup, { label: raw.label, children: inner }, `grp-${i}-${raw.label}`));
228
- return;
229
- }
230
- const o = normalizeOpt(raw);
231
- if (typeof filter === "function" && !matches(o)) return;
232
- out.push(renderOptionRow(o, disabled2 || !!o.disabled));
233
- });
234
- return out;
235
- };
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
+ });
236
204
  const renderFlat = () => {
237
- const shown = allLeaves.filter((l) => matches(l.opt));
238
205
  const out = [];
239
- for (let i = 0; i < shown.length; ) {
240
- const label2 = shown[i].group;
206
+ for (let i = 0; i < visibleLeaves.length; ) {
207
+ const label2 = visibleLeaves[i].group;
241
208
  if (label2 === void 0) {
242
- out.push(renderOptionRow(shown[i].opt, shown[i].disabled));
209
+ out.push(renderOptionRow(visibleLeaves[i].opt, visibleLeaves[i].disabled));
243
210
  i++;
244
211
  continue;
245
212
  }
246
213
  const rows = [];
247
214
  const start = i;
248
- while (i < shown.length && shown[i].group === label2) {
249
- 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));
250
217
  i++;
251
218
  }
252
219
  out.push(/* @__PURE__ */ jsx(MenuGroup, { label: label2, children: rows }, `flat-${start}-${label2}`));
253
220
  }
254
221
  return out;
255
222
  };
256
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
257
- renderTrigger ? renderTrigger({ open, value: currentRaw, selected: selectedOptions, disabled: !!disabled, icon }) : /* @__PURE__ */ jsxs(
258
- 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,
259
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,
260
235
  disabled,
261
236
  size,
237
+ status,
238
+ statusIcon,
262
239
  round,
263
- "aria-label": typeof label === "string" || typeof label === "number" ? String(label) : void 0,
264
- "aria-invalid": status === "critical" ? "true" : void 0,
240
+ className,
241
+ style,
265
242
  "aria-haspopup": filtering ? "dialog" : "menu",
266
243
  "aria-expanded": open ? "true" : "false",
267
- ...rest,
268
- children: [
269
- (leading ?? icon) && /* @__PURE__ */ jsx("a-select-leading", { "aria-hidden": "true", children: leading ?? /* @__PURE__ */ jsx(Icon, { shape: icon }) }),
270
- /* @__PURE__ */ jsx("a-button-label", { "data-placeholder": !display ? "" : void 0, children: display || placeholder }),
271
- /* @__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" }) })
272
- ]
244
+ trailing: /* @__PURE__ */ jsx("a-select-chevron", { open: open ? "" : void 0, "aria-hidden": "true", children: /* @__PURE__ */ jsx(Icon, { shape: "chevron-down" }) }),
245
+ ...rest
273
246
  }
274
247
  ),
275
248
  /* @__PURE__ */ jsxs(
@@ -314,7 +287,7 @@ const Select = (props) => {
314
287
  ),
315
288
  /* @__PURE__ */ jsx(MenuSeparator, {})
316
289
  ] }),
317
- visibleLeaves.length === 0 ? renderEmpty?.({ query: q }) : flattening ? renderFlat() : renderTree(options, false),
290
+ visibleLeaves.length === 0 ? renderEmpty?.({ query: q }) : flattening ? renderFlat() : renderTree(tree),
318
291
  clearable && selectedValues.length > 0 && // Pinned in the footer so it never scrolls away in a long / filtered list.
319
292
  /* @__PURE__ */ jsxs(Fragment, { children: [
320
293
  /* @__PURE__ */ jsx(MenuSeparator, { slot: "footer" }),
@@ -333,23 +306,6 @@ const Select = (props) => {
333
306
  }
334
307
  )
335
308
  ] });
336
- if (renderTrigger) return content;
337
- const statusGlyph = {
338
- brand: "circle-small-solid",
339
- info: "info",
340
- success: "circle-check",
341
- warning: "warning-triangle",
342
- critical: "warning-diamond"
343
- };
344
- const glyph = statusIcon === void 0 ? status ? statusGlyph[status] : void 0 : statusIcon;
345
- return /* @__PURE__ */ jsxs("a-select-field", { size, status, disabled: disabled ? "" : void 0, class: className, style, children: [
346
- label != null && /* @__PURE__ */ jsx("a-select-label", { children: label }),
347
- content,
348
- hint != null && /* @__PURE__ */ jsxs("a-select-hint", { children: [
349
- glyph && /* @__PURE__ */ jsx(Icon, { shape: glyph, "aria-hidden": "true" }),
350
- hint
351
- ] })
352
- ] });
353
309
  };
354
310
  export {
355
311
  Select,
@@ -11,9 +11,13 @@ interface FacetBase {
11
11
  /** Leading icon on the facet's row. */
12
12
  icon?: IconShape;
13
13
  }
14
- /** A per-facet option-list filter (like `Select`'s `filter`): `true` uses the
15
- * built-in case-insensitive substring match on an option's value / label /
16
- * 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. */
17
21
  export type FacetFilter = boolean | ((option: SelectOption<OptionValue>, query: string) => boolean);
18
22
  /** Pick **one** option. Value: the chosen option's `value` (or `undefined` when
19
23
  * cleared). Re-picking the selected option clears it. Options are `Select`'s
@@ -22,7 +22,11 @@ const leavesOf = (items) => {
22
22
  return out;
23
23
  };
24
24
  const isEmpty = (v) => v == null || v === "" || Array.isArray(v) && v.length === 0;
25
- 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);
26
30
  const SelectFaceted = (props) => {
27
31
  const {
28
32
  facets,
@@ -94,10 +98,11 @@ const SelectFaceted = (props) => {
94
98
  const clearAll = () => commit({}, { all: true });
95
99
  const visibleLeavesOf = (facet) => {
96
100
  const leaves = leavesByKey.get(facet.key) ?? [];
97
- if (!facet.filter) return leaves;
101
+ const filter = facet.filter;
102
+ if (!filter) return leaves;
98
103
  const q = queries[facet.key] ?? "";
99
- const match = typeof facet.filter === "function" ? facet.filter : defaultMatch;
100
- return leaves.filter((o) => match(o, q));
104
+ if (typeof filter !== "function" && !q.trim()) return leaves;
105
+ return leaves.filter(matcherFor(filter, q));
101
106
  };
102
107
  const filterHeader = (facet) => facet.filter ? /* @__PURE__ */ jsx("a-select-header", { slot: "header", "data-menu-open": "", children: /* @__PURE__ */ jsx(
103
108
  Input,
@@ -108,7 +113,10 @@ const SelectFaceted = (props) => {
108
113
  placeholder: "Filter\u2026",
109
114
  "aria-label": `Filter ${facet.label}`,
110
115
  "aria-autocomplete": "list",
111
- 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
+ }
112
120
  }
113
121
  ) }) : null;
114
122
  const optionRow = (facet, opt, keyPrefix = "") => {
@@ -190,9 +198,10 @@ const SelectFaceted = (props) => {
190
198
  ] });
191
199
  };
192
200
  const renderFlatResults = () => {
201
+ const match = prepareMatch(rootQuery);
193
202
  const groups = facets.filter((f) => f.kind === "single" || f.kind === "multiple").map((facet) => {
194
- const match = typeof facet.filter === "function" ? facet.filter : defaultMatch;
195
- 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 };
196
205
  }).filter((g) => g.matched.length > 0);
197
206
  return groups.map(({ facet, matched }) => /* @__PURE__ */ jsx(MenuGroup, { label: facet.label, children: matched.map((opt) => optionRow(facet, opt, `${facet.key}:`)) }, facet.key));
198
207
  };
@@ -206,14 +215,17 @@ const SelectFaceted = (props) => {
206
215
  return (
207
216
  // `data-menu-open` keeps the menu open through typing; the value commits on
208
217
  // Enter / blur, not per keystroke.
209
- /* @__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(
210
219
  Input,
211
220
  {
212
221
  size: "small",
213
222
  value: draft,
214
223
  placeholder: facet.placeholder,
215
224
  "aria-label": facet.label,
216
- 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
+ },
217
229
  onKeyDown: (e) => {
218
230
  if (e.key === "Enter") {
219
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 {};