bits-ui 1.0.0-next.28 → 1.0.0-next.29
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.
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
controlledOpen = false,
|
|
21
21
|
controlledValue = false,
|
|
22
22
|
items = [],
|
|
23
|
+
allowDeselect = true,
|
|
23
24
|
children,
|
|
24
25
|
}: ComboboxRootProps = $props();
|
|
25
26
|
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
name: box.with(() => name),
|
|
64
65
|
isCombobox: true,
|
|
65
66
|
items: box.with(() => items),
|
|
67
|
+
allowDeselect: box.with(() => allowDeselect),
|
|
66
68
|
});
|
|
67
69
|
</script>
|
|
68
70
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
controlledOpen = false,
|
|
21
21
|
controlledValue = false,
|
|
22
22
|
items = [],
|
|
23
|
+
allowDeselect = true,
|
|
23
24
|
children,
|
|
24
25
|
}: SelectRootProps = $props();
|
|
25
26
|
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
name: box.with(() => name),
|
|
64
65
|
isCombobox: false,
|
|
65
66
|
items: box.with(() => items),
|
|
67
|
+
allowDeselect: box.with(() => allowDeselect),
|
|
66
68
|
});
|
|
67
69
|
</script>
|
|
68
70
|
|
|
@@ -18,6 +18,7 @@ type SelectBaseRootStateProps = ReadableBoxedValues<{
|
|
|
18
18
|
label: string;
|
|
19
19
|
disabled?: boolean;
|
|
20
20
|
}[];
|
|
21
|
+
allowDeselect: boolean;
|
|
21
22
|
}> & WritableBoxedValues<{
|
|
22
23
|
open: boolean;
|
|
23
24
|
}> & {
|
|
@@ -31,6 +32,7 @@ declare class SelectBaseRootState {
|
|
|
31
32
|
open: SelectBaseRootStateProps["open"];
|
|
32
33
|
scrollAlignment: SelectBaseRootStateProps["scrollAlignment"];
|
|
33
34
|
items: SelectBaseRootStateProps["items"];
|
|
35
|
+
allowDeselect: SelectBaseRootStateProps["allowDeselect"];
|
|
34
36
|
touchedInput: boolean;
|
|
35
37
|
inputValue: string;
|
|
36
38
|
inputNode: HTMLElement | null;
|
|
@@ -404,6 +406,7 @@ type InitSelectProps = {
|
|
|
404
406
|
label: string;
|
|
405
407
|
disabled?: boolean;
|
|
406
408
|
}[];
|
|
409
|
+
allowDeselect: boolean;
|
|
407
410
|
}> & WritableBoxedValues<{
|
|
408
411
|
open: boolean;
|
|
409
412
|
}> & {
|
|
@@ -24,6 +24,7 @@ class SelectBaseRootState {
|
|
|
24
24
|
open;
|
|
25
25
|
scrollAlignment;
|
|
26
26
|
items;
|
|
27
|
+
allowDeselect;
|
|
27
28
|
touchedInput = $state(false);
|
|
28
29
|
inputValue = $state("");
|
|
29
30
|
inputNode = $state(null);
|
|
@@ -59,6 +60,7 @@ class SelectBaseRootState {
|
|
|
59
60
|
this.scrollAlignment = props.scrollAlignment;
|
|
60
61
|
this.isCombobox = props.isCombobox;
|
|
61
62
|
this.items = props.items;
|
|
63
|
+
this.allowDeselect = props.allowDeselect;
|
|
62
64
|
this.bitsAttrs = getSelectBitsAttrs(this);
|
|
63
65
|
$effect.pre(() => {
|
|
64
66
|
if (!this.open.current) {
|
|
@@ -277,10 +279,15 @@ class SelectInputState {
|
|
|
277
279
|
if (e.key === kbd.ENTER && !e.isComposing) {
|
|
278
280
|
e.preventDefault();
|
|
279
281
|
const highlightedValue = this.root.highlightedValue;
|
|
282
|
+
const isCurrentSelectedValue = highlightedValue === this.root.value.current;
|
|
283
|
+
if (!this.root.allowDeselect.current && isCurrentSelectedValue && !this.root.isMulti) {
|
|
284
|
+
this.root.handleClose();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
280
287
|
if (highlightedValue) {
|
|
281
288
|
this.root.toggleItem(highlightedValue, this.root.highlightedLabel ?? undefined);
|
|
282
289
|
}
|
|
283
|
-
if (!this.root.isMulti) {
|
|
290
|
+
if (!this.root.isMulti && !isCurrentSelectedValue) {
|
|
284
291
|
this.root.handleClose();
|
|
285
292
|
}
|
|
286
293
|
}
|
|
@@ -328,7 +335,9 @@ class SelectInputState {
|
|
|
328
335
|
};
|
|
329
336
|
#oninput = (e) => {
|
|
330
337
|
this.root.inputValue = e.currentTarget.value;
|
|
331
|
-
|
|
338
|
+
afterTick(() => {
|
|
339
|
+
this.root.setHighlightedToFirstCandidate();
|
|
340
|
+
});
|
|
332
341
|
};
|
|
333
342
|
props = $derived.by(() => ({
|
|
334
343
|
id: this.#id.current,
|
|
@@ -474,10 +483,15 @@ class SelectTriggerState {
|
|
|
474
483
|
if ((e.key === kbd.ENTER || e.key === kbd.SPACE) && !e.isComposing) {
|
|
475
484
|
e.preventDefault();
|
|
476
485
|
const highlightedValue = this.root.highlightedValue;
|
|
486
|
+
const isCurrentSelectedValue = highlightedValue === this.root.value.current;
|
|
487
|
+
if (!this.root.allowDeselect.current && isCurrentSelectedValue && !this.root.isMulti) {
|
|
488
|
+
this.root.handleClose();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
477
491
|
if (highlightedValue) {
|
|
478
492
|
this.root.toggleItem(highlightedValue, this.root.highlightedLabel ?? undefined);
|
|
479
493
|
}
|
|
480
|
-
if (!this.root.isMulti) {
|
|
494
|
+
if (!this.root.isMulti && !isCurrentSelectedValue) {
|
|
481
495
|
this.root.handleClose();
|
|
482
496
|
}
|
|
483
497
|
}
|
|
@@ -730,6 +744,13 @@ class SelectItemState {
|
|
|
730
744
|
if (this.disabled.current)
|
|
731
745
|
return;
|
|
732
746
|
const isCurrentSelectedValue = this.value.current === this.root.value.current;
|
|
747
|
+
// if allowDeselect is false and the item is already selected and we're not in a
|
|
748
|
+
// multi select, do nothing and close the menu
|
|
749
|
+
if (!this.root.allowDeselect.current && isCurrentSelectedValue && !this.root.isMulti) {
|
|
750
|
+
this.root.handleClose();
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
753
|
+
// otherwise, toggle the item and if we're not in a multi select, close the menu
|
|
733
754
|
this.root.toggleItem(this.value.current, this.label.current);
|
|
734
755
|
if (!this.root.isMulti && !isCurrentSelectedValue) {
|
|
735
756
|
this.root.handleClose();
|
|
@@ -84,6 +84,11 @@ export type SelectBaseRootPropsWithoutHTML = WithChildren<{
|
|
|
84
84
|
label: string;
|
|
85
85
|
disabled?: boolean;
|
|
86
86
|
}[];
|
|
87
|
+
/**
|
|
88
|
+
* Whether to allow the user to deselect an item by clicking on an already selected item.
|
|
89
|
+
* This is only applicable to `type="single"` selects/comboboxes.
|
|
90
|
+
*/
|
|
91
|
+
allowDeselect?: boolean;
|
|
87
92
|
}>;
|
|
88
93
|
export type SelectSingleRootPropsWithoutHTML = {
|
|
89
94
|
/**
|