bits-ui 2.2.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/slider/helpers.js +33 -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 +16 -18
- package/dist/bits/tooltip/tooltip.svelte.js +3 -1
- 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 +13 -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/package.json +1 -1
|
@@ -132,6 +132,29 @@ export function getThumbLabelStyles(direction, thumbPosition, labelPosition = "t
|
|
|
132
132
|
}
|
|
133
133
|
return style;
|
|
134
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Gets the number of decimal places in a number
|
|
137
|
+
*/
|
|
138
|
+
function getDecimalPlaces(num) {
|
|
139
|
+
if (Math.floor(num) === num)
|
|
140
|
+
return 0;
|
|
141
|
+
const str = num.toString();
|
|
142
|
+
if (str.indexOf(".") !== -1 && str.indexOf("e-") === -1) {
|
|
143
|
+
return str.split(".")[1].length;
|
|
144
|
+
}
|
|
145
|
+
else if (str.indexOf("e-") !== -1) {
|
|
146
|
+
const parts = str.split("e-");
|
|
147
|
+
return parseInt(parts[1], 10);
|
|
148
|
+
}
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Rounds a number to the specified number of decimal places
|
|
153
|
+
*/
|
|
154
|
+
function roundToPrecision(num, precision) {
|
|
155
|
+
const factor = Math.pow(10, precision);
|
|
156
|
+
return Math.round(num * factor) / factor;
|
|
157
|
+
}
|
|
135
158
|
/**
|
|
136
159
|
* Normalizes step to always be a sorted array of valid values within min/max range
|
|
137
160
|
*/
|
|
@@ -140,13 +163,21 @@ export function normalizeSteps(step, min, max) {
|
|
|
140
163
|
// generate regular steps - match original behavior exactly
|
|
141
164
|
const difference = max - min;
|
|
142
165
|
let count = Math.ceil(difference / step);
|
|
143
|
-
|
|
166
|
+
// Get precision from step to avoid floating point errors
|
|
167
|
+
const precision = getDecimalPlaces(step);
|
|
168
|
+
// Check if difference is divisible by step using integer arithmetic to avoid floating point errors
|
|
169
|
+
const factor = Math.pow(10, precision);
|
|
170
|
+
const intDifference = Math.round(difference * factor);
|
|
171
|
+
const intStep = Math.round(step * factor);
|
|
172
|
+
if (intDifference % intStep === 0) {
|
|
144
173
|
count++;
|
|
145
174
|
}
|
|
146
175
|
const steps = [];
|
|
147
176
|
for (let i = 0; i < count; i++) {
|
|
148
177
|
const value = min + i * step;
|
|
149
|
-
|
|
178
|
+
// Round to the precision of the step to avoid floating point errors
|
|
179
|
+
const roundedValue = roundToPrecision(value, precision);
|
|
180
|
+
steps.push(roundedValue);
|
|
150
181
|
}
|
|
151
182
|
return steps;
|
|
152
183
|
}
|
|
@@ -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,7 +1,7 @@
|
|
|
1
1
|
import { DOMContext } from "svelte-toolbelt";
|
|
2
2
|
import type { ReadableBoxedValues, WritableBoxedValues } from "../../internal/box.svelte.js";
|
|
3
3
|
import type { WithRefProps } from "../../internal/types.js";
|
|
4
|
-
import type { PointerEventHandler } from "svelte/elements";
|
|
4
|
+
import type { FocusEventHandler, MouseEventHandler, PointerEventHandler } from "svelte/elements";
|
|
5
5
|
type TooltipProviderStateProps = ReadableBoxedValues<{
|
|
6
6
|
delayDuration: number;
|
|
7
7
|
disableHoverableContent: boolean;
|
|
@@ -58,23 +58,21 @@ declare class TooltipTriggerState {
|
|
|
58
58
|
constructor(opts: TooltipTriggerStateProps, root: TooltipRootState);
|
|
59
59
|
handlePointerUp: () => void;
|
|
60
60
|
props: {
|
|
61
|
-
id: string;
|
|
62
|
-
"aria-describedby": string | undefined;
|
|
63
|
-
"data-state": string;
|
|
64
|
-
"data-disabled": "" | undefined;
|
|
65
|
-
"data-delay-duration":
|
|
66
|
-
"data-tooltip-trigger":
|
|
67
|
-
tabindex:
|
|
68
|
-
disabled: boolean;
|
|
69
|
-
onpointerup:
|
|
70
|
-
onpointerdown:
|
|
71
|
-
onpointermove: PointerEventHandler<HTMLElement>;
|
|
72
|
-
onpointerleave:
|
|
73
|
-
onfocus:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
onblur: () => void;
|
|
77
|
-
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>;
|
|
78
76
|
};
|
|
79
77
|
}
|
|
80
78
|
type TooltipContentStateProps = WithRefProps & ReadableBoxedValues<{
|
|
@@ -194,7 +194,9 @@ class TooltipTriggerState {
|
|
|
194
194
|
};
|
|
195
195
|
props = $derived.by(() => ({
|
|
196
196
|
id: this.opts.id.current,
|
|
197
|
-
"aria-describedby": this.root.opts.open.current
|
|
197
|
+
"aria-describedby": this.root.opts.open.current
|
|
198
|
+
? this.root.contentNode?.id
|
|
199
|
+
: undefined,
|
|
198
200
|
"data-state": this.root.stateAttr,
|
|
199
201
|
"data-disabled": getDataDisabled(this.#isDisabled),
|
|
200
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 {};
|
|
@@ -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
|
}));
|
|
@@ -233,17 +230,24 @@ class FloatingAnchorState {
|
|
|
233
230
|
}
|
|
234
231
|
const FloatingRootContext = new Context("Floating.Root");
|
|
235
232
|
const FloatingContentContext = new Context("Floating.Content");
|
|
236
|
-
|
|
237
|
-
|
|
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());
|
|
238
238
|
}
|
|
239
|
-
export function useFloatingContentState(props) {
|
|
240
|
-
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()));
|
|
241
243
|
}
|
|
242
244
|
export function useFloatingArrowState(props) {
|
|
243
245
|
return new FloatingArrowState(props, FloatingContentContext.get());
|
|
244
246
|
}
|
|
245
|
-
export function useFloatingAnchorState(props) {
|
|
246
|
-
return
|
|
247
|
+
export function useFloatingAnchorState(props, tooltip = false) {
|
|
248
|
+
return tooltip
|
|
249
|
+
? new FloatingAnchorState(props, FloatingTooltipRootContext.get())
|
|
250
|
+
: new FloatingAnchorState(props, FloatingRootContext.get());
|
|
247
251
|
}
|
|
248
252
|
//
|
|
249
253
|
// HELPERS
|
|
@@ -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">;
|