bits-ui 1.3.11 → 1.3.13
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/dist/bits/command/command.svelte.d.ts +2 -1
- package/dist/bits/command/command.svelte.js +30 -12
- package/dist/bits/command/components/command-item.svelte +1 -1
- package/dist/bits/command/components/command-list.svelte +9 -7
- package/dist/bits/context-menu/components/context-menu-content.svelte +3 -2
- package/dist/bits/menu/components/menu-sub-content-static.svelte +3 -2
- package/dist/bits/menu/components/menu-sub-content.svelte +3 -2
- package/dist/bits/radio-group/radio-group.svelte.js +8 -2
- package/package.json +1 -1
|
@@ -26,6 +26,7 @@ declare class CommandRootState {
|
|
|
26
26
|
labelNode: HTMLElement | null;
|
|
27
27
|
commandState: CommandState;
|
|
28
28
|
_commandState: CommandState;
|
|
29
|
+
searchHasHadValue: boolean;
|
|
29
30
|
setState<K extends keyof CommandState>(key: K, value: CommandState[K], opts?: boolean): void;
|
|
30
31
|
constructor(opts: CommandRootStateProps);
|
|
31
32
|
/**
|
|
@@ -266,7 +267,7 @@ declare class CommandSeparatorState {
|
|
|
266
267
|
constructor(opts: CommandSeparatorStateProps, root: CommandRootState);
|
|
267
268
|
props: {
|
|
268
269
|
readonly id: string;
|
|
269
|
-
readonly
|
|
270
|
+
readonly "aria-hidden": "true";
|
|
270
271
|
readonly "data-command-separator": "";
|
|
271
272
|
};
|
|
272
273
|
}
|
|
@@ -44,6 +44,8 @@ class CommandRootState {
|
|
|
44
44
|
commandState = $state.raw(null);
|
|
45
45
|
// internal state that we mutate in batches and publish to the `state` at once
|
|
46
46
|
_commandState = $state(null);
|
|
47
|
+
// whether the search has had a value other than ""
|
|
48
|
+
searchHasHadValue = $state(false);
|
|
47
49
|
#snapshot() {
|
|
48
50
|
return $state.snapshot(this._commandState);
|
|
49
51
|
}
|
|
@@ -70,6 +72,9 @@ class CommandRootState {
|
|
|
70
72
|
this.#filterItems();
|
|
71
73
|
this.#sort();
|
|
72
74
|
this.#selectFirstItem();
|
|
75
|
+
afterTick(() => {
|
|
76
|
+
this.#selectFirstItem();
|
|
77
|
+
});
|
|
73
78
|
}
|
|
74
79
|
else if (key === "value") {
|
|
75
80
|
// opts is a boolean referring to whether it should NOT be scrolled into view
|
|
@@ -100,6 +105,11 @@ class CommandRootState {
|
|
|
100
105
|
this.commandState = defaultState;
|
|
101
106
|
useRefById(opts);
|
|
102
107
|
this.onkeydown = this.onkeydown.bind(this);
|
|
108
|
+
$effect(() => {
|
|
109
|
+
if (this._commandState.search !== "") {
|
|
110
|
+
this.searchHasHadValue = true;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
103
113
|
}
|
|
104
114
|
/**
|
|
105
115
|
* Calculates score for an item based on search text and keywords.
|
|
@@ -268,7 +278,7 @@ class CommandRootState {
|
|
|
268
278
|
* Special handling for first items in groups.
|
|
269
279
|
*/
|
|
270
280
|
#scrollSelectedIntoView() {
|
|
271
|
-
|
|
281
|
+
afterTick(() => {
|
|
272
282
|
const item = this.#getSelectedItem();
|
|
273
283
|
if (!item)
|
|
274
284
|
return;
|
|
@@ -277,10 +287,10 @@ class CommandRootState {
|
|
|
277
287
|
return;
|
|
278
288
|
const firstChildOfParent = getFirstNonCommentChild(grandparent);
|
|
279
289
|
if (firstChildOfParent && firstChildOfParent.dataset?.value === item.dataset?.value) {
|
|
280
|
-
item
|
|
290
|
+
const closestGroupHeader = item
|
|
281
291
|
?.closest(COMMAND_GROUP_SELECTOR)
|
|
282
|
-
?.querySelector(COMMAND_GROUP_HEADING_SELECTOR)
|
|
283
|
-
|
|
292
|
+
?.querySelector(COMMAND_GROUP_HEADING_SELECTOR);
|
|
293
|
+
closestGroupHeader?.scrollIntoView({ block: "nearest" });
|
|
284
294
|
return;
|
|
285
295
|
}
|
|
286
296
|
item.scrollIntoView({ block: "nearest" });
|
|
@@ -419,15 +429,16 @@ class CommandRootState {
|
|
|
419
429
|
this.#sort();
|
|
420
430
|
this.#scheduleUpdate();
|
|
421
431
|
return () => {
|
|
432
|
+
const selectedItem = this.#getSelectedItem();
|
|
422
433
|
this.allIds.delete(id);
|
|
423
434
|
this.allItems.delete(id);
|
|
424
435
|
this.commandState.filtered.items.delete(id);
|
|
425
|
-
const selectedItem = this.#getSelectedItem();
|
|
426
436
|
this.#filterItems();
|
|
427
437
|
// The item removed have been the selected one,
|
|
428
438
|
// so selection should be moved to the first
|
|
429
|
-
if (selectedItem?.getAttribute("id") === id)
|
|
439
|
+
if (selectedItem?.getAttribute("id") === id) {
|
|
430
440
|
this.#selectFirstItem();
|
|
441
|
+
}
|
|
431
442
|
this.#scheduleUpdate();
|
|
432
443
|
};
|
|
433
444
|
}
|
|
@@ -558,12 +569,16 @@ class CommandEmptyState {
|
|
|
558
569
|
opts;
|
|
559
570
|
root;
|
|
560
571
|
#isInitialRender = true;
|
|
561
|
-
shouldRender = $derived.by(() =>
|
|
562
|
-
this.
|
|
572
|
+
shouldRender = $derived.by(() => {
|
|
573
|
+
return ((this.root._commandState.filtered.count === 0 &&
|
|
574
|
+
this.#isInitialRender === false &&
|
|
575
|
+
this.root.searchHasHadValue) ||
|
|
576
|
+
this.opts.forceMount.current);
|
|
577
|
+
});
|
|
563
578
|
constructor(opts, root) {
|
|
564
579
|
this.opts = opts;
|
|
565
580
|
this.root = root;
|
|
566
|
-
$effect(() => {
|
|
581
|
+
$effect.pre(() => {
|
|
567
582
|
this.#isInitialRender = false;
|
|
568
583
|
});
|
|
569
584
|
useRefById({
|
|
@@ -599,7 +614,7 @@ class CommandGroupContainerState {
|
|
|
599
614
|
...opts,
|
|
600
615
|
deps: () => this.shouldRender,
|
|
601
616
|
});
|
|
602
|
-
|
|
617
|
+
watch(() => this.opts.id.current, () => {
|
|
603
618
|
return this.root.registerGroup(this.opts.id.current);
|
|
604
619
|
});
|
|
605
620
|
$effect(() => {
|
|
@@ -712,6 +727,7 @@ class CommandItemState {
|
|
|
712
727
|
});
|
|
713
728
|
trueValue = $state("");
|
|
714
729
|
shouldRender = $derived.by(() => {
|
|
730
|
+
this.opts.ref.current;
|
|
715
731
|
if (this.#trueForceMount ||
|
|
716
732
|
this.root.opts.shouldFilter.current === false ||
|
|
717
733
|
!this.root.commandState.search) {
|
|
@@ -736,6 +752,7 @@ class CommandItemState {
|
|
|
736
752
|
() => this.opts.id.current,
|
|
737
753
|
() => this.#group?.opts.id.current,
|
|
738
754
|
() => this.opts.forceMount.current,
|
|
755
|
+
() => this.opts.ref.current,
|
|
739
756
|
], () => {
|
|
740
757
|
if (this.opts.forceMount.current)
|
|
741
758
|
return;
|
|
@@ -807,7 +824,7 @@ class CommandLoadingState {
|
|
|
807
824
|
class CommandSeparatorState {
|
|
808
825
|
opts;
|
|
809
826
|
root;
|
|
810
|
-
shouldRender = $derived.by(() => !this.root.
|
|
827
|
+
shouldRender = $derived.by(() => !this.root._commandState.search || this.opts.forceMount.current);
|
|
811
828
|
constructor(opts, root) {
|
|
812
829
|
this.opts = opts;
|
|
813
830
|
this.root = root;
|
|
@@ -818,7 +835,8 @@ class CommandSeparatorState {
|
|
|
818
835
|
}
|
|
819
836
|
props = $derived.by(() => ({
|
|
820
837
|
id: this.opts.id.current,
|
|
821
|
-
role
|
|
838
|
+
// role="separator" cannot belong to a role="listbox"
|
|
839
|
+
"aria-hidden": "true",
|
|
822
840
|
[COMMAND_SEPARATOR_ATTR]: "",
|
|
823
841
|
}));
|
|
824
842
|
}
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
37
|
{#key itemState.root.key}
|
|
38
|
-
<div style="display: contents;" data-item-wrapper data-value={
|
|
38
|
+
<div style="display: contents;" data-item-wrapper data-value={itemState.trueValue}>
|
|
39
39
|
{#if itemState.shouldRender}
|
|
40
40
|
{#if child}
|
|
41
41
|
{@render child({ props: mergedProps })}
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
const mergedProps = $derived(mergeProps(restProps, listState.props));
|
|
26
26
|
</script>
|
|
27
27
|
|
|
28
|
-
{#
|
|
29
|
-
{
|
|
30
|
-
{:
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
{#key listState.root._commandState.search === ""}
|
|
29
|
+
{#if child}
|
|
30
|
+
{@render child({ props: mergedProps })}
|
|
31
|
+
{:else}
|
|
32
|
+
<div {...mergedProps}>
|
|
33
|
+
{@render children?.()}
|
|
34
|
+
</div>
|
|
35
|
+
{/if}
|
|
36
|
+
{/key}
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
// the default menu behavior of handling outside interactions on the trigger
|
|
24
24
|
onEscapeKeydown = noop,
|
|
25
25
|
forceMount = false,
|
|
26
|
+
trapFocus = true,
|
|
26
27
|
...restProps
|
|
27
28
|
}: ContextMenuContentProps = $props();
|
|
28
29
|
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
onEscapeKeydown={handleEscapeKeydown}
|
|
77
78
|
{onOpenAutoFocus}
|
|
78
79
|
{isValidEvent}
|
|
79
|
-
trapFocus
|
|
80
|
+
{trapFocus}
|
|
80
81
|
{loop}
|
|
81
82
|
{id}
|
|
82
83
|
>
|
|
@@ -109,7 +110,7 @@
|
|
|
109
110
|
onEscapeKeydown={handleEscapeKeydown}
|
|
110
111
|
{onOpenAutoFocus}
|
|
111
112
|
{isValidEvent}
|
|
112
|
-
trapFocus
|
|
113
|
+
{trapFocus}
|
|
113
114
|
{loop}
|
|
114
115
|
{id}
|
|
115
116
|
>
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
onOpenAutoFocus: onOpenAutoFocusProp = noop,
|
|
26
26
|
onCloseAutoFocus: onCloseAutoFocusProp = noop,
|
|
27
27
|
onFocusOutside = noop,
|
|
28
|
+
trapFocus = false,
|
|
28
29
|
...restProps
|
|
29
30
|
}: MenuSubContentStaticProps = $props();
|
|
30
31
|
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
onFocusOutside={handleOnFocusOutside}
|
|
116
117
|
preventScroll={false}
|
|
117
118
|
{loop}
|
|
118
|
-
trapFocus
|
|
119
|
+
{trapFocus}
|
|
119
120
|
isStatic
|
|
120
121
|
>
|
|
121
122
|
{#snippet popper({ props })}
|
|
@@ -145,7 +146,7 @@
|
|
|
145
146
|
onFocusOutside={handleOnFocusOutside}
|
|
146
147
|
preventScroll={false}
|
|
147
148
|
{loop}
|
|
148
|
-
trapFocus
|
|
149
|
+
{trapFocus}
|
|
149
150
|
isStatic
|
|
150
151
|
>
|
|
151
152
|
{#snippet popper({ props })}
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
onCloseAutoFocus: onCloseAutoFocusProp = noop,
|
|
27
27
|
onFocusOutside = noop,
|
|
28
28
|
side = "right",
|
|
29
|
+
trapFocus = false,
|
|
29
30
|
...restProps
|
|
30
31
|
}: MenuSubContentProps = $props();
|
|
31
32
|
|
|
@@ -117,7 +118,7 @@
|
|
|
117
118
|
onFocusOutside={handleOnFocusOutside}
|
|
118
119
|
preventScroll={false}
|
|
119
120
|
{loop}
|
|
120
|
-
trapFocus
|
|
121
|
+
{trapFocus}
|
|
121
122
|
>
|
|
122
123
|
{#snippet popper({ props, wrapperProps })}
|
|
123
124
|
{@const finalProps = mergeProps(props, mergedProps, {
|
|
@@ -152,7 +153,7 @@
|
|
|
152
153
|
onFocusOutside={handleOnFocusOutside}
|
|
153
154
|
preventScroll={false}
|
|
154
155
|
{loop}
|
|
155
|
-
trapFocus
|
|
156
|
+
{trapFocus}
|
|
156
157
|
>
|
|
157
158
|
{#snippet popper({ props, wrapperProps })}
|
|
158
159
|
{@const finalProps = mergeProps(props, mergedProps, {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useRefById } from "svelte-toolbelt";
|
|
2
|
-
import { Context } from "runed";
|
|
2
|
+
import { Context, watch } from "runed";
|
|
3
3
|
import { getAriaChecked, getAriaRequired, getDataDisabled } from "../../internal/attrs.js";
|
|
4
4
|
import { useRovingFocus, } from "../../internal/use-roving-focus.svelte.js";
|
|
5
5
|
import { kbd } from "../../internal/kbd.js";
|
|
@@ -43,6 +43,7 @@ class RadioGroupItemState {
|
|
|
43
43
|
checked = $derived.by(() => this.root.opts.value.current === this.opts.value.current);
|
|
44
44
|
#isDisabled = $derived.by(() => this.opts.disabled.current || this.root.opts.disabled.current);
|
|
45
45
|
#isChecked = $derived.by(() => this.root.isChecked(this.opts.value.current));
|
|
46
|
+
#tabIndex = $state(-1);
|
|
46
47
|
constructor(opts, root) {
|
|
47
48
|
this.opts = opts;
|
|
48
49
|
this.root = root;
|
|
@@ -57,6 +58,12 @@ class RadioGroupItemState {
|
|
|
57
58
|
$effect(() => {
|
|
58
59
|
this.#tabIndex = this.root.rovingFocusGroup.getTabIndex(this.opts.ref.current);
|
|
59
60
|
});
|
|
61
|
+
watch([() => this.opts.value.current, () => this.root.opts.value.current], () => {
|
|
62
|
+
if (this.opts.value.current === this.root.opts.value.current) {
|
|
63
|
+
this.root.rovingFocusGroup.setCurrentTabStopId(this.opts.id.current);
|
|
64
|
+
this.#tabIndex = 0;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
60
67
|
this.onclick = this.onclick.bind(this);
|
|
61
68
|
this.onkeydown = this.onkeydown.bind(this);
|
|
62
69
|
this.onfocus = this.onfocus.bind(this);
|
|
@@ -81,7 +88,6 @@ class RadioGroupItemState {
|
|
|
81
88
|
}
|
|
82
89
|
this.root.rovingFocusGroup.handleKeydown(this.opts.ref.current, e, true);
|
|
83
90
|
}
|
|
84
|
-
#tabIndex = $state(-1);
|
|
85
91
|
snippetProps = $derived.by(() => ({ checked: this.#isChecked }));
|
|
86
92
|
props = $derived.by(() => ({
|
|
87
93
|
id: this.opts.id.current,
|