bits-ui 2.1.0 → 2.2.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.
- package/dist/bits/avatar/avatar.svelte.d.ts +2 -1
- package/dist/bits/avatar/avatar.svelte.js +5 -3
- package/dist/bits/calendar/calendar.svelte.d.ts +2 -0
- package/dist/bits/calendar/calendar.svelte.js +9 -4
- package/dist/bits/combobox/components/combobox-input.svelte +2 -2
- package/dist/bits/combobox/components/combobox.svelte +5 -0
- package/dist/bits/combobox/types.d.ts +18 -1
- package/dist/bits/date-field/date-field.svelte.d.ts +3 -1
- package/dist/bits/date-field/date-field.svelte.js +15 -6
- package/dist/bits/date-range-field/date-range-field.svelte.d.ts +2 -0
- package/dist/bits/date-range-field/date-range-field.svelte.js +4 -2
- package/dist/bits/link-preview/link-preview.svelte.d.ts +2 -0
- package/dist/bits/link-preview/link-preview.svelte.js +11 -6
- package/dist/bits/menu/menu.svelte.d.ts +2 -0
- package/dist/bits/menu/menu.svelte.js +15 -10
- package/dist/bits/navigation-menu/navigation-menu.svelte.d.ts +3 -1
- package/dist/bits/navigation-menu/navigation-menu.svelte.js +21 -11
- package/dist/bits/pin-input/pin-input.svelte.d.ts +4 -2
- package/dist/bits/pin-input/pin-input.svelte.js +17 -13
- package/dist/bits/pin-input/usePasswordManager.svelte.d.ts +3 -2
- package/dist/bits/pin-input/usePasswordManager.svelte.js +6 -5
- package/dist/bits/range-calendar/range-calendar.svelte.d.ts +2 -0
- package/dist/bits/range-calendar/range-calendar.svelte.js +9 -3
- package/dist/bits/scroll-area/scroll-area.svelte.d.ts +2 -0
- package/dist/bits/scroll-area/scroll-area.svelte.js +15 -12
- package/dist/bits/select/components/select.svelte +6 -0
- package/dist/bits/select/select.svelte.d.ts +5 -1
- package/dist/bits/select/select.svelte.js +34 -18
- package/dist/bits/slider/helpers.js +33 -2
- package/dist/bits/time-field/time-field.svelte.d.ts +3 -1
- package/dist/bits/time-field/time-field.svelte.js +15 -6
- package/dist/bits/time-range-field/time-range-field.svelte.d.ts +2 -0
- package/dist/bits/time-range-field/time-range-field.svelte.js +4 -2
- package/dist/bits/tooltip/components/tooltip-content-static.svelte +2 -0
- package/dist/bits/tooltip/components/tooltip-content.svelte +2 -0
- package/dist/bits/tooltip/components/tooltip-trigger.svelte +1 -1
- package/dist/bits/tooltip/components/tooltip.svelte +1 -1
- package/dist/bits/tooltip/tooltip.svelte.d.ts +18 -18
- package/dist/bits/tooltip/tooltip.svelte.js +7 -3
- package/dist/bits/utilities/floating-layer/components/floating-layer-anchor.svelte +9 -6
- package/dist/bits/utilities/floating-layer/components/floating-layer-content.svelte +25 -21
- package/dist/bits/utilities/floating-layer/components/floating-layer.svelte +2 -2
- package/dist/bits/utilities/floating-layer/components/floating-layer.svelte.d.ts +1 -0
- package/dist/bits/utilities/floating-layer/types.d.ts +18 -0
- package/dist/bits/utilities/floating-layer/use-floating-layer.svelte.d.ts +3 -3
- package/dist/bits/utilities/floating-layer/use-floating-layer.svelte.js +16 -11
- package/dist/bits/utilities/focus-scope/use-focus-scope.svelte.js +14 -9
- package/dist/bits/utilities/popper-layer/popper-layer-inner.svelte +2 -0
- package/dist/bits/utilities/popper-layer/types.d.ts +9 -0
- package/dist/bits/utilities/portal/types.d.ts +1 -1
- package/dist/bits/utilities/text-selection-layer/use-text-selection-layer.svelte.d.ts +2 -0
- package/dist/bits/utilities/text-selection-layer/use-text-selection-layer.svelte.js +7 -7
- package/dist/internal/box-auto-reset.svelte.d.ts +7 -1
- package/dist/internal/box-auto-reset.svelte.js +11 -6
- package/dist/internal/date-time/announcer.d.ts +1 -1
- package/dist/internal/date-time/announcer.js +20 -20
- package/dist/internal/date-time/calendar-helpers.svelte.js +7 -5
- package/dist/internal/date-time/field/helpers.d.ts +8 -2
- package/dist/internal/date-time/field/helpers.js +8 -7
- package/dist/internal/date-time/field/time-helpers.d.ts +8 -2
- package/dist/internal/date-time/field/time-helpers.js +9 -9
- package/dist/internal/dom.d.ts +0 -1
- package/dist/internal/dom.js +0 -3
- package/dist/internal/focus.d.ts +2 -2
- package/dist/internal/focus.js +14 -9
- package/dist/internal/math.d.ts +0 -4
- package/dist/internal/math.js +0 -28
- package/dist/internal/tabbable.d.ts +0 -2
- package/dist/internal/tabbable.js +10 -14
- package/dist/internal/use-data-typeahead.svelte.d.ts +1 -0
- package/dist/internal/use-data-typeahead.svelte.js +4 -1
- package/dist/internal/use-dom-typeahead.svelte.d.ts +3 -1
- package/dist/internal/use-dom-typeahead.svelte.js +5 -2
- package/dist/internal/use-grace-area.svelte.js +9 -5
- package/package.json +2 -2
- package/dist/internal/dom-context.svelte.d.ts +0 -9
- package/dist/internal/dom-context.svelte.js +0 -26
- package/dist/internal/use-size.svelte.d.ts +0 -7
- package/dist/internal/use-size.svelte.js +0 -54
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReadableBox, type WritableBox } from "svelte-toolbelt";
|
|
1
|
+
import { DOMContext, type ReadableBox, type WritableBox } from "svelte-toolbelt";
|
|
2
2
|
import type { HTMLImgAttributes } from "svelte/elements";
|
|
3
3
|
import type { AvatarImageLoadingStatus } from "./types.js";
|
|
4
4
|
import type { ReadableBoxedValues } from "../../internal/box.svelte.js";
|
|
@@ -15,6 +15,7 @@ type AvatarRootStateProps = WithRefProps<{
|
|
|
15
15
|
type AvatarImageSrc = string | null | undefined;
|
|
16
16
|
declare class AvatarRootState {
|
|
17
17
|
readonly opts: AvatarRootStateProps;
|
|
18
|
+
readonly domContext: DOMContext;
|
|
18
19
|
constructor(opts: AvatarRootStateProps);
|
|
19
20
|
loadImage(src: string, crossorigin?: CrossOrigin, referrerPolicy?: ReferrerPolicy): (() => void) | undefined;
|
|
20
21
|
props: {
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { untrack } from "svelte";
|
|
2
|
-
import { attachRef } from "svelte-toolbelt";
|
|
2
|
+
import { DOMContext, attachRef } from "svelte-toolbelt";
|
|
3
3
|
import { Context } from "runed";
|
|
4
4
|
const AVATAR_ROOT_ATTR = "data-avatar-root";
|
|
5
5
|
const AVATAR_IMAGE_ATTR = "data-avatar-image";
|
|
6
6
|
const AVATAR_FALLBACK_ATTR = "data-avatar-fallback";
|
|
7
7
|
class AvatarRootState {
|
|
8
8
|
opts;
|
|
9
|
+
domContext;
|
|
9
10
|
constructor(opts) {
|
|
10
11
|
this.opts = opts;
|
|
12
|
+
this.domContext = new DOMContext(this.opts.ref);
|
|
11
13
|
this.loadImage = this.loadImage.bind(this);
|
|
12
14
|
}
|
|
13
15
|
loadImage(src, crossorigin, referrerPolicy) {
|
|
@@ -22,7 +24,7 @@ class AvatarRootState {
|
|
|
22
24
|
image.referrerPolicy = referrerPolicy;
|
|
23
25
|
this.opts.loadingStatus.current = "loading";
|
|
24
26
|
image.onload = () => {
|
|
25
|
-
imageTimerId =
|
|
27
|
+
imageTimerId = this.domContext.setTimeout(() => {
|
|
26
28
|
this.opts.loadingStatus.current = "loaded";
|
|
27
29
|
}, this.opts.delayMs.current);
|
|
28
30
|
};
|
|
@@ -30,7 +32,7 @@ class AvatarRootState {
|
|
|
30
32
|
this.opts.loadingStatus.current = "error";
|
|
31
33
|
};
|
|
32
34
|
return () => {
|
|
33
|
-
|
|
35
|
+
this.domContext.clearTimeout(imageTimerId);
|
|
34
36
|
};
|
|
35
37
|
}
|
|
36
38
|
props = $derived.by(() => ({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type DateValue } from "@internationalized/date";
|
|
2
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
2
3
|
import { Context } from "runed";
|
|
3
4
|
import type { RangeCalendarRootState } from "../range-calendar/range-calendar.svelte.js";
|
|
4
5
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
@@ -45,6 +46,7 @@ export declare class CalendarRootState {
|
|
|
45
46
|
announcer: Announcer;
|
|
46
47
|
formatter: Formatter;
|
|
47
48
|
accessibleHeadingId: string;
|
|
49
|
+
domContext: DOMContext;
|
|
48
50
|
constructor(opts: CalendarRootStateProps);
|
|
49
51
|
setMonths(months: Month<DateValue>[]): void;
|
|
50
52
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getLocalTimeZone, isSameDay, isSameMonth, isToday, } from "@internationalized/date";
|
|
2
2
|
import { DEV } from "esm-env";
|
|
3
|
-
import { untrack } from "svelte";
|
|
4
|
-
import { attachRef } from "svelte-toolbelt";
|
|
3
|
+
import { onMount, untrack } from "svelte";
|
|
4
|
+
import { attachRef, DOMContext } from "svelte-toolbelt";
|
|
5
5
|
import { Context, watch } from "runed";
|
|
6
6
|
import { getAriaDisabled, getAriaHidden, getAriaReadonly, getAriaSelected, getDataDisabled, getDataReadonly, getDataSelected, getDataUnavailable, } from "../../internal/attrs.js";
|
|
7
7
|
import { useId } from "../../internal/use-id.js";
|
|
@@ -16,9 +16,11 @@ export class CalendarRootState {
|
|
|
16
16
|
announcer;
|
|
17
17
|
formatter;
|
|
18
18
|
accessibleHeadingId = useId();
|
|
19
|
+
domContext;
|
|
19
20
|
constructor(opts) {
|
|
20
21
|
this.opts = opts;
|
|
21
|
-
this.
|
|
22
|
+
this.domContext = new DOMContext(opts.ref);
|
|
23
|
+
this.announcer = getAnnouncer(null);
|
|
22
24
|
this.formatter = createFormatter(this.opts.locale.current);
|
|
23
25
|
this.setMonths = this.setMonths.bind(this);
|
|
24
26
|
this.nextPage = this.nextPage.bind(this);
|
|
@@ -36,6 +38,9 @@ export class CalendarRootState {
|
|
|
36
38
|
this.handleSingleUpdate = this.handleSingleUpdate.bind(this);
|
|
37
39
|
this.onkeydown = this.onkeydown.bind(this);
|
|
38
40
|
this.getBitsAttr = this.getBitsAttr.bind(this);
|
|
41
|
+
onMount(() => {
|
|
42
|
+
this.announcer = getAnnouncer(this.domContext.getDocument());
|
|
43
|
+
});
|
|
39
44
|
this.months = createMonths({
|
|
40
45
|
dateObj: this.opts.placeholder.current,
|
|
41
46
|
weekStartsOn: this.opts.weekStartsOn.current,
|
|
@@ -75,7 +80,7 @@ export class CalendarRootState {
|
|
|
75
80
|
* changes.
|
|
76
81
|
*/
|
|
77
82
|
$effect(() => {
|
|
78
|
-
const node =
|
|
83
|
+
const node = this.domContext.getElementById(this.accessibleHeadingId);
|
|
79
84
|
if (!node)
|
|
80
85
|
return;
|
|
81
86
|
node.textContent = this.fullCalendarLabel;
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
if (defaultValue) {
|
|
27
|
-
inputState.root.inputValue = defaultValue;
|
|
27
|
+
inputState.root.opts.inputValue.current = defaultValue;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const mergedProps = $derived(
|
|
31
|
-
mergeProps(restProps, inputState.props, { value: inputState.root.inputValue })
|
|
31
|
+
mergeProps(restProps, inputState.props, { value: inputState.root.opts.inputValue.current })
|
|
32
32
|
);
|
|
33
33
|
</script>
|
|
34
34
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
required = false,
|
|
21
21
|
items = [],
|
|
22
22
|
allowDeselect = true,
|
|
23
|
+
inputValue = "",
|
|
23
24
|
children,
|
|
24
25
|
}: ComboboxRootProps = $props();
|
|
25
26
|
|
|
@@ -61,6 +62,10 @@
|
|
|
61
62
|
isCombobox: true,
|
|
62
63
|
items: box.with(() => items),
|
|
63
64
|
allowDeselect: box.with(() => allowDeselect),
|
|
65
|
+
inputValue: box.with(
|
|
66
|
+
() => inputValue,
|
|
67
|
+
(v) => (inputValue = v)
|
|
68
|
+
),
|
|
64
69
|
});
|
|
65
70
|
</script>
|
|
66
71
|
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import type { BitsPrimitiveInputAttributes } from "../../shared/attributes.js";
|
|
2
|
+
import type { SelectBaseRootPropsWithoutHTML, SelectMultipleRootPropsWithoutHTML, SelectSingleRootPropsWithoutHTML } from "../select/types.js";
|
|
2
3
|
import type { WithChild, Without } from "../../internal/types.js";
|
|
3
|
-
export type
|
|
4
|
+
export type ComboboxBaseRootPropsWithoutHTML = SelectBaseRootPropsWithoutHTML & {
|
|
5
|
+
/**
|
|
6
|
+
* A read-only value that can be used to programmatically
|
|
7
|
+
* update the input value.
|
|
8
|
+
*
|
|
9
|
+
* This is useful for updating the displayed label/input
|
|
10
|
+
* when the value changes outside of Bits UI.
|
|
11
|
+
*/
|
|
12
|
+
inputValue?: string;
|
|
13
|
+
};
|
|
14
|
+
export type ComboboxSingleRootPropsWithoutHTML = ComboboxBaseRootPropsWithoutHTML & SelectSingleRootPropsWithoutHTML;
|
|
15
|
+
export type ComboboxSingleRootProps = ComboboxSingleRootPropsWithoutHTML;
|
|
16
|
+
export type ComboboxMultipleRootPropsWithoutHTML = ComboboxBaseRootPropsWithoutHTML & SelectMultipleRootPropsWithoutHTML;
|
|
17
|
+
export type ComboboxMultipleRootProps = ComboboxMultipleRootPropsWithoutHTML;
|
|
18
|
+
export type ComboboxRootPropsWithoutHTML = ComboboxBaseRootPropsWithoutHTML & (ComboboxSingleRootPropsWithoutHTML | ComboboxMultipleRootPropsWithoutHTML);
|
|
19
|
+
export type ComboboxRootProps = ComboboxRootPropsWithoutHTML;
|
|
20
|
+
export type { SelectContentProps as ComboboxContentProps, SelectContentPropsWithoutHTML as ComboboxContentPropsWithoutHTML, SelectContentStaticProps as ComboboxContentStaticProps, SelectContentStaticPropsWithoutHTML as ComboboxContentStaticPropsWithoutHTML, SelectItemProps as ComboboxItemProps, SelectItemPropsWithoutHTML as ComboboxItemPropsWithoutHTML, SelectItemSnippetProps as ComboboxItemSnippetProps, SelectTriggerProps as ComboboxTriggerProps, SelectTriggerPropsWithoutHTML as ComboboxTriggerPropsWithoutHTML, SelectGroupPropsWithoutHTML as ComboboxGroupPropsWithoutHTML, SelectGroupProps as ComboboxGroupProps, SelectGroupHeadingPropsWithoutHTML as ComboboxGroupHeadingPropsWithoutHTML, SelectGroupHeadingProps as ComboboxGroupHeadingProps, SelectViewportPropsWithoutHTML as ComboboxViewportPropsWithoutHTML, SelectViewportProps as ComboboxViewportProps, SelectScrollDownButtonProps as ComboboxScrollDownButtonProps, SelectScrollDownButtonPropsWithoutHTML as ComboboxScrollDownButtonPropsWithoutHTML, SelectScrollUpButtonProps as ComboboxScrollUpButtonProps, SelectScrollUpButtonPropsWithoutHTML as ComboboxScrollUpButtonPropsWithoutHTML, SelectArrowProps as ComboboxArrowProps, SelectArrowPropsWithoutHTML as ComboboxArrowPropsWithoutHTML, SelectPortalProps as ComboboxPortalProps, SelectPortalPropsWithoutHTML as ComboboxPortalPropsWithoutHTML, } from "../select/types.js";
|
|
4
21
|
export type ComboboxInputPropsWithoutHTML = WithChild<{
|
|
5
22
|
/**
|
|
6
23
|
* The default value of the input. This is not a reactive prop and is only used to populate
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Updater } from "svelte/store";
|
|
2
2
|
import type { DateValue } from "@internationalized/date";
|
|
3
|
-
import { type WritableBox } from "svelte-toolbelt";
|
|
3
|
+
import { type WritableBox, DOMContext } from "svelte-toolbelt";
|
|
4
4
|
import type { DateRangeFieldRootState } from "../date-range-field/date-range-field.svelte.js";
|
|
5
5
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
6
6
|
import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, WithRefProps } from "../../internal/types.js";
|
|
@@ -74,6 +74,7 @@ export declare class DateFieldRootState {
|
|
|
74
74
|
dayPeriodNode: HTMLElement | null;
|
|
75
75
|
rangeRoot: DateRangeFieldRootState | undefined;
|
|
76
76
|
name: string;
|
|
77
|
+
domContext: DOMContext;
|
|
77
78
|
constructor(props: DateFieldRootStateProps, rangeRoot?: DateRangeFieldRootState);
|
|
78
79
|
setName(name: string): void;
|
|
79
80
|
/**
|
|
@@ -165,6 +166,7 @@ export declare class DateFieldInputState {
|
|
|
165
166
|
#private;
|
|
166
167
|
readonly opts: DateFieldInputStateProps;
|
|
167
168
|
readonly root: DateFieldRootState;
|
|
169
|
+
readonly domContext: DOMContext;
|
|
168
170
|
constructor(opts: DateFieldInputStateProps, root: DateFieldRootState);
|
|
169
171
|
props: {
|
|
170
172
|
readonly id: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { box, onDestroyEffect, attachRef } from "svelte-toolbelt";
|
|
1
|
+
import { box, onDestroyEffect, attachRef, DOMContext } from "svelte-toolbelt";
|
|
2
2
|
import { onMount, untrack } from "svelte";
|
|
3
3
|
import { Context, watch } from "runed";
|
|
4
4
|
import { getAriaDisabled, getAriaHidden, getAriaInvalid, getAriaReadonly, getDataDisabled, getDataInvalid, getDataReadonly, } from "../../internal/attrs.js";
|
|
@@ -99,6 +99,7 @@ export class DateFieldRootState {
|
|
|
99
99
|
dayPeriodNode = $state(null);
|
|
100
100
|
rangeRoot = undefined;
|
|
101
101
|
name = $state("");
|
|
102
|
+
domContext = new DOMContext(() => null);
|
|
102
103
|
constructor(props, rangeRoot) {
|
|
103
104
|
this.rangeRoot = rangeRoot;
|
|
104
105
|
/**
|
|
@@ -127,7 +128,7 @@ export class DateFieldRootState {
|
|
|
127
128
|
this.formatter = createFormatter(this.locale.current);
|
|
128
129
|
this.initialSegments = initializeSegmentValues(this.inferredGranularity);
|
|
129
130
|
this.segmentValues = this.initialSegments;
|
|
130
|
-
this.announcer = getAnnouncer();
|
|
131
|
+
this.announcer = getAnnouncer(null);
|
|
131
132
|
this.getFieldNode = this.getFieldNode.bind(this);
|
|
132
133
|
this.updateSegment = this.updateSegment.bind(this);
|
|
133
134
|
this.handleSegmentClick = this.handleSegmentClick.bind(this);
|
|
@@ -138,12 +139,12 @@ export class DateFieldRootState {
|
|
|
138
139
|
});
|
|
139
140
|
});
|
|
140
141
|
onMount(() => {
|
|
141
|
-
this.announcer = getAnnouncer();
|
|
142
|
+
this.announcer = getAnnouncer(this.domContext.getDocument());
|
|
142
143
|
});
|
|
143
144
|
onDestroyEffect(() => {
|
|
144
145
|
if (rangeRoot)
|
|
145
146
|
return;
|
|
146
|
-
removeDescriptionElement(this.descriptionId);
|
|
147
|
+
removeDescriptionElement(this.descriptionId, this.domContext.getDocument());
|
|
147
148
|
});
|
|
148
149
|
$effect(() => {
|
|
149
150
|
if (rangeRoot)
|
|
@@ -157,7 +158,12 @@ export class DateFieldRootState {
|
|
|
157
158
|
return;
|
|
158
159
|
if (this.value.current) {
|
|
159
160
|
const descriptionId = untrack(() => this.descriptionId);
|
|
160
|
-
setDescription(
|
|
161
|
+
setDescription({
|
|
162
|
+
id: descriptionId,
|
|
163
|
+
formatter: this.formatter,
|
|
164
|
+
value: this.value.current,
|
|
165
|
+
doc: this.domContext.getDocument(),
|
|
166
|
+
});
|
|
161
167
|
}
|
|
162
168
|
const placeholder = untrack(() => this.placeholder.current);
|
|
163
169
|
if (this.value.current && placeholder !== this.value.current) {
|
|
@@ -553,9 +559,12 @@ export class DateFieldRootState {
|
|
|
553
559
|
export class DateFieldInputState {
|
|
554
560
|
opts;
|
|
555
561
|
root;
|
|
562
|
+
domContext;
|
|
556
563
|
constructor(opts, root) {
|
|
557
564
|
this.opts = opts;
|
|
558
565
|
this.root = root;
|
|
566
|
+
this.domContext = new DOMContext(opts.ref);
|
|
567
|
+
this.root.domContext = this.domContext;
|
|
559
568
|
$effect(() => {
|
|
560
569
|
this.root.setName(this.opts.name.current);
|
|
561
570
|
});
|
|
@@ -563,7 +572,7 @@ export class DateFieldInputState {
|
|
|
563
572
|
#ariaDescribedBy = $derived.by(() => {
|
|
564
573
|
if (!isBrowser)
|
|
565
574
|
return undefined;
|
|
566
|
-
const doesDescriptionExist =
|
|
575
|
+
const doesDescriptionExist = this.domContext.getElementById(this.root.descriptionId);
|
|
567
576
|
if (!doesDescriptionExist)
|
|
568
577
|
return undefined;
|
|
569
578
|
return this.root.descriptionId;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DateValue } from "@internationalized/date";
|
|
2
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
2
3
|
import { Context } from "runed";
|
|
3
4
|
import type { DateFieldRootState } from "../date-field/date-field.svelte.js";
|
|
4
5
|
import { DateFieldInputState } from "../date-field/date-field.svelte.js";
|
|
@@ -41,6 +42,7 @@ export declare class DateRangeFieldRootState {
|
|
|
41
42
|
startValueComplete: boolean;
|
|
42
43
|
endValueComplete: boolean;
|
|
43
44
|
rangeComplete: boolean;
|
|
45
|
+
domContext: DOMContext;
|
|
44
46
|
constructor(opts: DateRangeFieldRootStateProps);
|
|
45
47
|
validationStatus: false | {
|
|
46
48
|
readonly reason: "custom";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { box, onDestroyEffect, attachRef } from "svelte-toolbelt";
|
|
1
|
+
import { box, onDestroyEffect, attachRef, DOMContext } from "svelte-toolbelt";
|
|
2
2
|
import { Context, watch } from "runed";
|
|
3
3
|
import { DateFieldInputState, useDateFieldRoot } from "../date-field/date-field.svelte.js";
|
|
4
4
|
import { useId } from "../../internal/use-id.js";
|
|
@@ -21,11 +21,13 @@ export class DateRangeFieldRootState {
|
|
|
21
21
|
startValueComplete = $derived.by(() => this.opts.startValue.current !== undefined);
|
|
22
22
|
endValueComplete = $derived.by(() => this.opts.endValue.current !== undefined);
|
|
23
23
|
rangeComplete = $derived(this.startValueComplete && this.endValueComplete);
|
|
24
|
+
domContext;
|
|
24
25
|
constructor(opts) {
|
|
25
26
|
this.opts = opts;
|
|
26
27
|
this.formatter = createFormatter(this.opts.locale.current);
|
|
28
|
+
this.domContext = new DOMContext(this.opts.ref);
|
|
27
29
|
onDestroyEffect(() => {
|
|
28
|
-
removeDescriptionElement(this.descriptionId);
|
|
30
|
+
removeDescriptionElement(this.descriptionId, this.domContext.getDocument());
|
|
29
31
|
});
|
|
30
32
|
$effect(() => {
|
|
31
33
|
if (this.formatter.getLocale() === this.opts.locale.current)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
1
2
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
2
3
|
import type { BitsFocusEvent, BitsPointerEvent, WithRefProps } from "../../internal/types.js";
|
|
3
4
|
type LinkPreviewRootStateProps = WritableBoxedValues<{
|
|
@@ -16,6 +17,7 @@ declare class LinkPreviewRootState {
|
|
|
16
17
|
contentMounted: boolean;
|
|
17
18
|
triggerNode: HTMLElement | null;
|
|
18
19
|
isOpening: boolean;
|
|
20
|
+
domContext: DOMContext;
|
|
19
21
|
constructor(opts: LinkPreviewRootStateProps);
|
|
20
22
|
clearTimeout(): void;
|
|
21
23
|
handleOpen(): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterSleep, onDestroyEffect, attachRef } from "svelte-toolbelt";
|
|
1
|
+
import { afterSleep, onDestroyEffect, attachRef, DOMContext } from "svelte-toolbelt";
|
|
2
2
|
import { Context, watch } from "runed";
|
|
3
3
|
import { on } from "svelte/events";
|
|
4
4
|
import { getAriaExpanded, getDataOpenClosed } from "../../internal/attrs.js";
|
|
@@ -17,6 +17,7 @@ class LinkPreviewRootState {
|
|
|
17
17
|
contentMounted = $state(false);
|
|
18
18
|
triggerNode = $state(null);
|
|
19
19
|
isOpening = false;
|
|
20
|
+
domContext = new DOMContext(() => null);
|
|
20
21
|
constructor(opts) {
|
|
21
22
|
this.opts = opts;
|
|
22
23
|
watch(() => this.opts.open.current, (isOpen) => {
|
|
@@ -24,11 +25,13 @@ class LinkPreviewRootState {
|
|
|
24
25
|
this.hasSelection = false;
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
28
|
+
if (!this.domContext)
|
|
29
|
+
return;
|
|
27
30
|
const handlePointerUp = () => {
|
|
28
31
|
this.containsSelection = false;
|
|
29
32
|
this.isPointerDownOnContent = false;
|
|
30
33
|
afterSleep(1, () => {
|
|
31
|
-
const isSelection =
|
|
34
|
+
const isSelection = this.domContext.getDocument().getSelection()?.toString() !== "";
|
|
32
35
|
if (isSelection) {
|
|
33
36
|
this.hasSelection = true;
|
|
34
37
|
}
|
|
@@ -37,7 +40,7 @@ class LinkPreviewRootState {
|
|
|
37
40
|
}
|
|
38
41
|
});
|
|
39
42
|
};
|
|
40
|
-
const unsubListener = on(
|
|
43
|
+
const unsubListener = on(this.domContext.getDocument(), "pointerup", handlePointerUp);
|
|
41
44
|
if (!this.contentNode)
|
|
42
45
|
return;
|
|
43
46
|
const tabCandidates = getTabbableCandidates(this.contentNode);
|
|
@@ -53,7 +56,7 @@ class LinkPreviewRootState {
|
|
|
53
56
|
}
|
|
54
57
|
clearTimeout() {
|
|
55
58
|
if (this.timeout) {
|
|
56
|
-
|
|
59
|
+
this.domContext.clearTimeout(this.timeout);
|
|
57
60
|
this.timeout = null;
|
|
58
61
|
}
|
|
59
62
|
}
|
|
@@ -62,7 +65,7 @@ class LinkPreviewRootState {
|
|
|
62
65
|
if (this.opts.open.current)
|
|
63
66
|
return;
|
|
64
67
|
this.isOpening = true;
|
|
65
|
-
this.timeout =
|
|
68
|
+
this.timeout = this.domContext.setTimeout(() => {
|
|
66
69
|
if (this.isOpening) {
|
|
67
70
|
this.opts.open.current = true;
|
|
68
71
|
this.isOpening = false;
|
|
@@ -78,7 +81,7 @@ class LinkPreviewRootState {
|
|
|
78
81
|
this.isOpening = false;
|
|
79
82
|
this.clearTimeout();
|
|
80
83
|
if (!this.isPointerDownOnContent && !this.hasSelection) {
|
|
81
|
-
this.timeout =
|
|
84
|
+
this.timeout = this.domContext.setTimeout(() => {
|
|
82
85
|
this.opts.open.current = false;
|
|
83
86
|
}, this.opts.closeDelay.current);
|
|
84
87
|
}
|
|
@@ -90,6 +93,7 @@ class LinkPreviewTriggerState {
|
|
|
90
93
|
constructor(opts, root) {
|
|
91
94
|
this.opts = opts;
|
|
92
95
|
this.root = root;
|
|
96
|
+
this.root.domContext = new DOMContext(opts.ref);
|
|
93
97
|
this.onpointerenter = this.onpointerenter.bind(this);
|
|
94
98
|
this.onpointerleave = this.onpointerleave.bind(this);
|
|
95
99
|
this.onfocus = this.onfocus.bind(this);
|
|
@@ -136,6 +140,7 @@ class LinkPreviewContentState {
|
|
|
136
140
|
constructor(opts, root) {
|
|
137
141
|
this.opts = opts;
|
|
138
142
|
this.root = root;
|
|
143
|
+
this.root.domContext = new DOMContext(opts.ref);
|
|
139
144
|
this.onpointerdown = this.onpointerdown.bind(this);
|
|
140
145
|
this.onpointerenter = this.onpointerenter.bind(this);
|
|
141
146
|
this.onfocusout = this.onfocusout.bind(this);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
1
2
|
import { Context } from "runed";
|
|
2
3
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
3
4
|
import { CustomEventDispatcher } from "../../internal/events.js";
|
|
@@ -52,6 +53,7 @@ declare class MenuContentState {
|
|
|
52
53
|
search: string;
|
|
53
54
|
rovingFocusGroup: ReturnType<typeof useRovingFocus>;
|
|
54
55
|
mounted: boolean;
|
|
56
|
+
domContext: DOMContext;
|
|
55
57
|
constructor(opts: MenuContentStateProps, parentMenu: MenuMenuState);
|
|
56
58
|
onCloseAutoFocus: (e: Event) => void;
|
|
57
59
|
handleTabKeyDown(e: BitsKeyboardEvent): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterTick, box, mergeProps, onDestroyEffect, attachRef } from "svelte-toolbelt";
|
|
1
|
+
import { afterTick, box, mergeProps, onDestroyEffect, attachRef, DOMContext, getWindow, } from "svelte-toolbelt";
|
|
2
2
|
import { Context, watch } from "runed";
|
|
3
3
|
import { FIRST_LAST_KEYS, LAST_KEYS, SELECTION_KEYS, SUB_OPEN_KEYS, getCheckedState, isMouseEvent, } from "./utils.js";
|
|
4
4
|
import { focusFirst } from "../../internal/focus.js";
|
|
@@ -75,9 +75,11 @@ class MenuContentState {
|
|
|
75
75
|
rovingFocusGroup;
|
|
76
76
|
mounted = $state(false);
|
|
77
77
|
#isSub;
|
|
78
|
+
domContext;
|
|
78
79
|
constructor(opts, parentMenu) {
|
|
79
80
|
this.opts = opts;
|
|
80
81
|
this.parentMenu = parentMenu;
|
|
82
|
+
this.domContext = new DOMContext(opts.ref);
|
|
81
83
|
parentMenu.contentId = opts.id;
|
|
82
84
|
this.#isSub = opts.isSub ?? false;
|
|
83
85
|
this.onkeydown = this.onkeydown.bind(this);
|
|
@@ -96,7 +98,10 @@ class MenuContentState {
|
|
|
96
98
|
this.parentMenu.root.isPointerInTransit = value;
|
|
97
99
|
},
|
|
98
100
|
});
|
|
99
|
-
this.#handleTypeaheadSearch = useDOMTypeahead(
|
|
101
|
+
this.#handleTypeaheadSearch = useDOMTypeahead({
|
|
102
|
+
getActiveElement: () => this.domContext.getActiveElement(),
|
|
103
|
+
getWindow: () => this.domContext.getWindow(),
|
|
104
|
+
}).handleTypeaheadSearch;
|
|
100
105
|
this.rovingFocusGroup = useRovingFocus({
|
|
101
106
|
rootNode: box.with(() => this.parentMenu.contentNode),
|
|
102
107
|
candidateAttr: this.parentMenu.root.getAttr("item"),
|
|
@@ -117,7 +122,7 @@ class MenuContentState {
|
|
|
117
122
|
});
|
|
118
123
|
$effect(() => {
|
|
119
124
|
if (!this.parentMenu.opts.open.current) {
|
|
120
|
-
|
|
125
|
+
this.domContext.getWindow().clearTimeout(this.#timer);
|
|
121
126
|
}
|
|
122
127
|
});
|
|
123
128
|
}
|
|
@@ -174,7 +179,7 @@ class MenuContentState {
|
|
|
174
179
|
});
|
|
175
180
|
}
|
|
176
181
|
else {
|
|
177
|
-
|
|
182
|
+
this.domContext.getDocument().body.focus();
|
|
178
183
|
}
|
|
179
184
|
}
|
|
180
185
|
onkeydown(e) {
|
|
@@ -213,7 +218,7 @@ class MenuContentState {
|
|
|
213
218
|
if (LAST_KEYS.includes(e.key)) {
|
|
214
219
|
candidateNodes.reverse();
|
|
215
220
|
}
|
|
216
|
-
focusFirst(candidateNodes);
|
|
221
|
+
focusFirst(candidateNodes, { select: false }, () => this.domContext.getActiveElement());
|
|
217
222
|
}
|
|
218
223
|
onblur(e) {
|
|
219
224
|
if (!isElement(e.currentTarget))
|
|
@@ -222,7 +227,7 @@ class MenuContentState {
|
|
|
222
227
|
return;
|
|
223
228
|
// clear search buffer when leaving the menu
|
|
224
229
|
if (!e.currentTarget.contains?.(e.target)) {
|
|
225
|
-
|
|
230
|
+
this.domContext.getWindow().clearTimeout(this.#timer);
|
|
226
231
|
this.search = "";
|
|
227
232
|
}
|
|
228
233
|
}
|
|
@@ -452,7 +457,7 @@ class MenuSubTriggerState {
|
|
|
452
457
|
#clearOpenTimer() {
|
|
453
458
|
if (this.#openTimer === null)
|
|
454
459
|
return;
|
|
455
|
-
|
|
460
|
+
this.content.domContext.getWindow().clearTimeout(this.#openTimer);
|
|
456
461
|
this.#openTimer = null;
|
|
457
462
|
}
|
|
458
463
|
onpointermove(e) {
|
|
@@ -462,7 +467,7 @@ class MenuSubTriggerState {
|
|
|
462
467
|
!this.submenu.opts.open.current &&
|
|
463
468
|
!this.#openTimer &&
|
|
464
469
|
!this.content.parentMenu.root.isPointerInTransit) {
|
|
465
|
-
this.#openTimer =
|
|
470
|
+
this.#openTimer = this.content.domContext.setTimeout(() => {
|
|
466
471
|
this.submenu.onOpen();
|
|
467
472
|
this.#clearOpenTimer();
|
|
468
473
|
}, 100);
|
|
@@ -757,7 +762,7 @@ class ContextMenuTriggerState {
|
|
|
757
762
|
#clearLongPressTimer() {
|
|
758
763
|
if (this.#longPressTimer === null)
|
|
759
764
|
return;
|
|
760
|
-
|
|
765
|
+
getWindow(this.opts.ref.current).clearTimeout(this.#longPressTimer);
|
|
761
766
|
}
|
|
762
767
|
#handleOpen(e) {
|
|
763
768
|
this.#point = { x: e.clientX, y: e.clientY };
|
|
@@ -775,7 +780,7 @@ class ContextMenuTriggerState {
|
|
|
775
780
|
if (this.opts.disabled.current || isMouseEvent(e))
|
|
776
781
|
return;
|
|
777
782
|
this.#clearLongPressTimer();
|
|
778
|
-
this.#longPressTimer =
|
|
783
|
+
this.#longPressTimer = getWindow(this.opts.ref.current).setTimeout(() => this.#handleOpen(e), 700);
|
|
779
784
|
}
|
|
780
785
|
onpointermove(e) {
|
|
781
786
|
if (this.opts.disabled.current || isMouseEvent(e))
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Based on Radix UI's Navigation Menu
|
|
3
3
|
* https://www.radix-ui.com/docs/primitives/components/navigation-menu
|
|
4
4
|
*/
|
|
5
|
-
import { type AnyFn, type ReadableBox, type ReadableBoxedValues, type WithRefProps, type WritableBox, type WritableBoxedValues } from "svelte-toolbelt";
|
|
5
|
+
import { type AnyFn, type ReadableBox, type ReadableBoxedValues, type WithRefProps, type WritableBox, type WritableBoxedValues, DOMContext } from "svelte-toolbelt";
|
|
6
6
|
import { Context } from "runed";
|
|
7
7
|
import { type Snippet } from "svelte";
|
|
8
8
|
import { SvelteMap } from "svelte/reactivity";
|
|
@@ -125,6 +125,7 @@ export declare class NavigationMenuItemState {
|
|
|
125
125
|
props: Record<string, unknown>;
|
|
126
126
|
}]> | undefined>;
|
|
127
127
|
contentProps: ReadableBox<Record<string, unknown>>;
|
|
128
|
+
domContext: DOMContext;
|
|
128
129
|
constructor(opts: NavigationMenuItemStateProps, listContext: NavigationMenuListState);
|
|
129
130
|
onEntryKeydown: (side?: "start" | "end") => void;
|
|
130
131
|
onFocusProxyEnter: (side?: "start" | "end") => void;
|
|
@@ -294,6 +295,7 @@ declare class NavigationMenuContentImplState {
|
|
|
294
295
|
listContext: NavigationMenuListState;
|
|
295
296
|
prevMotionAttribute: MotionAttribute | null;
|
|
296
297
|
motionAttribute: MotionAttribute | null;
|
|
298
|
+
domContext: DOMContext;
|
|
297
299
|
constructor(opts: NavigationMenuContentImplStateProps, itemContext: NavigationMenuItemState);
|
|
298
300
|
onFocusOutside: (e: Event) => void;
|
|
299
301
|
onInteractOutside: (e: PointerEvent) => void;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Based on Radix UI's Navigation Menu
|
|
3
3
|
* https://www.radix-ui.com/docs/primitives/components/navigation-menu
|
|
4
4
|
*/
|
|
5
|
-
import { afterSleep, afterTick, box, attachRef, } from "svelte-toolbelt";
|
|
5
|
+
import { afterSleep, afterTick, box, attachRef, DOMContext, getWindow, } from "svelte-toolbelt";
|
|
6
6
|
import { Context, useDebounce, watch } from "runed";
|
|
7
7
|
import { untrack } from "svelte";
|
|
8
8
|
import { SvelteMap } from "svelte/reactivity";
|
|
@@ -71,7 +71,10 @@ class NavigationMenuRootState {
|
|
|
71
71
|
});
|
|
72
72
|
constructor(opts) {
|
|
73
73
|
this.opts = opts;
|
|
74
|
-
this.isDelaySkipped = boxAutoReset(false,
|
|
74
|
+
this.isDelaySkipped = boxAutoReset(false, {
|
|
75
|
+
afterMs: this.opts.skipDelayDuration.current,
|
|
76
|
+
getWindow: () => getWindow(opts.ref.current),
|
|
77
|
+
});
|
|
75
78
|
this.provider = useNavigationMenuProvider({
|
|
76
79
|
value: this.opts.value,
|
|
77
80
|
previousValue: this.previousValue,
|
|
@@ -224,9 +227,11 @@ export class NavigationMenuItemState {
|
|
|
224
227
|
contentChildren = box(undefined);
|
|
225
228
|
contentChild = box(undefined);
|
|
226
229
|
contentProps = box({});
|
|
230
|
+
domContext;
|
|
227
231
|
constructor(opts, listContext) {
|
|
228
232
|
this.opts = opts;
|
|
229
233
|
this.listContext = listContext;
|
|
234
|
+
this.domContext = new DOMContext(opts.ref);
|
|
230
235
|
}
|
|
231
236
|
#handleContentEntry = (side = "start") => {
|
|
232
237
|
if (!this.contentNode)
|
|
@@ -234,7 +239,7 @@ export class NavigationMenuItemState {
|
|
|
234
239
|
this.restoreContentTabOrder();
|
|
235
240
|
const candidates = getTabbableCandidates(this.contentNode);
|
|
236
241
|
if (candidates.length)
|
|
237
|
-
focusFirst(side === "start" ? candidates : candidates.reverse());
|
|
242
|
+
focusFirst(side === "start" ? candidates : candidates.reverse(), () => this.domContext.getActiveElement());
|
|
238
243
|
};
|
|
239
244
|
#handleContentExit = () => {
|
|
240
245
|
if (!this.contentNode)
|
|
@@ -265,7 +270,10 @@ class NavigationMenuTriggerState {
|
|
|
265
270
|
focusProxyMounted = $state(false);
|
|
266
271
|
constructor(opts, context) {
|
|
267
272
|
this.opts = opts;
|
|
268
|
-
this.hasPointerMoveOpened = boxAutoReset(false,
|
|
273
|
+
this.hasPointerMoveOpened = boxAutoReset(false, {
|
|
274
|
+
afterMs: 300,
|
|
275
|
+
getWindow: () => getWindow(opts.ref.current),
|
|
276
|
+
});
|
|
269
277
|
this.context = context.provider;
|
|
270
278
|
this.itemContext = context.item;
|
|
271
279
|
this.listContext = context.list;
|
|
@@ -565,11 +573,13 @@ class NavigationMenuContentImplState {
|
|
|
565
573
|
untrack(() => (this.prevMotionAttribute = attribute));
|
|
566
574
|
return attribute;
|
|
567
575
|
});
|
|
576
|
+
domContext;
|
|
568
577
|
constructor(opts, itemContext) {
|
|
569
578
|
this.opts = opts;
|
|
570
579
|
this.itemContext = itemContext;
|
|
571
580
|
this.listContext = itemContext.listContext;
|
|
572
581
|
this.context = itemContext.listContext.context;
|
|
582
|
+
this.domContext = new DOMContext(opts.ref);
|
|
573
583
|
watch([
|
|
574
584
|
() => this.itemContext.opts.value.current,
|
|
575
585
|
() => this.itemContext.triggerNode,
|
|
@@ -581,7 +591,7 @@ class NavigationMenuContentImplState {
|
|
|
581
591
|
const handleClose = () => {
|
|
582
592
|
this.context.onItemDismiss();
|
|
583
593
|
this.itemContext.onRootContentClose();
|
|
584
|
-
if (content.contains(
|
|
594
|
+
if (content.contains(this.domContext.getActiveElement())) {
|
|
585
595
|
this.itemContext.triggerNode?.focus();
|
|
586
596
|
}
|
|
587
597
|
};
|
|
@@ -629,13 +639,13 @@ class NavigationMenuContentImplState {
|
|
|
629
639
|
const isTabKey = e.key === kbd.TAB && !isMetaKey;
|
|
630
640
|
const candidates = getTabbableCandidates(e.currentTarget);
|
|
631
641
|
if (isTabKey) {
|
|
632
|
-
const focusedElement =
|
|
642
|
+
const focusedElement = this.domContext.getActiveElement();
|
|
633
643
|
const index = candidates.findIndex((candidate) => candidate === focusedElement);
|
|
634
644
|
const isMovingBackwards = e.shiftKey;
|
|
635
645
|
const nextCandidates = isMovingBackwards
|
|
636
646
|
? candidates.slice(0, index).reverse()
|
|
637
647
|
: candidates.slice(index + 1, candidates.length);
|
|
638
|
-
if (focusFirst(nextCandidates)) {
|
|
648
|
+
if (focusFirst(nextCandidates, () => this.domContext.getActiveElement())) {
|
|
639
649
|
// prevent browser tab keydown because we've handled focus
|
|
640
650
|
e.preventDefault();
|
|
641
651
|
return;
|
|
@@ -648,7 +658,7 @@ class NavigationMenuContentImplState {
|
|
|
648
658
|
return;
|
|
649
659
|
}
|
|
650
660
|
}
|
|
651
|
-
let activeEl =
|
|
661
|
+
let activeEl = this.domContext.getActiveElement();
|
|
652
662
|
if (this.itemContext.contentNode) {
|
|
653
663
|
const focusedNode = this.itemContext.contentNode.querySelector("[data-focused]");
|
|
654
664
|
if (focusedNode) {
|
|
@@ -798,14 +808,14 @@ export function useNavigationMenuIndicator() {
|
|
|
798
808
|
return new NavigationMenuIndicatorState(NavigationMenuProviderContext.get());
|
|
799
809
|
}
|
|
800
810
|
//
|
|
801
|
-
function focusFirst(candidates) {
|
|
802
|
-
const previouslyFocusedElement =
|
|
811
|
+
function focusFirst(candidates, getActiveElement) {
|
|
812
|
+
const previouslyFocusedElement = getActiveElement();
|
|
803
813
|
return candidates.some((candidate) => {
|
|
804
814
|
// if focus is already where we want to go, we don't want to keep going through the candidates
|
|
805
815
|
if (candidate === previouslyFocusedElement)
|
|
806
816
|
return true;
|
|
807
817
|
candidate.focus();
|
|
808
|
-
return
|
|
818
|
+
return getActiveElement() !== previouslyFocusedElement;
|
|
809
819
|
});
|
|
810
820
|
}
|
|
811
821
|
function removeFromTabOrder(candidates) {
|