@antadesign/anta 0.3.12 → 0.3.14
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.
- package/README.md +31 -36
- package/dist/anta_helpers.d.ts +10 -2
- package/dist/anta_helpers.js +5 -0
- package/dist/components/Banner.d.ts +79 -0
- package/dist/components/Banner.js +69 -0
- package/dist/components/Button.d.ts +17 -4
- package/dist/components/Button.js +8 -0
- package/dist/components/InputDate.d.ts +9 -1
- package/dist/components/InputDate.js +4 -1
- package/dist/components/Menu.d.ts +6 -5
- package/dist/components/Select.d.ts +81 -51
- package/dist/components/Select.js +21 -9
- package/dist/components/SelectFaceted.d.ts +21 -16
- package/dist/components/SelectFaceted.js +4 -4
- package/dist/components/SelectFaceted.module.css +1 -1
- package/dist/components/Text.d.ts +2 -2
- package/dist/components/Title.d.ts +2 -2
- package/dist/components/Toaster.d.ts +48 -0
- package/dist/components/Toaster.js +56 -0
- package/dist/components/Tooltip.d.ts +1 -1
- package/dist/components/select-options.d.ts +10 -5
- package/dist/components/select-options.js +1 -1
- package/dist/elements/a-banner.css +1 -0
- package/dist/elements/a-banner.d.ts +10 -0
- package/dist/elements/a-banner.js +141 -0
- package/dist/elements/a-button.css +1 -1
- package/dist/elements/a-checkbox.css +1 -1
- package/dist/elements/a-expander.css +1 -1
- package/dist/elements/a-expander.js +1 -0
- package/dist/elements/a-input-time.css +1 -1
- package/dist/elements/a-input.css +1 -1
- package/dist/elements/a-input.js +2 -2
- package/dist/elements/a-menu-item.css +1 -1
- package/dist/elements/a-menu-item.js +6 -1
- package/dist/elements/a-menu.css +1 -1
- package/dist/elements/a-menu.d.ts +6 -2
- package/dist/elements/a-menu.js +67 -28
- package/dist/elements/a-radio-group.css +1 -1
- package/dist/elements/a-radio-group.d.ts +1 -0
- package/dist/elements/a-radio-group.js +11 -2
- package/dist/elements/a-radio.css +1 -1
- package/dist/elements/a-tabs.css +1 -1
- package/dist/elements/a-tabs.d.ts +1 -0
- package/dist/elements/a-tabs.js +35 -6
- package/dist/elements/a-tag.css +1 -1
- package/dist/elements/a-text.css +1 -1
- package/dist/elements/a-title.css +1 -1
- package/dist/elements/a-toast.css +1 -0
- package/dist/elements/a-toast.d.ts +70 -0
- package/dist/elements/a-toast.js +283 -0
- package/dist/elements/a-toaster.css +1 -0
- package/dist/elements/a-toaster.d.ts +30 -0
- package/dist/elements/a-toaster.js +98 -0
- package/dist/elements/a-tooltip.js +1 -1
- package/dist/elements/index.d.ts +1 -0
- package/dist/elements/index.js +3 -0
- package/dist/general_types.d.ts +52 -9
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/jsx-runtime.d.ts +3 -1
- package/dist/reset.css +1 -1
- package/dist/theme-anta.css +1 -0
- package/dist/toaster.d.ts +99 -0
- package/dist/toaster.js +100 -0
- package/dist/tokens.css +1 -1
- package/package.json +2 -1
- package/dist/components/Card.module.css +0 -35
- package/dist/components/Progress.module.css +0 -0
- package/dist/components/Radio.d.ts +0 -37
- package/dist/components/Radio.js +0 -33
- package/dist/components/Tab.d.ts +0 -37
- package/dist/components/Tab.js +0 -5
- package/dist/components/Tabs.module.css +0 -1
- package/dist/components/Text.module.css +0 -0
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import type { BaseProps } from '../general_types';
|
|
2
2
|
import type { IconShape } from '../elements/a-icon.shapes';
|
|
3
3
|
import { type MenuProps } from './Menu';
|
|
4
|
+
/** The type an option `value` may take: `string`, `number`, or `boolean`. Selection
|
|
5
|
+
* compares values with `===`. Object-shaped values are out of scope; give the option a
|
|
6
|
+
* stable primitive `value` and read the object back off `attrs.option` (or, in
|
|
7
|
+
* `SelectFaceted`, use a `custom` facet). */
|
|
8
|
+
export type OptionValue = string | number | boolean;
|
|
4
9
|
/** One option in a `<Select>`. Pass a bare string as shorthand for
|
|
5
10
|
* `{ value: s, label: s }`. Carries an index signature so you can attach
|
|
6
11
|
* arbitrary fields (a `ranAt` date, a `status`, …) and read them back in
|
|
7
|
-
* `renderOption`; the built-in filter still matches on `value`/`label`/`hint`.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
* `renderOption`; the built-in filter still matches on `value`/`label`/`hint`.
|
|
13
|
+
*
|
|
14
|
+
* Generic in the value type `V` (defaults to `string`): `Select` infers `V` from your
|
|
15
|
+
* `options`, so `{ value: 365 }` round-trips as `number` through `onValueChange`. */
|
|
16
|
+
export interface SelectOption<V extends OptionValue = string> {
|
|
17
|
+
/** The option's value (`V`) — its identity, what `value` / `defaultValue` name, and
|
|
18
|
+
* what `onValueChange` reports. Unique across the whole `options` tree (selection is
|
|
11
19
|
* value-keyed and global across groups / submenus). */
|
|
12
|
-
value:
|
|
20
|
+
value: V;
|
|
13
21
|
/** Visible label. Defaults to `value`. */
|
|
14
22
|
label?: string;
|
|
15
23
|
/** Secondary text under the label (the option row's `hint`). */
|
|
@@ -32,11 +40,11 @@ export interface SelectOption {
|
|
|
32
40
|
/** A titled group of options rendered **inline** under a heading (like `MenuGroup`).
|
|
33
41
|
* Selection stays global — a group only organizes; its heading isn't selectable.
|
|
34
42
|
* `disabled` cascades to every descendant. Nest groups / submenus freely. */
|
|
35
|
-
export interface SelectGroup {
|
|
43
|
+
export interface SelectGroup<V extends OptionValue = string> {
|
|
36
44
|
/** The section heading (non-interactive). */
|
|
37
45
|
label: string;
|
|
38
46
|
/** The grouped items — options, or further groups / submenus. */
|
|
39
|
-
options: SelectItem[];
|
|
47
|
+
options: SelectItem<V>[];
|
|
40
48
|
/** Disable the whole group (cascades to all descendants). */
|
|
41
49
|
disabled?: boolean;
|
|
42
50
|
}
|
|
@@ -44,13 +52,13 @@ export interface SelectGroup {
|
|
|
44
52
|
* Navigation only — the parent row opens the submenu and is never itself selectable.
|
|
45
53
|
* While a filter query is active the tree flattens and a submenu collapses into a
|
|
46
54
|
* group (its `label` becomes the heading). `disabled` cascades to descendants. */
|
|
47
|
-
export interface SelectSubmenu {
|
|
55
|
+
export interface SelectSubmenu<V extends OptionValue = string> {
|
|
48
56
|
/** The parent row's label — and the group heading when filtering flattens it. */
|
|
49
57
|
label: string;
|
|
50
58
|
/** Leading icon on the parent row. */
|
|
51
59
|
icon?: IconShape;
|
|
52
60
|
/** The submenu's items — options, or further groups / submenus. */
|
|
53
|
-
submenu: SelectItem[];
|
|
61
|
+
submenu: SelectItem<V>[];
|
|
54
62
|
/** Disable the whole branch (cascades to all descendants). */
|
|
55
63
|
disabled?: boolean;
|
|
56
64
|
}
|
|
@@ -58,13 +66,13 @@ export interface SelectSubmenu {
|
|
|
58
66
|
* inline `SelectGroup`, or a flyout `SelectSubmenu`. Discriminated by shape — an
|
|
59
67
|
* `options` array is a group, a `submenu` array is a submenu, else it's an option.
|
|
60
68
|
* (`options` / `submenu` are therefore reserved keys on an option object.) */
|
|
61
|
-
export type SelectItem = string | SelectOption | SelectGroup | SelectSubmenu
|
|
69
|
+
export type SelectItem<V extends OptionValue = string> = string | SelectOption<V> | SelectGroup<V> | SelectSubmenu<V>;
|
|
62
70
|
/** Per-row snapshot passed to `renderOption` / `renderIndicator`. Everything here
|
|
63
71
|
* is known at render time; the combobox "active" cursor is deliberately absent
|
|
64
72
|
* (it's a live element state the DOM owns, not a render-time value). */
|
|
65
|
-
export interface OptionState {
|
|
73
|
+
export interface OptionState<V extends OptionValue = string> {
|
|
66
74
|
/** The option's value. */
|
|
67
|
-
value:
|
|
75
|
+
value: V;
|
|
68
76
|
/** Whether this row is currently selected. */
|
|
69
77
|
selected: boolean;
|
|
70
78
|
/** Whether this row is disabled. */
|
|
@@ -81,15 +89,15 @@ export interface EmptyState {
|
|
|
81
89
|
}
|
|
82
90
|
/** Snapshot passed to `renderTrigger` so a custom trigger can reflect the current
|
|
83
91
|
* selection and open state. */
|
|
84
|
-
export interface TriggerState {
|
|
92
|
+
export interface TriggerState<V extends OptionValue = string> {
|
|
85
93
|
/** Whether the menu is open — use it for `aria-expanded` and a chevron. */
|
|
86
94
|
open: boolean;
|
|
87
|
-
/** The current selection: a
|
|
95
|
+
/** The current selection: a single value (single), an array (`multiple`), or
|
|
88
96
|
* `undefined` when nothing is chosen. */
|
|
89
|
-
value:
|
|
97
|
+
value: V | V[] | undefined;
|
|
90
98
|
/** The resolved option objects for the current selection (empty when none).
|
|
91
99
|
* `selected.length` is the multi-select count. */
|
|
92
|
-
selected: SelectOption[];
|
|
100
|
+
selected: SelectOption<V>[];
|
|
93
101
|
/** Whether the whole select is disabled. */
|
|
94
102
|
disabled: boolean;
|
|
95
103
|
/** The `icon` shape passed to `Select`, if any — hand it to your trigger
|
|
@@ -102,12 +110,12 @@ export interface TriggerState {
|
|
|
102
110
|
* row, or the `clearable` "Clear" footer) carries `all: true` instead. **Always
|
|
103
111
|
* narrow on `'all' in attrs` before reading `option`** — the `all` variant fires
|
|
104
112
|
* for single-select too (via `clearable`), not just multiple. */
|
|
105
|
-
export type SelectChangeAttrs = {
|
|
113
|
+
export type SelectChangeAttrs<V extends OptionValue = string> = {
|
|
106
114
|
/** The option value that changed — the chosen value (single) or the toggled
|
|
107
115
|
* row (multiple). */
|
|
108
|
-
value:
|
|
116
|
+
value: V;
|
|
109
117
|
/** The resolved option object for `value`. */
|
|
110
|
-
option: SelectOption
|
|
118
|
+
option: SelectOption<V>;
|
|
111
119
|
/** Multiple only: whether the change turned selection **on** (true) or off. */
|
|
112
120
|
selected?: boolean;
|
|
113
121
|
} | {
|
|
@@ -121,17 +129,21 @@ export type SelectChangeAttrs = {
|
|
|
121
129
|
/** Props shared by both selection modes, intersected into `SelectProps`. Exported
|
|
122
130
|
* (and kept as an interface intersected — not a union base via `extends`) so its
|
|
123
131
|
* members read as `Select`'s *own* props in the generated docs, not inherited. */
|
|
124
|
-
export interface SelectCommonProps extends Omit<BaseProps, 'children'> {
|
|
132
|
+
export interface SelectCommonProps<V extends OptionValue = string> extends Omit<BaseProps, 'children'> {
|
|
125
133
|
/** The options to choose from — bare strings, `SelectOption` objects, `SelectGroup`s
|
|
126
134
|
* (inline titled sections), or `SelectSubmenu`s (flyout branches). Groups and
|
|
127
135
|
* submenus nest and mix with plain options. Selection stays global (one `value`,
|
|
128
136
|
* leaf options only); a filter query flattens the tree into grouped results.
|
|
129
137
|
*
|
|
138
|
+
* `Select` infers its value type `V` from these options: `{ value: 365 }` makes
|
|
139
|
+
* `onValueChange` report `number`. A mix of value types widens `V` to the union.
|
|
140
|
+
*
|
|
130
141
|
* Each leaf `value` is the option's identity and must be **unique across the whole
|
|
131
|
-
* tree**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
|
|
142
|
+
* tree** (selection is value-keyed, so a value repeated in two sections is one logical
|
|
143
|
+
* pick: both rows toggle together, the trigger resolves to the last). Values that
|
|
144
|
+
* stringify alike (`365` and `"365"`) also collide as row keys; dev builds
|
|
145
|
+
* `console.warn` on either. */
|
|
146
|
+
options: SelectItem<V>[];
|
|
135
147
|
/** Preferred placement of the options menu relative to the trigger. The menu
|
|
136
148
|
* auto-flips vertically and clamps horizontally when needed.
|
|
137
149
|
* @defaultValue bottom-start */
|
|
@@ -183,7 +195,7 @@ export interface SelectCommonProps extends Omit<BaseProps, 'children'> {
|
|
|
183
195
|
* type. `true` uses the built-in matcher — a case-insensitive substring of the
|
|
184
196
|
* option's **value / label / hint**. Pass a **function** `(option, query) =>
|
|
185
197
|
* boolean` for custom matching (called per option; return `true` to keep it). */
|
|
186
|
-
filter?: boolean | ((option: SelectOption
|
|
198
|
+
filter?: boolean | ((option: SelectOption<V>, query: string) => boolean);
|
|
187
199
|
/** `multiple` only: a "Select all" row at the top that toggles every enabled
|
|
188
200
|
* option (the currently-visible ones when a `filter` query is active); its box
|
|
189
201
|
* shows the mixed state when only some are selected. On by default in
|
|
@@ -208,13 +220,31 @@ export interface SelectCommonProps extends Omit<BaseProps, 'children'> {
|
|
|
208
220
|
* `OptionState` (`value`/`selected`/`disabled`). Filtering still works (it
|
|
209
221
|
* matches the option's `value`/`label`/`hint`), but match-highlighting is
|
|
210
222
|
* skipped — your content owns its own display. */
|
|
211
|
-
renderOption?: (option: SelectOption
|
|
223
|
+
renderOption?: (option: SelectOption<V>, state: OptionState<V>) => React.ReactNode;
|
|
212
224
|
/** Replace each row's selection **mark** with your own node, drawn at the
|
|
213
225
|
* leading edge. The row stays the control (`role` + `aria-checked` from
|
|
214
226
|
* `indicator` / `selection`); only the drawn mark changes, so pair it with an
|
|
215
227
|
* `indicator` (`'check'` / `'radio'`) or `selection="multiple"` for the
|
|
216
228
|
* semantics. Composes with `renderOption`. */
|
|
217
|
-
renderIndicator?: (state: OptionState) => React.ReactNode;
|
|
229
|
+
renderIndicator?: (state: OptionState<V>) => React.ReactNode;
|
|
230
|
+
/** `multiple` only: spell the picks out in the count summary — `3 selected:
|
|
231
|
+
* A, B, C` (labels comma-joined) in place of the bare `3 selected`. Applies
|
|
232
|
+
* to the multi-count case only: `All` stays `All`, a single pick stays its
|
|
233
|
+
* own label, and an empty selection stays the `placeholder`. The list flows
|
|
234
|
+
* into the read-only field, so it ellipsizes at the field's width when long
|
|
235
|
+
* (`3 selected: Engineering, Des… `). `renderSummary` overrides this. */
|
|
236
|
+
verbose?: boolean;
|
|
237
|
+
/** `multiple` only: build the trigger's selection summary text yourself,
|
|
238
|
+
* replacing the built-in "`All` / one label / `N selected`" logic. Receives
|
|
239
|
+
* the resolved selected options (`selected.length` is the count) and runs only
|
|
240
|
+
* while something is selected — an empty selection still shows the
|
|
241
|
+
* `placeholder`. Return a **string**: it flows into the default trigger's
|
|
242
|
+
* read-only field, so a long summary ellipsizes at the field's width just
|
|
243
|
+
* like a long value (`Engineering, Design, … `). Return `undefined` to fall
|
|
244
|
+
* back to the default for that case (e.g. customize only the count, keeping
|
|
245
|
+
* the single-label case built-in). For rich content (chips, multiple nodes)
|
|
246
|
+
* use `renderTrigger`, which replaces the whole field. */
|
|
247
|
+
renderSummary?: (selected: SelectOption<V>[]) => string | undefined;
|
|
218
248
|
/** Render your own trigger in place of the default field. Receives a
|
|
219
249
|
* `TriggerState` (`open` / `value` / `selected` / `disabled` / `icon`) to drive
|
|
220
250
|
* its look. **Return exactly one focusable element** (an Anta `Button`, say) —
|
|
@@ -225,7 +255,7 @@ export interface SelectCommonProps extends Omit<BaseProps, 'children'> {
|
|
|
225
255
|
* trigger owns its own styling: the field props (`label`, `hint`, `size`, `status`,
|
|
226
256
|
* `placeholder`, `round`) and `className` / `style` apply to the *default* trigger
|
|
227
257
|
* only — put your own on the element you return. */
|
|
228
|
-
renderTrigger?: (state: TriggerState) => React.ReactNode;
|
|
258
|
+
renderTrigger?: (state: TriggerState<V>) => React.ReactNode;
|
|
229
259
|
/** Render content in the menu body when the (filtered) option list is empty —
|
|
230
260
|
* a "no results" message, a loading indicator (gated on your own external
|
|
231
261
|
* loading state), or a "create from the query" row. Receives an `EmptyState`
|
|
@@ -239,37 +269,37 @@ export interface SelectCommonProps extends Omit<BaseProps, 'children'> {
|
|
|
239
269
|
* `<Select>` props. `selection` discriminates the value shape: single mode
|
|
240
270
|
* (`value: string`) or `multiple` (`value: string[]`).
|
|
241
271
|
*/
|
|
242
|
-
export type SelectProps = SelectCommonProps & ({
|
|
243
|
-
/** Selection mode. `'single'` (the default) keeps `value` a
|
|
272
|
+
export type SelectProps<V extends OptionValue = string> = SelectCommonProps<V> & ({
|
|
273
|
+
/** Selection mode. `'single'` (the default) keeps `value` a single value and
|
|
244
274
|
* closes the menu on pick. Switch to `'multiple'` for checkboxes + an
|
|
245
275
|
* array value.
|
|
246
276
|
* @defaultValue single */
|
|
247
277
|
selection?: 'single';
|
|
248
|
-
/** Controlled value — the `value`
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
value?:
|
|
253
|
-
/** Initial value (an option's `value`
|
|
278
|
+
/** Controlled value — the `value` of the selected option. When provided, the
|
|
279
|
+
* consumer owns selection: the field follows this prop and a pick only
|
|
280
|
+
* *requests* a change via `onValueChange` (reject by not updating). Leave
|
|
281
|
+
* undefined for uncontrolled. */
|
|
282
|
+
value?: V;
|
|
283
|
+
/** Initial value (an option's `value`) for the uncontrolled case — the
|
|
254
284
|
* wrapper then owns it. */
|
|
255
|
-
defaultValue?:
|
|
285
|
+
defaultValue?: V;
|
|
256
286
|
/** Fires after the selection changes, with the new value and a
|
|
257
287
|
* `{ value, option }` snapshot. Select has no discrete element state, so
|
|
258
288
|
* there is no cancelable `onStateChange` (see the Input event-model note). */
|
|
259
|
-
onValueChange?: (value:
|
|
289
|
+
onValueChange?: (value: V, attrs: SelectChangeAttrs<V>) => void;
|
|
260
290
|
} | {
|
|
261
291
|
/** Multi-select: checkboxes on every row, the menu stays open while
|
|
262
292
|
* toggling, the field shows an "N selected" count, and `value` is an array. */
|
|
263
293
|
selection: 'multiple';
|
|
264
|
-
/** Controlled values — the `value`
|
|
294
|
+
/** Controlled values — the `value`s of the selected options (see the
|
|
265
295
|
* single-select `value` note). */
|
|
266
|
-
value?:
|
|
267
|
-
/** Initial values (option `value`
|
|
268
|
-
defaultValue?:
|
|
296
|
+
value?: V[];
|
|
297
|
+
/** Initial values (option `value`s) for the uncontrolled case. */
|
|
298
|
+
defaultValue?: V[];
|
|
269
299
|
/** Fires after any toggle, with the new value array and a `{ value, option,
|
|
270
300
|
* selected }` snapshot of the row that changed (or `{ all: true }` for the
|
|
271
301
|
* Select-all row). */
|
|
272
|
-
onValueChange?: (value:
|
|
302
|
+
onValueChange?: (value: V[], attrs: SelectChangeAttrs<V>) => void;
|
|
273
303
|
});
|
|
274
304
|
/** Rolled-up selection of a group / submenu subtree: `'none'` / `'all'` of the
|
|
275
305
|
* descendant leaves selected, or `'some'` in between. On `SelectedGroup` /
|
|
@@ -277,26 +307,26 @@ export type SelectProps = SelectCommonProps & ({
|
|
|
277
307
|
export type SelectionState = 'none' | 'some' | 'all';
|
|
278
308
|
/** A leaf option annotated with its current selection — a `SelectOption` plus
|
|
279
309
|
* `selected`. Returned by {@link optionsWithSelection}. */
|
|
280
|
-
export type SelectedOption = SelectOption & {
|
|
310
|
+
export type SelectedOption<V extends OptionValue = string> = SelectOption<V> & {
|
|
281
311
|
selected: boolean;
|
|
282
312
|
};
|
|
283
313
|
/** A group with its descendants annotated and a rolled-up `selectionState`.
|
|
284
314
|
* Returned by {@link optionsWithSelection}. */
|
|
285
|
-
export interface SelectedGroup extends Omit<SelectGroup
|
|
286
|
-
options: SelectedItem[];
|
|
315
|
+
export interface SelectedGroup<V extends OptionValue = string> extends Omit<SelectGroup<V>, 'options'> {
|
|
316
|
+
options: SelectedItem<V>[];
|
|
287
317
|
selectionState: SelectionState;
|
|
288
318
|
}
|
|
289
319
|
/** A submenu with its descendants annotated and a rolled-up `selectionState`.
|
|
290
320
|
* Returned by {@link optionsWithSelection}. */
|
|
291
|
-
export interface SelectedSubmenu extends Omit<SelectSubmenu
|
|
292
|
-
submenu: SelectedItem[];
|
|
321
|
+
export interface SelectedSubmenu<V extends OptionValue = string> extends Omit<SelectSubmenu<V>, 'submenu'> {
|
|
322
|
+
submenu: SelectedItem<V>[];
|
|
293
323
|
selectionState: SelectionState;
|
|
294
324
|
}
|
|
295
325
|
/** One node of the tree from {@link optionsWithSelection}: a leaf `SelectedOption`
|
|
296
326
|
* (with `selected`), or a `SelectedGroup` / `SelectedSubmenu` (annotated children
|
|
297
327
|
* + rolled-up `selectionState`). Mirrors `SelectItem` minus the bare-string
|
|
298
328
|
* shorthand — strings are normalized to `SelectedOption`. */
|
|
299
|
-
export type SelectedItem = SelectedOption | SelectedGroup | SelectedSubmenu
|
|
329
|
+
export type SelectedItem<V extends OptionValue = string> = SelectedOption<V> | SelectedGroup<V> | SelectedSubmenu<V>;
|
|
300
330
|
/**
|
|
301
331
|
* Project a `Select` `options` tree onto a set of selected values: returns a mirror
|
|
302
332
|
* of the tree with every leaf marked `selected` and every group / submenu carrying a
|
|
@@ -319,7 +349,7 @@ export type SelectedItem = SelectedOption | SelectedGroup | SelectedSubmenu;
|
|
|
319
349
|
* // { value: 'eng-fe', label: 'Frontend', selected: false }, … ] }
|
|
320
350
|
* ```
|
|
321
351
|
*/
|
|
322
|
-
export declare function optionsWithSelection(options: SelectItem[], values:
|
|
352
|
+
export declare function optionsWithSelection<V extends OptionValue = string>(options: SelectItem<V>[], values: V | V[] | undefined): SelectedItem<V>[];
|
|
323
353
|
/**
|
|
324
354
|
* `<Select>` — a single- or multi-select dropdown, composed from `<Input>` (a
|
|
325
355
|
* read-only trigger) and `<Menu>` (the options). `selection` sets behaviour:
|
|
@@ -345,4 +375,4 @@ export declare function optionsWithSelection(options: SelectItem[], values: stri
|
|
|
345
375
|
* />
|
|
346
376
|
* ```
|
|
347
377
|
*/
|
|
348
|
-
export declare const Select: (props: SelectProps) => any;
|
|
378
|
+
export declare const Select: <V extends OptionValue = string>(props: SelectProps<V>) => any;
|
|
@@ -62,6 +62,8 @@ const Select = (props) => {
|
|
|
62
62
|
clearLabel = "Clear",
|
|
63
63
|
renderOption,
|
|
64
64
|
renderIndicator,
|
|
65
|
+
verbose,
|
|
66
|
+
renderSummary,
|
|
65
67
|
renderTrigger,
|
|
66
68
|
renderEmpty,
|
|
67
69
|
className,
|
|
@@ -96,9 +98,10 @@ const Select = (props) => {
|
|
|
96
98
|
collectLeaves(options, void 0, false, allLeaves);
|
|
97
99
|
const seenValues = /* @__PURE__ */ new Set();
|
|
98
100
|
for (const l of allLeaves) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
const key = String(l.opt.value);
|
|
102
|
+
if (seenValues.has(key))
|
|
103
|
+
console.warn(`[anta] <Select> duplicate option value=${JSON.stringify(l.opt.value)} \u2014 values must be unique (compared as strings for row keys).`);
|
|
104
|
+
seenValues.add(key);
|
|
102
105
|
}
|
|
103
106
|
const byValue = new Map(allLeaves.map((l) => [l.opt.value, l.opt]));
|
|
104
107
|
const filtering = filter !== void 0 && filter !== false;
|
|
@@ -111,13 +114,22 @@ const Select = (props) => {
|
|
|
111
114
|
const selectedValues = Array.isArray(currentRaw) ? currentRaw : currentRaw != null ? [currentRaw] : [];
|
|
112
115
|
const isSelected = (v) => selectedValues.includes(v);
|
|
113
116
|
const selectedOptions = selectedValues.map((v) => byValue.get(v)).filter(Boolean);
|
|
117
|
+
const allEnabledValues = allLeaves.filter((l) => !l.disabled).map((l) => l.opt.value);
|
|
118
|
+
const everythingSelected = multiple && allEnabledValues.length > 1 && allEnabledValues.every((v) => selectedValues.includes(v));
|
|
119
|
+
const labelOf = (o) => o.label ?? String(o.value);
|
|
114
120
|
let display = "";
|
|
115
121
|
if (multiple) {
|
|
116
|
-
|
|
117
|
-
|
|
122
|
+
const custom = selectedOptions.length > 0 ? renderSummary?.(selectedOptions) : void 0;
|
|
123
|
+
if (custom != null && custom !== "") display = custom;
|
|
124
|
+
else if (everythingSelected) display = "All";
|
|
125
|
+
else if (selectedOptions.length === 1) display = labelOf(selectedOptions[0]);
|
|
126
|
+
else if (selectedOptions.length > 1) {
|
|
127
|
+
const count = `${selectedOptions.length} selected`;
|
|
128
|
+
display = verbose ? `${count}: ${selectedOptions.map(labelOf).join(", ")}` : count;
|
|
129
|
+
}
|
|
118
130
|
} else if (currentRaw != null) {
|
|
119
131
|
const o = byValue.get(currentRaw);
|
|
120
|
-
display = o ? o
|
|
132
|
+
display = o ? labelOf(o) : "";
|
|
121
133
|
}
|
|
122
134
|
const choose = (o, e) => {
|
|
123
135
|
if (multiple) {
|
|
@@ -166,7 +178,7 @@ const Select = (props) => {
|
|
|
166
178
|
selectionIndicator: menuItemIndicator,
|
|
167
179
|
...ariaSelectable,
|
|
168
180
|
indicator: customMark ?? void 0,
|
|
169
|
-
label: custom ? void 0 : highlight(o.label ?? o.value, queryRe),
|
|
181
|
+
label: custom ? void 0 : highlight(o.label ?? String(o.value), queryRe),
|
|
170
182
|
hint: custom ? void 0 : o.hint ? highlight(o.hint, queryRe) : o.hint,
|
|
171
183
|
icon: custom ? void 0 : o.icon,
|
|
172
184
|
tone: o.tone,
|
|
@@ -177,10 +189,10 @@ const Select = (props) => {
|
|
|
177
189
|
onSelect: (e) => choose(o, e),
|
|
178
190
|
children: [
|
|
179
191
|
custom,
|
|
180
|
-
tip && /* @__PURE__ */ jsx(Tooltip, { ...hintOnly ? {
|
|
192
|
+
tip && /* @__PURE__ */ jsx(Tooltip, { follow: true, ...hintOnly ? { delay: 700 } : {}, children: tip })
|
|
181
193
|
]
|
|
182
194
|
},
|
|
183
|
-
o.value
|
|
195
|
+
String(o.value)
|
|
184
196
|
);
|
|
185
197
|
};
|
|
186
198
|
const renderTree = (items, disabled2) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BaseProps } from '../general_types';
|
|
2
2
|
import type { IconShape } from '../elements/a-icon.shapes';
|
|
3
|
-
import type { SelectItem, SelectOption } from './Select';
|
|
3
|
+
import type { OptionValue, SelectItem, SelectOption } from './Select';
|
|
4
4
|
import { type MenuProps } from './Menu';
|
|
5
5
|
interface FacetBase {
|
|
6
6
|
/** The facet's namespace — the key its value is stored under in the value
|
|
@@ -15,26 +15,27 @@ interface FacetBase {
|
|
|
15
15
|
/** A per-facet option-list filter (like `Select`'s `filter`): `true` uses the
|
|
16
16
|
* built-in case-insensitive substring match on an option's value / label /
|
|
17
17
|
* hint; a function `(option, query) => boolean` does custom matching. */
|
|
18
|
-
export type FacetFilter = boolean | ((option: SelectOption
|
|
19
|
-
/** Pick **one** option. Value: the chosen option's `value`
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
export type FacetFilter = boolean | ((option: SelectOption<OptionValue>, query: string) => boolean);
|
|
19
|
+
/** Pick **one** option. Value: the chosen option's `value` (or `undefined` when
|
|
20
|
+
* cleared). Re-picking the selected option clears it. Options are `Select`'s
|
|
21
|
+
* `SelectItem`s — bare strings or `SelectOption`s carrying the same fields
|
|
22
|
+
* (`value`, `label`, `hint`, `icon`, `tone`, `disabled`). Option `value`s may be
|
|
23
|
+
* `string` / `number` / `boolean` and round-trip unchanged. */
|
|
23
24
|
export interface SelectFacetSingle extends FacetBase {
|
|
24
25
|
kind: 'single';
|
|
25
26
|
/** The options — bare strings or `SelectOption`s (groups / submenus are
|
|
26
27
|
* flattened to their leaves). */
|
|
27
|
-
options: SelectItem[];
|
|
28
|
+
options: SelectItem<OptionValue>[];
|
|
28
29
|
/** Add a search field atop this facet's flyout that filters its options. */
|
|
29
30
|
filter?: FacetFilter;
|
|
30
31
|
}
|
|
31
|
-
/** Pick **any number** of options. Value: an array of the chosen `value`
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
/** Pick **any number** of options. Value: an array of the chosen `value`s
|
|
33
|
+
* (empty array clears the facet). Options are the same `SelectItem`s as `single`,
|
|
34
|
+
* with the same `string` / `number` / `boolean` value support. */
|
|
34
35
|
export interface SelectFacetMultiple extends FacetBase {
|
|
35
36
|
kind: 'multiple';
|
|
36
37
|
/** The options — bare strings or `SelectOption`s (groups / submenus flattened). */
|
|
37
|
-
options: SelectItem[];
|
|
38
|
+
options: SelectItem<OptionValue>[];
|
|
38
39
|
/** Add a search field atop this facet's flyout that filters its options. */
|
|
39
40
|
filter?: FacetFilter;
|
|
40
41
|
/** A "Select all" row that toggles every option. On by default — set `false`
|
|
@@ -75,9 +76,11 @@ export interface SelectFacetCustom<V = unknown> extends FacetBase {
|
|
|
75
76
|
}
|
|
76
77
|
/** One facet (dimension) of the filter, discriminated by `kind`. */
|
|
77
78
|
export type SelectFacet = SelectFacetSingle | SelectFacetMultiple | SelectFacetText | SelectFacetCustom;
|
|
78
|
-
/** The filter value: a facet key → that facet's value. Per kind
|
|
79
|
-
* `string`
|
|
80
|
-
*
|
|
79
|
+
/** The filter value: a facet key → that facet's value. Per kind: an option value
|
|
80
|
+
* (`string` / `number` / `boolean`) for `single`, a `string` for `text`, an array for
|
|
81
|
+
* `multiple`, or your own `V` for `custom`. Values are stored and reported unchanged.
|
|
82
|
+
* Typed loosely as `unknown` since facets in one control can hold different value
|
|
83
|
+
* types; narrow per facet when you read it. A cleared facet is absent from the record. */
|
|
81
84
|
export type SelectFacetedValue = Record<string, unknown>;
|
|
82
85
|
/** Second argument to `onValueChange` — what changed. A single-facet edit
|
|
83
86
|
* carries `facet` / `kind` / the facet's new `value`; the "Clear all" row
|
|
@@ -122,8 +125,10 @@ export interface SelectFacetedProps extends Omit<BaseProps, 'children'> {
|
|
|
122
125
|
value?: SelectFacetedValue;
|
|
123
126
|
/** Initial value for the uncontrolled case (the wrapper then owns it). */
|
|
124
127
|
defaultValue?: SelectFacetedValue;
|
|
125
|
-
/** Fires after any facet changes
|
|
126
|
-
* attrs
|
|
128
|
+
/** Fires after any facet changes. `value` is the whole new record (a facet key →
|
|
129
|
+
* that facet's value; a cleared facet is absent). `attrs` says what changed:
|
|
130
|
+
* `{ facet, kind, value }` for a single facet edit, or `{ all: true }` for the
|
|
131
|
+
* "Clear all" row — narrow on `'all' in attrs` before reading `facet`. */
|
|
127
132
|
onValueChange?: (value: SelectFacetedValue, attrs: SelectFacetedChangeAttrs) => void;
|
|
128
133
|
/** Default trigger's button label.
|
|
129
134
|
* @defaultValue Filter */
|
|
@@ -120,7 +120,7 @@ const SelectFaceted = (props) => {
|
|
|
120
120
|
const optionRow = (facet, opt, keyPrefix = "") => {
|
|
121
121
|
const shared = {
|
|
122
122
|
icon: opt.icon,
|
|
123
|
-
label: opt.label ?? opt.value,
|
|
123
|
+
label: opt.label ?? String(opt.value),
|
|
124
124
|
hint: opt.hint,
|
|
125
125
|
tone: opt.tone,
|
|
126
126
|
toneSelected,
|
|
@@ -151,7 +151,7 @@ const SelectFaceted = (props) => {
|
|
|
151
151
|
selectionIndicator: "checkbox",
|
|
152
152
|
selected: arr.includes(opt.value),
|
|
153
153
|
onSelect: (e) => isolable && e?.altKey ? setFacet(facet, [opt.value]) : setFacet(facet, arr.includes(opt.value) ? arr.filter((v) => v !== opt.value) : [...arr, opt.value]),
|
|
154
|
-
children: tip && /* @__PURE__ */ jsx(Tooltip, { ...hintOnly ? {
|
|
154
|
+
children: tip && /* @__PURE__ */ jsx(Tooltip, { follow: true, ...hintOnly ? { delay: 700 } : {}, children: tip })
|
|
155
155
|
},
|
|
156
156
|
`${keyPrefix}${opt.value}`
|
|
157
157
|
);
|
|
@@ -196,7 +196,7 @@ const SelectFaceted = (props) => {
|
|
|
196
196
|
const applied = current[facet.key] ?? "";
|
|
197
197
|
const draft = drafts[facet.key] ?? applied;
|
|
198
198
|
const apply = () => {
|
|
199
|
-
const next = draft.trim()
|
|
199
|
+
const next = draft.trim() === "" ? void 0 : draft;
|
|
200
200
|
if (next !== (applied || void 0)) setFacet(facet, next);
|
|
201
201
|
};
|
|
202
202
|
return (
|
|
@@ -312,7 +312,7 @@ const SelectFaceted = (props) => {
|
|
|
312
312
|
searchable && rootQuery.trim() ? renderFlatResults() : facets.map((facet) => /* @__PURE__ */ jsxs(MenuItem, { submenu: true, icon: facet.icon, label: facet.label, children: [
|
|
313
313
|
(() => {
|
|
314
314
|
const s = summaryOf(facet);
|
|
315
|
-
return s != null ? /* @__PURE__ */ jsx(Tag, { size: "small", tone: "brand", children: s }) : null;
|
|
315
|
+
return s != null ? /* @__PURE__ */ jsx(Tag, { size: "small", tone: "brand", children: /* @__PURE__ */ jsx("span", { className: styles.summary, children: s }) }) : null;
|
|
316
316
|
})(),
|
|
317
317
|
renderEditor(facet)
|
|
318
318
|
] }, facet.key)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.search{padding:var(--menu-padding, 4px)}.footer{padding:var(--menu-padding, 4px);border-top:1px solid var(--border-4)}
|
|
1
|
+
.search{padding:var(--menu-padding, 4px)}.summary{display:block;max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.footer{padding:var(--menu-padding, 4px);border-top:1px solid var(--border-4)}
|
|
@@ -18,11 +18,11 @@ export type ExpandMode = {
|
|
|
18
18
|
collapsible?: boolean;
|
|
19
19
|
};
|
|
20
20
|
export type TextProps = BaseProps & {
|
|
21
|
-
/** Visual priority. Maps to text-1..text-
|
|
21
|
+
/** Visual priority. Maps to text-1..text-4 (`primary` = text-1, the
|
|
22
22
|
* strongest). The default is `secondary` (text-2) — body text reads a
|
|
23
23
|
* step softer than the strongest foreground; pass `primary` for emphasis.
|
|
24
24
|
* @defaultValue secondary */
|
|
25
|
-
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
|
|
25
|
+
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary';
|
|
26
26
|
/** Color tint. `neutral` (the default) is the untinted `--text-{N}` scale; a
|
|
27
27
|
* named tone applies the matching `--text-{N}-{tone}` palette. Any literal CSS
|
|
28
28
|
* color (`'#ff1493'`, `'rebeccapurple'`) is a one-off custom tone — its hue is
|
|
@@ -5,9 +5,9 @@ export interface TitleProps extends BaseProps {
|
|
|
5
5
|
* (h1 is typically reserved for the page title).
|
|
6
6
|
* @defaultValue 2 */
|
|
7
7
|
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
8
|
-
/** Visual priority. Maps to text-1..text-
|
|
8
|
+
/** Visual priority. Maps to text-1..text-4 (`primary` = text-1).
|
|
9
9
|
* @defaultValue primary */
|
|
10
|
-
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
|
|
10
|
+
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary';
|
|
11
11
|
/** Color tint. `neutral` (the default) is the untinted `--text-{N}` scale; a
|
|
12
12
|
* named tone applies the matching `--text-{N}-{tone}` palette. Any literal CSS
|
|
13
13
|
* color (`'#ff1493'`, `'rebeccapurple'`) is a one-off custom tone — its hue is
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { BaseProps } from "../general_types";
|
|
2
|
+
import { type Toaster as ToasterStore } from "../toaster";
|
|
3
|
+
export interface ToasterProps extends BaseProps {
|
|
4
|
+
/** The store this region renders. Omit to bind the default store driven by
|
|
5
|
+
* `Toaster.manager`; pass a `createToaster()` for an isolated region. */
|
|
6
|
+
toaster?: ToasterStore;
|
|
7
|
+
/** Accessible label for the region landmark.
|
|
8
|
+
* @defaultValue 'Notifications' */
|
|
9
|
+
label?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `<Toaster>` — the mounted notification region. Keep one mounted somewhere in
|
|
13
|
+
* your app (a portal is fine); toasts are added imperatively through the store
|
|
14
|
+
* (`Toaster.manager`, or a `createToaster()` you pass as `toaster`). It
|
|
15
|
+
* subscribes to the store and renders each toast through the reconciler, so
|
|
16
|
+
* React/Preact owns the toast nodes.
|
|
17
|
+
*
|
|
18
|
+
* Announcement is opt-in **per toast** (`add(render, { politeness })`), not a
|
|
19
|
+
* blanket live region on the whole toaster.
|
|
20
|
+
*
|
|
21
|
+
* Requires `@antadesign/anta/elements` to be imported (client-side only) to
|
|
22
|
+
* register the underlying custom elements.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <Toaster /> // mount once, keep it mounted
|
|
27
|
+
*
|
|
28
|
+
* // A bare string is auto-wrapped in a dismissible Banner:
|
|
29
|
+
* Toaster.manager.add(() => 'Saved', { placement: 'bottom-right' })
|
|
30
|
+
*
|
|
31
|
+
* // Or toast a Banner yourself and wire its dismiss to the toast:
|
|
32
|
+
* Toaster.manager.add((id) => (
|
|
33
|
+
* <Banner tone="success" message="Saved" onDismiss={() => Toaster.manager.dismiss(id)} />
|
|
34
|
+
* ))
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
declare const ToasterImpl: ({ toaster, label, className, style, children: _children, ...rest }: ToasterProps) => any;
|
|
38
|
+
/**
|
|
39
|
+
* The `<Toaster>` component, carrying the default toast store as a static:
|
|
40
|
+
* `Toaster.manager.add(render, opts)`. A function-with-a-static (like
|
|
41
|
+
* `Component.displayName`) — no class component, which would couple to a renderer.
|
|
42
|
+
*/
|
|
43
|
+
export declare const Toaster: typeof ToasterImpl & {
|
|
44
|
+
/** The default toast store, bound to a `<Toaster>` mounted with no `toaster`. */
|
|
45
|
+
readonly manager: ToasterStore;
|
|
46
|
+
};
|
|
47
|
+
export { createToaster } from "../toaster";
|
|
48
|
+
export type { Toaster as ToasterManager, ToastOptions, ToastPlacement, ToastContent, ToastRender, } from "../toaster";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx } from "@antadesign/anta/jsx-runtime";
|
|
2
|
+
import { useMemo, useSyncExternalStore } from "../jsx-runtime";
|
|
3
|
+
import { createToaster } from "../toaster";
|
|
4
|
+
import { Banner } from "./Banner";
|
|
5
|
+
const ToastItem = ({ entry, store }) => {
|
|
6
|
+
const content = useMemo(() => entry.render(entry.id), [entry.id, entry.rev]);
|
|
7
|
+
const isNode = typeof Node !== "undefined" && content instanceof Node;
|
|
8
|
+
const isText = typeof content === "string" || typeof content === "number";
|
|
9
|
+
const common = {
|
|
10
|
+
slot: entry.placement,
|
|
11
|
+
duration: entry.duration,
|
|
12
|
+
leaving: entry.leaving ? "" : void 0,
|
|
13
|
+
rev: entry.rev,
|
|
14
|
+
// Opt-in per-toast announcement. role=status/alert (not a bare aria-live) so
|
|
15
|
+
// it announces when inserted — a plain aria-live region must pre-exist before
|
|
16
|
+
// its content changes, which a freshly-added toast can't satisfy. Omitted (no
|
|
17
|
+
// announcement) unless requested.
|
|
18
|
+
role: entry.politeness === "assertive" ? "alert" : entry.politeness === "polite" ? "status" : void 0,
|
|
19
|
+
// Fires after the exit animation; that's when the entry actually leaves.
|
|
20
|
+
ondismiss: () => store.remove(entry.id)
|
|
21
|
+
};
|
|
22
|
+
if (isNode) return /* @__PURE__ */ jsx("a-toast", { ...common, content });
|
|
23
|
+
if (isText)
|
|
24
|
+
return /* @__PURE__ */ jsx("a-toast", { ...common, children: /* @__PURE__ */ jsx(
|
|
25
|
+
Banner,
|
|
26
|
+
{
|
|
27
|
+
round: true,
|
|
28
|
+
message: content,
|
|
29
|
+
dismissed: false,
|
|
30
|
+
onDismiss: () => store.dismiss(entry.id)
|
|
31
|
+
}
|
|
32
|
+
) });
|
|
33
|
+
return /* @__PURE__ */ jsx("a-toast", { ...common, children: content });
|
|
34
|
+
};
|
|
35
|
+
const ToasterImpl = ({
|
|
36
|
+
toaster,
|
|
37
|
+
label = "Notifications",
|
|
38
|
+
className,
|
|
39
|
+
style,
|
|
40
|
+
// The region's children come from the store, not from JSX.
|
|
41
|
+
children: _children,
|
|
42
|
+
...rest
|
|
43
|
+
}) => {
|
|
44
|
+
const store = toaster ?? getDefaultStore();
|
|
45
|
+
const entries = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getServerSnapshot);
|
|
46
|
+
return /* @__PURE__ */ jsx("a-toaster", { role: "region", "aria-label": label, class: className, style, ...rest, children: entries.map((entry) => /* @__PURE__ */ jsx(ToastItem, { entry, store }, entry.id)) });
|
|
47
|
+
};
|
|
48
|
+
let defaultStore;
|
|
49
|
+
const getDefaultStore = () => defaultStore ??= createToaster();
|
|
50
|
+
const Toaster = ToasterImpl;
|
|
51
|
+
Object.defineProperty(Toaster, "manager", { get: getDefaultStore, enumerable: true });
|
|
52
|
+
import { createToaster as createToaster2 } from "../toaster";
|
|
53
|
+
export {
|
|
54
|
+
Toaster,
|
|
55
|
+
createToaster2 as createToaster
|
|
56
|
+
};
|
|
@@ -5,7 +5,7 @@ export interface TooltipProps extends BaseProps {
|
|
|
5
5
|
children?: React.ReactNode;
|
|
6
6
|
/** Show delay in milliseconds after hover / focus. Never use `0` — use
|
|
7
7
|
* ~`50` for a near-instant tooltip (0 has caused issues in practice).
|
|
8
|
-
* @defaultValue
|
|
8
|
+
* @defaultValue 300 */
|
|
9
9
|
delay?: number;
|
|
10
10
|
/** Which side of the anchor the bubble prefers. Auto-flips to the other
|
|
11
11
|
* side when there isn't room.
|