bits-ui 2.16.3 → 2.16.5
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/date-field/date-field.svelte.d.ts +5 -0
- package/dist/bits/date-field/date-field.svelte.js +5 -0
- package/dist/bits/menu/menu.svelte.js +14 -0
- package/dist/bits/navigation-menu/navigation-menu.svelte.js +1 -1
- package/dist/bits/select/select.svelte.d.ts +2 -0
- package/dist/bits/select/select.svelte.js +18 -2
- package/dist/bits/tooltip/tooltip.svelte.js +1 -1
- package/dist/bits/utilities/popper-layer/popper-layer-inner.svelte +8 -3
- package/dist/internal/floating-svelte/use-floating.svelte.js +12 -2
- package/package.json +1 -1
|
@@ -135,6 +135,7 @@ export declare class DateFieldRootState {
|
|
|
135
135
|
style: {
|
|
136
136
|
caretColor: string;
|
|
137
137
|
};
|
|
138
|
+
onbeforeinput: (e: InputEvent) => void;
|
|
138
139
|
};
|
|
139
140
|
updateSegment<T extends keyof DateAndTimeSegmentObj>(part: T, cb: T extends DateSegmentPart ? Updater<DateSegmentObj[T]> : T extends EditableTimeSegmentPart ? Updater<TimeSegmentObj[T]> : Updater<DateAndTimeSegmentObj[T]>): void;
|
|
140
141
|
handleSegmentClick(e: BitsMouseEvent): void;
|
|
@@ -256,6 +257,7 @@ declare abstract class BaseNumericSegmentState {
|
|
|
256
257
|
style: {
|
|
257
258
|
caretColor: string;
|
|
258
259
|
};
|
|
260
|
+
onbeforeinput: (e: InputEvent) => void;
|
|
259
261
|
} | {
|
|
260
262
|
"aria-labelledby": string;
|
|
261
263
|
contenteditable: string | undefined;
|
|
@@ -285,6 +287,7 @@ declare abstract class BaseNumericSegmentState {
|
|
|
285
287
|
style: {
|
|
286
288
|
caretColor: string;
|
|
287
289
|
};
|
|
290
|
+
onbeforeinput: (e: InputEvent) => void;
|
|
288
291
|
};
|
|
289
292
|
}
|
|
290
293
|
declare class DateFieldYearSegmentState extends BaseNumericSegmentState {
|
|
@@ -345,6 +348,7 @@ export declare class DateFieldDayPeriodSegmentState {
|
|
|
345
348
|
style: {
|
|
346
349
|
caretColor: string;
|
|
347
350
|
};
|
|
351
|
+
onbeforeinput: (e: InputEvent) => void;
|
|
348
352
|
} | {
|
|
349
353
|
"aria-labelledby": string;
|
|
350
354
|
contenteditable: string | undefined;
|
|
@@ -373,6 +377,7 @@ export declare class DateFieldDayPeriodSegmentState {
|
|
|
373
377
|
style: {
|
|
374
378
|
caretColor: string;
|
|
375
379
|
};
|
|
380
|
+
onbeforeinput: (e: InputEvent) => void;
|
|
376
381
|
} | undefined;
|
|
377
382
|
}
|
|
378
383
|
interface DateFieldLiteralSegmentStateOpts extends WithRefOpts {
|
|
@@ -414,6 +414,11 @@ export class DateFieldRootState {
|
|
|
414
414
|
style: {
|
|
415
415
|
caretColor: "transparent",
|
|
416
416
|
},
|
|
417
|
+
onbeforeinput: (e) => {
|
|
418
|
+
if (!e.data || e.data.length <= 1) {
|
|
419
|
+
e.preventDefault();
|
|
420
|
+
}
|
|
421
|
+
},
|
|
417
422
|
};
|
|
418
423
|
#getLabelledBy(segmentId) {
|
|
419
424
|
return `${segmentId} ${this.getLabelNode()?.id ?? ""}`;
|
|
@@ -183,6 +183,10 @@ export class MenuContentState {
|
|
|
183
183
|
this.opts.onCloseAutoFocus.current?.(e);
|
|
184
184
|
if (e.defaultPrevented || this.#isSub)
|
|
185
185
|
return;
|
|
186
|
+
if (this.parentMenu.root.ignoreCloseAutoFocus) {
|
|
187
|
+
e.preventDefault();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
186
190
|
if (this.parentMenu.triggerNode && isTabbable(this.parentMenu.triggerNode)) {
|
|
187
191
|
e.preventDefault();
|
|
188
192
|
this.parentMenu.triggerNode.focus();
|
|
@@ -306,7 +310,17 @@ export class MenuContentState {
|
|
|
306
310
|
}
|
|
307
311
|
if (e.target.closest(`#${triggerId}`)) {
|
|
308
312
|
e.preventDefault();
|
|
313
|
+
return;
|
|
309
314
|
}
|
|
315
|
+
/**
|
|
316
|
+
* when the menu closes due to an outside pointer interaction (for example,
|
|
317
|
+
* clicking another dropdown trigger), avoid focusing this menu's trigger
|
|
318
|
+
* to prevent stealing focus from the new interaction target.
|
|
319
|
+
*/
|
|
320
|
+
this.parentMenu.root.ignoreCloseAutoFocus = true;
|
|
321
|
+
afterTick(() => {
|
|
322
|
+
this.parentMenu.root.ignoreCloseAutoFocus = false;
|
|
323
|
+
});
|
|
310
324
|
}
|
|
311
325
|
get shouldRender() {
|
|
312
326
|
return this.parentMenu.contentPresence.shouldRender;
|
|
@@ -80,7 +80,7 @@ export class NavigationMenuRootState {
|
|
|
80
80
|
const isOpen = this.opts?.value?.current !== "";
|
|
81
81
|
if (isOpen || this.isDelaySkipped.current) {
|
|
82
82
|
// 150 for user to switch trigger or move into content view
|
|
83
|
-
return
|
|
83
|
+
return 150;
|
|
84
84
|
}
|
|
85
85
|
else {
|
|
86
86
|
return this.opts.delayDuration.current;
|
|
@@ -41,11 +41,13 @@ declare abstract class SelectBaseRootState {
|
|
|
41
41
|
readonly highlightedValue: string | null;
|
|
42
42
|
readonly highlightedId: string | undefined;
|
|
43
43
|
readonly highlightedLabel: string | null;
|
|
44
|
+
contentIsPositioned: boolean;
|
|
44
45
|
isUsingKeyboard: boolean;
|
|
45
46
|
isCombobox: boolean;
|
|
46
47
|
domContext: DOMContext;
|
|
47
48
|
constructor(opts: SelectBaseRootStateOpts);
|
|
48
49
|
setHighlightedNode(node: HTMLElement | null, initial?: boolean): void;
|
|
50
|
+
scrollHighlightedNodeIntoView(node: HTMLElement): void;
|
|
49
51
|
getCandidateNodes(): HTMLElement[];
|
|
50
52
|
setHighlightedToFirstCandidate(initial?: boolean): void;
|
|
51
53
|
getNodeByValue(value: string): HTMLElement | null;
|
|
@@ -65,6 +65,7 @@ class SelectBaseRootState {
|
|
|
65
65
|
return null;
|
|
66
66
|
return this.highlightedNode.getAttribute("data-label");
|
|
67
67
|
});
|
|
68
|
+
contentIsPositioned = $state(false);
|
|
68
69
|
isUsingKeyboard = false;
|
|
69
70
|
isCombobox = false;
|
|
70
71
|
domContext = new DOMContext(() => null);
|
|
@@ -87,9 +88,14 @@ class SelectBaseRootState {
|
|
|
87
88
|
setHighlightedNode(node, initial = false) {
|
|
88
89
|
this.highlightedNode = node;
|
|
89
90
|
if (node && (this.isUsingKeyboard || initial)) {
|
|
90
|
-
|
|
91
|
+
this.scrollHighlightedNodeIntoView(node);
|
|
91
92
|
}
|
|
92
93
|
}
|
|
94
|
+
scrollHighlightedNodeIntoView(node) {
|
|
95
|
+
if (!this.viewportNode || !this.contentIsPositioned)
|
|
96
|
+
return;
|
|
97
|
+
node.scrollIntoView({ block: this.opts.scrollAlignment.current });
|
|
98
|
+
}
|
|
93
99
|
getCandidateNodes() {
|
|
94
100
|
const node = this.contentNode;
|
|
95
101
|
if (!node)
|
|
@@ -713,13 +719,20 @@ export class SelectContentState {
|
|
|
713
719
|
}
|
|
714
720
|
onDestroyEffect(() => {
|
|
715
721
|
this.root.contentNode = null;
|
|
722
|
+
this.root.contentIsPositioned = false;
|
|
716
723
|
this.isPositioned = false;
|
|
717
724
|
});
|
|
718
725
|
watch(() => this.root.opts.open.current, () => {
|
|
719
726
|
if (this.root.opts.open.current)
|
|
720
727
|
return;
|
|
728
|
+
this.root.contentIsPositioned = false;
|
|
721
729
|
this.isPositioned = false;
|
|
722
730
|
});
|
|
731
|
+
watch([() => this.isPositioned, () => this.root.highlightedNode], () => {
|
|
732
|
+
if (!this.isPositioned || !this.root.highlightedNode)
|
|
733
|
+
return;
|
|
734
|
+
this.root.scrollHighlightedNodeIntoView(this.root.highlightedNode);
|
|
735
|
+
});
|
|
723
736
|
this.onpointermove = this.onpointermove.bind(this);
|
|
724
737
|
}
|
|
725
738
|
onpointermove(_) {
|
|
@@ -782,6 +795,7 @@ export class SelectContentState {
|
|
|
782
795
|
// onPlaced is also called when the menu is closed, so we need to check if the menu
|
|
783
796
|
// is actually open to avoid setting positioning to true when the menu is closed
|
|
784
797
|
if (this.root.opts.open.current) {
|
|
798
|
+
this.root.contentIsPositioned = true;
|
|
785
799
|
this.isPositioned = true;
|
|
786
800
|
}
|
|
787
801
|
},
|
|
@@ -1120,7 +1134,9 @@ export class SelectScrollDownButtonState {
|
|
|
1120
1134
|
}
|
|
1121
1135
|
this.scrollIntoViewTimer = afterSleep(5, () => {
|
|
1122
1136
|
const activeItem = this.root.highlightedNode;
|
|
1123
|
-
activeItem
|
|
1137
|
+
if (!activeItem)
|
|
1138
|
+
return;
|
|
1139
|
+
this.root.scrollHighlightedNodeIntoView(activeItem);
|
|
1124
1140
|
});
|
|
1125
1141
|
});
|
|
1126
1142
|
}
|
|
@@ -163,8 +163,8 @@ export class TooltipProviderState {
|
|
|
163
163
|
onClose = (tooltip) => {
|
|
164
164
|
if (this.#openTooltip === tooltip) {
|
|
165
165
|
this.#openTooltip = null;
|
|
166
|
+
this.#startTimer();
|
|
166
167
|
}
|
|
167
|
-
this.#startTimer();
|
|
168
168
|
};
|
|
169
169
|
isTooltipOpen = (tooltip) => {
|
|
170
170
|
return this.#openTooltip === tooltip;
|
|
@@ -52,6 +52,11 @@
|
|
|
52
52
|
enabled: boolean;
|
|
53
53
|
contentPointerEvents?: "auto" | "none";
|
|
54
54
|
} = $props();
|
|
55
|
+
|
|
56
|
+
const resolvedPreventScroll = $derived(preventScroll ?? true);
|
|
57
|
+
const effectiveStrategy = $derived(
|
|
58
|
+
strategy ?? (resolvedPreventScroll ? "fixed" : "absolute")
|
|
59
|
+
);
|
|
55
60
|
</script>
|
|
56
61
|
|
|
57
62
|
<PopperContent
|
|
@@ -68,7 +73,7 @@
|
|
|
68
73
|
{sticky}
|
|
69
74
|
{hideWhenDetached}
|
|
70
75
|
{updatePositionStrategy}
|
|
71
|
-
{
|
|
76
|
+
strategy={effectiveStrategy}
|
|
72
77
|
{dir}
|
|
73
78
|
{wrapperId}
|
|
74
79
|
{style}
|
|
@@ -79,9 +84,9 @@
|
|
|
79
84
|
>
|
|
80
85
|
{#snippet content({ props: floatingProps, wrapperProps })}
|
|
81
86
|
{#if restProps.forceMount && enabled}
|
|
82
|
-
<ScrollLock {
|
|
87
|
+
<ScrollLock preventScroll={resolvedPreventScroll} />
|
|
83
88
|
{:else if !restProps.forceMount}
|
|
84
|
-
<ScrollLock {
|
|
89
|
+
<ScrollLock preventScroll={resolvedPreventScroll} />
|
|
85
90
|
{/if}
|
|
86
91
|
<FocusScope
|
|
87
92
|
{onOpenAutoFocus}
|
|
@@ -23,6 +23,7 @@ export function useFloating(options) {
|
|
|
23
23
|
let middlewareData = $state({});
|
|
24
24
|
let isPositioned = $state(false);
|
|
25
25
|
let hasWhileMountedPosition = false;
|
|
26
|
+
let updateRequestId = 0;
|
|
26
27
|
const floatingStyles = $derived.by(() => {
|
|
27
28
|
// preserve last known position when floating ref is null (during transitions)
|
|
28
29
|
const xVal = floating.current ? roundByDPR(floating.current, x) : x;
|
|
@@ -50,12 +51,20 @@ export function useFloating(options) {
|
|
|
50
51
|
function update() {
|
|
51
52
|
if (reference.current === null || floating.current === null)
|
|
52
53
|
return;
|
|
53
|
-
|
|
54
|
+
const referenceNode = reference.current;
|
|
55
|
+
const floatingNode = floating.current;
|
|
56
|
+
const requestId = ++updateRequestId;
|
|
57
|
+
computePosition(referenceNode, floatingNode, {
|
|
54
58
|
middleware: middlewareOption,
|
|
55
59
|
placement: placementOption,
|
|
56
60
|
strategy: strategyOption,
|
|
57
61
|
}).then((position) => {
|
|
58
|
-
|
|
62
|
+
// ignore stale async resolutions when newer updates were requested.
|
|
63
|
+
if (requestId !== updateRequestId)
|
|
64
|
+
return;
|
|
65
|
+
// ignore stale resolutions after ref replacement.
|
|
66
|
+
if (reference.current !== referenceNode || floating.current !== floatingNode)
|
|
67
|
+
return;
|
|
59
68
|
const referenceHidden = isReferenceHidden(referenceNode);
|
|
60
69
|
if (referenceHidden) {
|
|
61
70
|
// keep last good coordinates when the anchor disappears to avoid
|
|
@@ -91,6 +100,7 @@ export function useFloating(options) {
|
|
|
91
100
|
whileElementsMountedCleanup();
|
|
92
101
|
whileElementsMountedCleanup = undefined;
|
|
93
102
|
}
|
|
103
|
+
updateRequestId++;
|
|
94
104
|
}
|
|
95
105
|
function attach() {
|
|
96
106
|
cleanup();
|