@tristan2828/ui-foundation 3.30.0 → 3.30.1
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.
|
@@ -688,6 +688,12 @@ Save button, no Undo:
|
|
|
688
688
|
| `choice`: a select, a switch, a single reference | the pick (its list opens with the field, non-modal) | closes the list with nothing picked: gives up |
|
|
689
689
|
| `multi`: a multi reference | leaving it, or Ctrl/Cmd+Enter (Enter picks) | closes the list first; Esc again gives up |
|
|
690
690
|
|
|
691
|
+
In either multi picker (`MultiChoice`, `MultiReference`), on a form, in
|
|
692
|
+
a toolbar filter or in place, Escape never removes a pick: it closes the
|
|
693
|
+
list when it's open and leaves the value alone when it's closed (Base UI
|
|
694
|
+
would empty it). A pick comes off only by its chip's remove button,
|
|
695
|
+
Backspace in the empty input, or unpicking it in the list.
|
|
696
|
+
|
|
691
697
|
Leaving means clicking or tabbing anywhere else. Unchanged closes with no
|
|
692
698
|
request; a value the form's schema refuses never leaves the browser and
|
|
693
699
|
shows the schema's message. Opening another value saves the open one
|
|
@@ -13,5 +13,17 @@ import * as React from 'react';
|
|
|
13
13
|
import { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxContent, ComboboxEmpty, ComboboxItem, ComboboxList, ComboboxValue, useComboboxAnchor, } from '../ui/combobox.js';
|
|
14
14
|
export function MultiChoice({ options, value, onValueChange, getLabel = String, id, placeholder, 'aria-label': ariaLabel, 'aria-invalid': ariaInvalid, className, }) {
|
|
15
15
|
const anchor = useComboboxAnchor();
|
|
16
|
-
return (_jsxs(Combobox, { multiple: true, autoHighlight: true, items: options, value: value, onValueChange: (next
|
|
16
|
+
return (_jsxs(Combobox, { multiple: true, autoHighlight: true, items: options, value: value, onValueChange: (next, details) => {
|
|
17
|
+
// Base UI empties the value on Escape while the list is closed, so
|
|
18
|
+
// a second Escape after a pick wiped every chip (issue #123). Escape
|
|
19
|
+
// never removes picks here: a chip's remove button, Backspace or
|
|
20
|
+
// unpicking in the list does. Let the key go on, so a dialog or an
|
|
21
|
+
// edit in place gets its own Escape.
|
|
22
|
+
if (details.reason === 'escape-key') {
|
|
23
|
+
details.cancel();
|
|
24
|
+
details.allowPropagation();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
onValueChange(next);
|
|
28
|
+
}, itemToStringLabel: getLabel, children: [_jsx(ComboboxChips, { ref: anchor, className: className, children: _jsx(ComboboxValue, { children: (selected) => (_jsxs(React.Fragment, { children: [selected.map((option) => (_jsx(ComboboxChip, { children: getLabel(option) }, option))), _jsx(ComboboxChipsInput, { id: id, "aria-label": ariaLabel, "aria-invalid": ariaInvalid, placeholder: selected.length === 0 ? placeholder : undefined })] })) }) }), _jsxs(ComboboxContent, { anchor: anchor, children: [_jsx(ComboboxEmpty, { children: "No options found." }), _jsx(ComboboxList, { children: (option) => (_jsx(ComboboxItem, { value: option, children: getLabel(option) }, option)) })] })] }));
|
|
17
29
|
}
|
|
@@ -27,7 +27,19 @@ export function MultiReference({ options, value, onValueChange, getLabel, onSear
|
|
|
27
27
|
return (_jsxs(Combobox, { multiple: true, autoHighlight: true,
|
|
28
28
|
// Ids, not {id,label} objects: Base UI compares items to the value
|
|
29
29
|
// with Object.is, so the items must have the value's own shape.
|
|
30
|
-
items: options.map((option) => option.id), value: value, onValueChange: (next
|
|
30
|
+
items: options.map((option) => option.id), value: value, onValueChange: (next, details) => {
|
|
31
|
+
// Base UI empties the value on Escape while the list is closed, so
|
|
32
|
+
// a second Escape after a pick wiped every chip (issue #123). Escape
|
|
33
|
+
// never removes picks here: a chip's remove button, Backspace or
|
|
34
|
+
// unpicking in the list does. Let the key go on, so a dialog or an
|
|
35
|
+
// edit in place gets its own Escape.
|
|
36
|
+
if (details.reason === 'escape-key') {
|
|
37
|
+
details.cancel();
|
|
38
|
+
details.allowPropagation();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
onValueChange(next);
|
|
42
|
+
}, onInputValueChange: onSearchChange, itemToStringLabel: label, filter: null, readOnly: readOnly, children: [_jsx(ComboboxChips, { ref: anchor, className: className, children: _jsx(ComboboxValue, { children: (selected) => (_jsxs(React.Fragment, { children: [selected.map((option) => (_jsx(ComboboxChip, { children: label(option) }, option))), _jsx(ComboboxChipsInput, { id: id, onKeyDown: (event) => {
|
|
31
43
|
if (searching && event.key === 'Enter') {
|
|
32
44
|
event.preventDefault();
|
|
33
45
|
event.preventBaseUIHandler();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tristan2828/ui-foundation",
|
|
3
|
-
"version": "3.30.
|
|
3
|
+
"version": "3.30.1",
|
|
4
4
|
"description": "Shared UI foundation for contract-first, database-backed React apps: shadcn primitives, DataTable/EntityForm composites, auth, the gateway error seam, design tokens, lint rules and the AI playbook.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|