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,6 +1,6 @@
|
|
|
1
1
|
import type { Updater } from "svelte/store";
|
|
2
2
|
import { Time } from "@internationalized/date";
|
|
3
|
-
import { type WritableBox } from "svelte-toolbelt";
|
|
3
|
+
import { type WritableBox, DOMContext } from "svelte-toolbelt";
|
|
4
4
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
5
5
|
import type { BitsFocusEvent, BitsKeyboardEvent, BitsMouseEvent, WithRefProps } from "../../internal/types.js";
|
|
6
6
|
import type { TimeSegmentObj, SegmentPart, HourCycle, TimeValidator, TimeOnInvalid, EditableTimeSegmentPart } from "../../shared/date/types.js";
|
|
@@ -70,6 +70,7 @@ export declare class TimeFieldRootState<T extends TimeValue = Time> {
|
|
|
70
70
|
valueTime: Time | undefined;
|
|
71
71
|
hourCycle: HourCycle;
|
|
72
72
|
rangeRoot: TimeRangeFieldRootState<T> | undefined;
|
|
73
|
+
domContext: DOMContext;
|
|
73
74
|
constructor(props: TimeFieldRootStateProps<T>, rangeRoot?: TimeRangeFieldRootState<T>);
|
|
74
75
|
setName(name: string): void;
|
|
75
76
|
setFieldNode(node: HTMLElement | null): void;
|
|
@@ -149,6 +150,7 @@ export declare class TimeFieldInputState {
|
|
|
149
150
|
#private;
|
|
150
151
|
readonly opts: TimeFieldInputStateProps;
|
|
151
152
|
readonly root: TimeFieldRootState;
|
|
153
|
+
domContext: DOMContext;
|
|
152
154
|
constructor(opts: TimeFieldInputStateProps, root: TimeFieldRootState);
|
|
153
155
|
props: {
|
|
154
156
|
readonly id: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CalendarDateTime, Time, ZonedDateTime } from "@internationalized/date";
|
|
2
|
-
import { onDestroyEffect, attachRef, box } from "svelte-toolbelt";
|
|
2
|
+
import { onDestroyEffect, attachRef, box, DOMContext } from "svelte-toolbelt";
|
|
3
3
|
import { onMount, untrack } from "svelte";
|
|
4
4
|
import { Context, watch } from "runed";
|
|
5
5
|
import { getAriaDisabled, getAriaHidden, getAriaInvalid, getAriaReadonly, getDataDisabled, getDataInvalid, getDataReadonly, } from "../../internal/attrs.js";
|
|
@@ -96,6 +96,7 @@ export class TimeFieldRootState {
|
|
|
96
96
|
return getDefaultHourCycle(this.locale.current);
|
|
97
97
|
});
|
|
98
98
|
rangeRoot = undefined;
|
|
99
|
+
domContext = new DOMContext(() => null);
|
|
99
100
|
constructor(props, rangeRoot) {
|
|
100
101
|
this.rangeRoot = rangeRoot;
|
|
101
102
|
/**
|
|
@@ -124,7 +125,7 @@ export class TimeFieldRootState {
|
|
|
124
125
|
this.formatter = createTimeFormatter(this.locale.current);
|
|
125
126
|
this.initialSegments = this.#initializeTimeSegmentValues();
|
|
126
127
|
this.segmentValues = this.initialSegments;
|
|
127
|
-
this.announcer = getAnnouncer();
|
|
128
|
+
this.announcer = getAnnouncer(null);
|
|
128
129
|
this.getFieldNode = this.getFieldNode.bind(this);
|
|
129
130
|
this.updateSegment = this.updateSegment.bind(this);
|
|
130
131
|
this.handleSegmentClick = this.handleSegmentClick.bind(this);
|
|
@@ -135,10 +136,10 @@ export class TimeFieldRootState {
|
|
|
135
136
|
});
|
|
136
137
|
});
|
|
137
138
|
onMount(() => {
|
|
138
|
-
this.announcer = getAnnouncer();
|
|
139
|
+
this.announcer = getAnnouncer(this.domContext.getDocument());
|
|
139
140
|
});
|
|
140
141
|
onDestroyEffect(() => {
|
|
141
|
-
removeTimeDescriptionElement(this.descriptionId);
|
|
142
|
+
removeTimeDescriptionElement(this.descriptionId, this.domContext.getDocument());
|
|
142
143
|
});
|
|
143
144
|
$effect(() => {
|
|
144
145
|
if (this.formatter.getLocale() === this.locale.current)
|
|
@@ -148,7 +149,12 @@ export class TimeFieldRootState {
|
|
|
148
149
|
$effect(() => {
|
|
149
150
|
if (this.value.current) {
|
|
150
151
|
const descriptionId = untrack(() => this.descriptionId);
|
|
151
|
-
setTimeDescription(
|
|
152
|
+
setTimeDescription({
|
|
153
|
+
id: descriptionId,
|
|
154
|
+
formatter: this.formatter,
|
|
155
|
+
value: this.#toDateValue(this.value.current),
|
|
156
|
+
doc: this.domContext.getDocument(),
|
|
157
|
+
});
|
|
152
158
|
}
|
|
153
159
|
const placeholder = untrack(() => this.placeholder.current);
|
|
154
160
|
if (this.value.current && placeholder !== this.value.current) {
|
|
@@ -446,9 +452,12 @@ export class TimeFieldRootState {
|
|
|
446
452
|
export class TimeFieldInputState {
|
|
447
453
|
opts;
|
|
448
454
|
root;
|
|
455
|
+
domContext;
|
|
449
456
|
constructor(opts, root) {
|
|
450
457
|
this.opts = opts;
|
|
451
458
|
this.root = root;
|
|
459
|
+
this.domContext = new DOMContext(opts.ref);
|
|
460
|
+
this.root.setName(this.opts.name.current);
|
|
452
461
|
$effect(() => {
|
|
453
462
|
this.root.setName(this.opts.name.current);
|
|
454
463
|
});
|
|
@@ -456,7 +465,7 @@ export class TimeFieldInputState {
|
|
|
456
465
|
#ariaDescribedBy = $derived.by(() => {
|
|
457
466
|
if (!isBrowser)
|
|
458
467
|
return undefined;
|
|
459
|
-
const doesDescriptionExist =
|
|
468
|
+
const doesDescriptionExist = this.domContext.getElementById(this.root.descriptionId);
|
|
460
469
|
if (!doesDescriptionExist)
|
|
461
470
|
return undefined;
|
|
462
471
|
return this.root.descriptionId;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Time } from "@internationalized/date";
|
|
2
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
2
3
|
import { Context } from "runed";
|
|
3
4
|
import type { TimeFieldRootState } from "../time-field/time-field.svelte.js";
|
|
4
5
|
import { TimeFieldInputState } from "../time-field/time-field.svelte.js";
|
|
@@ -45,6 +46,7 @@ export declare class TimeRangeFieldRootState<T extends TimeValue = Time> {
|
|
|
45
46
|
endValueTime: Time | undefined;
|
|
46
47
|
minValueTime: Time | undefined;
|
|
47
48
|
maxValueTime: Time | undefined;
|
|
49
|
+
domContext: DOMContext;
|
|
48
50
|
constructor(opts: TimeRangeFieldRootStateProps<T>);
|
|
49
51
|
validationStatus: false | {
|
|
50
52
|
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 { TimeFieldInputState, useTimeFieldRoot } from "../time-field/time-field.svelte.js";
|
|
4
4
|
import { useId } from "../../internal/use-id.js";
|
|
@@ -41,11 +41,13 @@ export class TimeRangeFieldRootState {
|
|
|
41
41
|
return undefined;
|
|
42
42
|
return convertTimeValueToTime(this.opts.maxValue.current);
|
|
43
43
|
});
|
|
44
|
+
domContext;
|
|
44
45
|
constructor(opts) {
|
|
45
46
|
this.opts = opts;
|
|
46
47
|
this.formatter = createTimeFormatter(this.opts.locale.current);
|
|
48
|
+
this.domContext = new DOMContext(this.opts.ref);
|
|
47
49
|
onDestroyEffect(() => {
|
|
48
|
-
removeDescriptionElement(this.descriptionId);
|
|
50
|
+
removeDescriptionElement(this.descriptionId, this.domContext.getDocument());
|
|
49
51
|
});
|
|
50
52
|
$effect(() => {
|
|
51
53
|
if (this.formatter.getLocale() === this.opts.locale.current)
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
preventScroll={false}
|
|
47
47
|
forceMount={true}
|
|
48
48
|
ref={contentState.opts.ref}
|
|
49
|
+
tooltip={true}
|
|
49
50
|
>
|
|
50
51
|
{#snippet popper({ props })}
|
|
51
52
|
{@const mergedProps = mergeProps(props, {
|
|
@@ -64,6 +65,7 @@
|
|
|
64
65
|
<PopperLayer
|
|
65
66
|
{...mergedProps}
|
|
66
67
|
{...contentState.popperProps}
|
|
68
|
+
tooltip={true}
|
|
67
69
|
isStatic
|
|
68
70
|
present={contentState.root.opts.open.current}
|
|
69
71
|
{id}
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
preventScroll={false}
|
|
65
65
|
forceMount={true}
|
|
66
66
|
ref={contentState.opts.ref}
|
|
67
|
+
tooltip={true}
|
|
67
68
|
>
|
|
68
69
|
{#snippet popper({ props, wrapperProps })}
|
|
69
70
|
{@const mergedProps = mergeProps(props, {
|
|
@@ -91,6 +92,7 @@
|
|
|
91
92
|
preventScroll={false}
|
|
92
93
|
forceMount={false}
|
|
93
94
|
ref={contentState.opts.ref}
|
|
95
|
+
tooltip={true}
|
|
94
96
|
>
|
|
95
97
|
{#snippet popper({ props, wrapperProps })}
|
|
96
98
|
{@const mergedProps = mergeProps(props, {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
const mergedProps = $derived(mergeProps(restProps, triggerState.props, { type }));
|
|
30
30
|
</script>
|
|
31
31
|
|
|
32
|
-
<FloatingLayerAnchor {id} ref={triggerState.opts.ref}>
|
|
32
|
+
<FloatingLayerAnchor {id} ref={triggerState.opts.ref} tooltip={true}>
|
|
33
33
|
{#if child}
|
|
34
34
|
{@render child({ props: mergedProps })}
|
|
35
35
|
{:else}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
1
2
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
2
3
|
import type { WithRefProps } from "../../internal/types.js";
|
|
3
|
-
import type { PointerEventHandler } from "svelte/elements";
|
|
4
|
+
import type { FocusEventHandler, MouseEventHandler, PointerEventHandler } from "svelte/elements";
|
|
4
5
|
type TooltipProviderStateProps = ReadableBoxedValues<{
|
|
5
6
|
delayDuration: number;
|
|
6
7
|
disableHoverableContent: boolean;
|
|
@@ -53,26 +54,25 @@ declare class TooltipTriggerState {
|
|
|
53
54
|
#private;
|
|
54
55
|
readonly opts: TooltipTriggerStateProps;
|
|
55
56
|
readonly root: TooltipRootState;
|
|
57
|
+
domContext: DOMContext;
|
|
56
58
|
constructor(opts: TooltipTriggerStateProps, root: TooltipRootState);
|
|
57
59
|
handlePointerUp: () => void;
|
|
58
60
|
props: {
|
|
59
|
-
id: string;
|
|
60
|
-
"aria-describedby": string | undefined;
|
|
61
|
-
"data-state": string;
|
|
62
|
-
"data-disabled": "" | undefined;
|
|
63
|
-
"data-delay-duration":
|
|
64
|
-
"data-tooltip-trigger":
|
|
65
|
-
tabindex:
|
|
66
|
-
disabled: boolean;
|
|
67
|
-
onpointerup:
|
|
68
|
-
onpointerdown:
|
|
69
|
-
onpointermove: PointerEventHandler<HTMLElement>;
|
|
70
|
-
onpointerleave:
|
|
71
|
-
onfocus:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
onblur: () => void;
|
|
75
|
-
onclick: () => void;
|
|
61
|
+
readonly id: string;
|
|
62
|
+
readonly "aria-describedby": string | undefined;
|
|
63
|
+
readonly "data-state": string;
|
|
64
|
+
readonly "data-disabled": "" | undefined;
|
|
65
|
+
readonly "data-delay-duration": `${number}`;
|
|
66
|
+
readonly "data-tooltip-trigger": "";
|
|
67
|
+
readonly tabindex: 0 | undefined;
|
|
68
|
+
readonly disabled: boolean;
|
|
69
|
+
readonly onpointerup: PointerEventHandler<HTMLElement>;
|
|
70
|
+
readonly onpointerdown: PointerEventHandler<HTMLElement>;
|
|
71
|
+
readonly onpointermove: PointerEventHandler<HTMLElement>;
|
|
72
|
+
readonly onpointerleave: PointerEventHandler<HTMLElement>;
|
|
73
|
+
readonly onfocus: FocusEventHandler<HTMLElement>;
|
|
74
|
+
readonly onblur: FocusEventHandler<HTMLElement>;
|
|
75
|
+
readonly onclick: MouseEventHandler<HTMLElement>;
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
type TooltipContentStateProps = WithRefProps & ReadableBoxedValues<{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { box, onMountEffect, attachRef } from "svelte-toolbelt";
|
|
1
|
+
import { box, onMountEffect, attachRef, DOMContext } from "svelte-toolbelt";
|
|
2
2
|
import { on } from "svelte/events";
|
|
3
3
|
import { Context, watch } from "runed";
|
|
4
4
|
import { useTimeoutFn } from "../../internal/use-timeout-fn.svelte.js";
|
|
@@ -135,9 +135,11 @@ class TooltipTriggerState {
|
|
|
135
135
|
#isPointerDown = box(false);
|
|
136
136
|
#hasPointerMoveOpened = $state(false);
|
|
137
137
|
#isDisabled = $derived.by(() => this.opts.disabled.current || this.root.disabled);
|
|
138
|
+
domContext;
|
|
138
139
|
constructor(opts, root) {
|
|
139
140
|
this.opts = opts;
|
|
140
141
|
this.root = root;
|
|
142
|
+
this.domContext = new DOMContext(opts.ref);
|
|
141
143
|
}
|
|
142
144
|
handlePointerUp = () => {
|
|
143
145
|
this.#isPointerDown.current = false;
|
|
@@ -151,7 +153,7 @@ class TooltipTriggerState {
|
|
|
151
153
|
if (this.#isDisabled)
|
|
152
154
|
return;
|
|
153
155
|
this.#isPointerDown.current = true;
|
|
154
|
-
|
|
156
|
+
this.domContext.getDocument().addEventListener("pointerup", () => {
|
|
155
157
|
this.handlePointerUp();
|
|
156
158
|
}, { once: true });
|
|
157
159
|
};
|
|
@@ -192,7 +194,9 @@ class TooltipTriggerState {
|
|
|
192
194
|
};
|
|
193
195
|
props = $derived.by(() => ({
|
|
194
196
|
id: this.opts.id.current,
|
|
195
|
-
"aria-describedby": this.root.opts.open.current
|
|
197
|
+
"aria-describedby": this.root.opts.open.current
|
|
198
|
+
? this.root.contentNode?.id
|
|
199
|
+
: undefined,
|
|
196
200
|
"data-state": this.root.stateAttr,
|
|
197
201
|
"data-disabled": getDataDisabled(this.#isDisabled),
|
|
198
202
|
"data-delay-duration": `${this.root.delayDuration}`,
|
|
@@ -4,13 +4,16 @@
|
|
|
4
4
|
import type { AnchorProps } from "./index.js";
|
|
5
5
|
import type { Measurable } from "../../../../internal/floating-svelte/types.js";
|
|
6
6
|
|
|
7
|
-
let { id, children, virtualEl, ref }: AnchorProps = $props();
|
|
7
|
+
let { id, children, virtualEl, ref, tooltip = false }: AnchorProps = $props();
|
|
8
8
|
|
|
9
|
-
useFloatingAnchorState(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
useFloatingAnchorState(
|
|
10
|
+
{
|
|
11
|
+
id: box.with(() => id),
|
|
12
|
+
virtualEl: box.with(() => virtualEl as unknown as Measurable | null),
|
|
13
|
+
ref,
|
|
14
|
+
},
|
|
15
|
+
tooltip
|
|
16
|
+
);
|
|
14
17
|
</script>
|
|
15
18
|
|
|
16
19
|
{@render children?.()}
|
|
@@ -25,29 +25,33 @@
|
|
|
25
25
|
wrapperId = useId(),
|
|
26
26
|
customAnchor = null,
|
|
27
27
|
enabled,
|
|
28
|
+
tooltip = false,
|
|
28
29
|
}: ContentImplProps = $props();
|
|
29
30
|
|
|
30
|
-
const contentState = useFloatingContentState(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
const contentState = useFloatingContentState(
|
|
32
|
+
{
|
|
33
|
+
side: box.with(() => side),
|
|
34
|
+
sideOffset: box.with(() => sideOffset),
|
|
35
|
+
align: box.with(() => align),
|
|
36
|
+
alignOffset: box.with(() => alignOffset),
|
|
37
|
+
id: box.with(() => id),
|
|
38
|
+
arrowPadding: box.with(() => arrowPadding),
|
|
39
|
+
avoidCollisions: box.with(() => avoidCollisions),
|
|
40
|
+
collisionBoundary: box.with(() => collisionBoundary),
|
|
41
|
+
collisionPadding: box.with(() => collisionPadding),
|
|
42
|
+
hideWhenDetached: box.with(() => hideWhenDetached),
|
|
43
|
+
onPlaced: box.with(() => onPlaced),
|
|
44
|
+
sticky: box.with(() => sticky),
|
|
45
|
+
updatePositionStrategy: box.with(() => updatePositionStrategy),
|
|
46
|
+
strategy: box.with(() => strategy),
|
|
47
|
+
dir: box.with(() => dir),
|
|
48
|
+
style: box.with(() => style),
|
|
49
|
+
enabled: box.with(() => enabled),
|
|
50
|
+
wrapperId: box.with(() => wrapperId),
|
|
51
|
+
customAnchor: box.with(() => customAnchor),
|
|
52
|
+
},
|
|
53
|
+
tooltip
|
|
54
|
+
);
|
|
51
55
|
|
|
52
56
|
const mergedProps = $derived(
|
|
53
57
|
mergeProps(contentState.wrapperProps, {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
3
|
import { useFloatingRootState } from "../use-floating-layer.svelte.js";
|
|
4
4
|
|
|
5
|
-
let { children }: { children?: Snippet } = $props();
|
|
5
|
+
let { children, tooltip = false }: { children?: Snippet; tooltip?: boolean } = $props();
|
|
6
6
|
|
|
7
|
-
useFloatingRootState();
|
|
7
|
+
useFloatingRootState(tooltip);
|
|
8
8
|
</script>
|
|
9
9
|
|
|
10
10
|
{@render children?.()}
|
|
@@ -107,10 +107,28 @@ export type FloatingLayerContentImplProps = {
|
|
|
107
107
|
*/
|
|
108
108
|
onPlaced?: () => void;
|
|
109
109
|
enabled: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Tooltips are special in that they are commonly composed
|
|
112
|
+
* with other floating components, where the same trigger is
|
|
113
|
+
* used for both the tooltip and the popover.
|
|
114
|
+
*
|
|
115
|
+
* For situations like this, we need to use a different context
|
|
116
|
+
* symbol so that conflicts don't occur.
|
|
117
|
+
*/
|
|
118
|
+
tooltip?: boolean;
|
|
110
119
|
} & FloatingLayerContentProps;
|
|
111
120
|
export type FloatingLayerAnchorProps = {
|
|
112
121
|
id: string;
|
|
113
122
|
children?: Snippet;
|
|
114
123
|
virtualEl?: ReadableBox<Measurable | null>;
|
|
115
124
|
ref: ReadableBox<HTMLElement | null>;
|
|
125
|
+
/**
|
|
126
|
+
* Tooltips are special in that they are commonly composed
|
|
127
|
+
* with other floating components, where the same trigger is
|
|
128
|
+
* used for both the tooltip and the popover.
|
|
129
|
+
*
|
|
130
|
+
* For situations like this, we need to use a different context
|
|
131
|
+
* symbol so that conflicts don't occur.
|
|
132
|
+
*/
|
|
133
|
+
tooltip?: boolean;
|
|
116
134
|
};
|
|
@@ -942,10 +942,10 @@ declare class FloatingAnchorState {
|
|
|
942
942
|
readonly root: FloatingRootState;
|
|
943
943
|
constructor(opts: FloatingAnchorStateProps, root: FloatingRootState);
|
|
944
944
|
}
|
|
945
|
-
export declare function useFloatingRootState(): FloatingRootState;
|
|
946
|
-
export declare function useFloatingContentState(props: FloatingContentStateProps): FloatingContentState;
|
|
945
|
+
export declare function useFloatingRootState(tooltip?: boolean): FloatingRootState;
|
|
946
|
+
export declare function useFloatingContentState(props: FloatingContentStateProps, tooltip?: boolean): FloatingContentState;
|
|
947
947
|
export declare function useFloatingArrowState(props: FloatingArrowStateProps): FloatingArrowState;
|
|
948
|
-
export declare function useFloatingAnchorState(props: FloatingAnchorStateProps): FloatingAnchorState;
|
|
948
|
+
export declare function useFloatingAnchorState(props: FloatingAnchorStateProps, tooltip?: boolean): FloatingAnchorState;
|
|
949
949
|
export declare function getSideFromPlacement(placement: Placement): "left" | "right" | "top" | "bottom";
|
|
950
950
|
export declare function getAlignFromPlacement(placement: Placement): "end" | "center" | "start";
|
|
951
951
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { arrow, autoUpdate, flip, hide, limitShift, offset, shift, size, } from "@floating-ui/dom";
|
|
2
|
-
import { attachRef, box, cssToStyleObj, styleToString } from "svelte-toolbelt";
|
|
2
|
+
import { attachRef, box, cssToStyleObj, getWindow, styleToString, } from "svelte-toolbelt";
|
|
3
3
|
import { Context, ElementSize, watch } from "runed";
|
|
4
4
|
import { isNotNull } from "../../../internal/is.js";
|
|
5
5
|
import { useId } from "../../../internal/use-id.js";
|
|
@@ -140,9 +140,6 @@ class FloatingContentState {
|
|
|
140
140
|
"data-align": this.placedAlign,
|
|
141
141
|
style: styleToString({
|
|
142
142
|
...this.#transformedStyle,
|
|
143
|
-
// if the FloatingContent hasn't been placed yet (not all measurements done)
|
|
144
|
-
// we prevent animations so that users's animation don't kick in too early referring wrong sides
|
|
145
|
-
// animation: !this.floating.isPositioned ? "none" : undefined,
|
|
146
143
|
}),
|
|
147
144
|
...attachRef(this.contentRef),
|
|
148
145
|
}));
|
|
@@ -195,7 +192,8 @@ class FloatingContentState {
|
|
|
195
192
|
watch(() => this.contentRef.current, (contentNode) => {
|
|
196
193
|
if (!contentNode)
|
|
197
194
|
return;
|
|
198
|
-
|
|
195
|
+
const win = getWindow(contentNode);
|
|
196
|
+
this.contentZIndex = win.getComputedStyle(contentNode).zIndex;
|
|
199
197
|
});
|
|
200
198
|
$effect(() => {
|
|
201
199
|
this.floating.floating.current = this.wrapperRef.current;
|
|
@@ -232,17 +230,24 @@ class FloatingAnchorState {
|
|
|
232
230
|
}
|
|
233
231
|
const FloatingRootContext = new Context("Floating.Root");
|
|
234
232
|
const FloatingContentContext = new Context("Floating.Content");
|
|
235
|
-
|
|
236
|
-
|
|
233
|
+
const FloatingTooltipRootContext = new Context("Floating.Root");
|
|
234
|
+
export function useFloatingRootState(tooltip = false) {
|
|
235
|
+
return tooltip
|
|
236
|
+
? FloatingTooltipRootContext.set(new FloatingRootState())
|
|
237
|
+
: FloatingRootContext.set(new FloatingRootState());
|
|
237
238
|
}
|
|
238
|
-
export function useFloatingContentState(props) {
|
|
239
|
-
return
|
|
239
|
+
export function useFloatingContentState(props, tooltip = false) {
|
|
240
|
+
return tooltip
|
|
241
|
+
? FloatingContentContext.set(new FloatingContentState(props, FloatingTooltipRootContext.get()))
|
|
242
|
+
: FloatingContentContext.set(new FloatingContentState(props, FloatingRootContext.get()));
|
|
240
243
|
}
|
|
241
244
|
export function useFloatingArrowState(props) {
|
|
242
245
|
return new FloatingArrowState(props, FloatingContentContext.get());
|
|
243
246
|
}
|
|
244
|
-
export function useFloatingAnchorState(props) {
|
|
245
|
-
return
|
|
247
|
+
export function useFloatingAnchorState(props, tooltip = false) {
|
|
248
|
+
return tooltip
|
|
249
|
+
? new FloatingAnchorState(props, FloatingTooltipRootContext.get())
|
|
250
|
+
: new FloatingAnchorState(props, FloatingRootContext.get());
|
|
246
251
|
}
|
|
247
252
|
//
|
|
248
253
|
// HELPERS
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { afterSleep, afterTick, executeCallbacks } from "svelte-toolbelt";
|
|
1
|
+
import { afterSleep, afterTick, DOMContext, executeCallbacks } from "svelte-toolbelt";
|
|
2
2
|
import { Context, watch } from "runed";
|
|
3
3
|
import { on } from "svelte/events";
|
|
4
4
|
import { createFocusScopeAPI, createFocusScopeStack, removeLinks, } from "./focus-scope-stack.svelte.js";
|
|
@@ -21,6 +21,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
21
21
|
const focusScope = createFocusScopeAPI();
|
|
22
22
|
const ctx = FocusScopeContext.getOr({ ignoreCloseAutoFocus: false });
|
|
23
23
|
let lastFocusedElement = null;
|
|
24
|
+
const domContext = new DOMContext(ref);
|
|
24
25
|
function manageFocus(event) {
|
|
25
26
|
if (focusScope.paused || !ref.current || focusScope.isHandlingFocus)
|
|
26
27
|
return;
|
|
@@ -89,14 +90,16 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
89
90
|
* If the element was removed and focus is now outside the container,
|
|
90
91
|
* (e.g., browser moved it to body), refocus the container.
|
|
91
92
|
*/
|
|
92
|
-
if (elementWasRemoved &&
|
|
93
|
+
if (elementWasRemoved &&
|
|
94
|
+
ref.current &&
|
|
95
|
+
!ref.current.contains(domContext.getActiveElement())) {
|
|
93
96
|
focus(ref.current);
|
|
94
97
|
}
|
|
95
98
|
}
|
|
96
99
|
watch([() => ref.current, () => enabled.current], ([container, enabled]) => {
|
|
97
100
|
if (!container || !enabled)
|
|
98
101
|
return;
|
|
99
|
-
const removeEvents = executeCallbacks(on(
|
|
102
|
+
const removeEvents = executeCallbacks(on(domContext.getDocument(), "focusin", manageFocus), on(domContext.getDocument(), "focusout", manageFocus));
|
|
100
103
|
const mutationObserver = new MutationObserver(handleMutations);
|
|
101
104
|
mutationObserver.observe(container, {
|
|
102
105
|
childList: true,
|
|
@@ -111,7 +114,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
111
114
|
watch([() => forceMount.current, () => ref.current], ([forceMount, container]) => {
|
|
112
115
|
if (forceMount)
|
|
113
116
|
return;
|
|
114
|
-
const prevFocusedElement =
|
|
117
|
+
const prevFocusedElement = domContext.getActiveElement();
|
|
115
118
|
handleOpen(container, prevFocusedElement);
|
|
116
119
|
return () => {
|
|
117
120
|
if (!container)
|
|
@@ -122,7 +125,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
122
125
|
watch([() => forceMount.current, () => ref.current, () => enabled.current], ([forceMount, container]) => {
|
|
123
126
|
if (!forceMount)
|
|
124
127
|
return;
|
|
125
|
-
const prevFocusedElement =
|
|
128
|
+
const prevFocusedElement = domContext.getActiveElement();
|
|
126
129
|
handleOpen(container, prevFocusedElement);
|
|
127
130
|
return () => {
|
|
128
131
|
if (!container)
|
|
@@ -132,7 +135,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
132
135
|
});
|
|
133
136
|
function handleOpen(container, prevFocusedElement) {
|
|
134
137
|
if (!container)
|
|
135
|
-
container =
|
|
138
|
+
container = domContext.getElementById(id.current);
|
|
136
139
|
if (!container || !enabled.current)
|
|
137
140
|
return;
|
|
138
141
|
focusScopeStack.add(focusScope);
|
|
@@ -146,7 +149,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
146
149
|
return;
|
|
147
150
|
const result = focusFirst(removeLinks(getTabbableCandidates(container)), {
|
|
148
151
|
select: true,
|
|
149
|
-
});
|
|
152
|
+
}, () => domContext.getActiveElement());
|
|
150
153
|
if (!result)
|
|
151
154
|
focus(container);
|
|
152
155
|
});
|
|
@@ -159,7 +162,9 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
159
162
|
const shouldIgnore = ctx.ignoreCloseAutoFocus;
|
|
160
163
|
afterSleep(0, () => {
|
|
161
164
|
if (!destroyEvent.defaultPrevented && prevFocusedElement && !shouldIgnore) {
|
|
162
|
-
focus(isTabbable(prevFocusedElement)
|
|
165
|
+
focus(isTabbable(prevFocusedElement)
|
|
166
|
+
? prevFocusedElement
|
|
167
|
+
: domContext.getDocument().body, {
|
|
163
168
|
select: true,
|
|
164
169
|
});
|
|
165
170
|
}
|
|
@@ -174,7 +179,7 @@ export function useFocusScope({ id, loop, enabled, onOpenAutoFocus, onCloseAutoF
|
|
|
174
179
|
if (focusScope.paused)
|
|
175
180
|
return;
|
|
176
181
|
const isTabKey = e.key === kbd.TAB && !e.ctrlKey && !e.altKey && !e.metaKey;
|
|
177
|
-
const focusedElement =
|
|
182
|
+
const focusedElement = domContext.getActiveElement();
|
|
178
183
|
if (!(isTabKey && focusedElement))
|
|
179
184
|
return;
|
|
180
185
|
const container = ref.current;
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
isStatic = false,
|
|
46
46
|
enabled,
|
|
47
47
|
ref,
|
|
48
|
+
tooltip = false,
|
|
48
49
|
...restProps
|
|
49
50
|
}: Omit<PopperLayerImplProps, "present" | "children"> & {
|
|
50
51
|
enabled: boolean;
|
|
@@ -72,6 +73,7 @@
|
|
|
72
73
|
{onPlaced}
|
|
73
74
|
{customAnchor}
|
|
74
75
|
{enabled}
|
|
76
|
+
{tooltip}
|
|
75
77
|
>
|
|
76
78
|
{#snippet content({ props: floatingProps, wrapperProps })}
|
|
77
79
|
{#if restProps.forceMount && enabled}
|
|
@@ -22,4 +22,13 @@ export type PopperLayerImplProps = Omit<EscapeLayerImplProps & DismissibleLayerI
|
|
|
22
22
|
}
|
|
23
23
|
]>;
|
|
24
24
|
isStatic?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Tooltips are special in that they are commonly composed
|
|
27
|
+
* with other floating components, where the same trigger is
|
|
28
|
+
* used for both the tooltip and the popover.
|
|
29
|
+
*
|
|
30
|
+
* For situations like this, we need to use a different context
|
|
31
|
+
* symbol so that conflicts don't occur.
|
|
32
|
+
*/
|
|
33
|
+
tooltip?: boolean;
|
|
25
34
|
}, "enabled">;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DOMContext } from "svelte-toolbelt";
|
|
1
2
|
import type { TextSelectionLayerImplProps } from "./types.js";
|
|
2
3
|
import type { ReadableBoxedValues } from "../../../internal/box.svelte.js";
|
|
3
4
|
type TextSelectionLayerStateProps = ReadableBoxedValues<Required<Omit<TextSelectionLayerImplProps, "children" | "preventOverflowTextSelection" | "ref">> & {
|
|
@@ -6,6 +7,7 @@ type TextSelectionLayerStateProps = ReadableBoxedValues<Required<Omit<TextSelect
|
|
|
6
7
|
export declare class TextSelectionLayerState {
|
|
7
8
|
#private;
|
|
8
9
|
readonly opts: TextSelectionLayerStateProps;
|
|
10
|
+
readonly domContext: DOMContext;
|
|
9
11
|
constructor(opts: TextSelectionLayerStateProps);
|
|
10
12
|
}
|
|
11
13
|
export declare function useTextSelectionLayer(props: TextSelectionLayerStateProps): TextSelectionLayerState;
|