@choice-ui/react 1.9.4 → 1.9.7
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/components/command/dist/index.d.ts +3 -0
- package/dist/components/command/src/components/command-list.d.ts +3 -0
- package/dist/components/command/src/components/command-list.js +4 -1
- package/dist/components/numeric-input/dist/index.d.ts +2 -0
- package/dist/components/numeric-input/dist/index.js +40 -13
- package/dist/components/numeric-input/src/context/numeric-input-context.d.ts +1 -0
- package/dist/components/numeric-input/src/hooks/use-input-interactions.d.ts +3 -1
- package/dist/components/numeric-input/src/hooks/use-numeric-input.d.ts +1 -0
- package/dist/components/numeric-input/src/hooks/use-numeric-input.js +36 -13
- package/dist/components/numeric-input/src/numeric-input.d.ts +1 -0
- package/dist/components/numeric-input/src/numeric-input.js +4 -0
- package/dist/components/scroll-area/dist/index.d.ts +4 -27
- package/dist/components/scroll-area/dist/index.js +96 -123
- package/dist/components/scroll-area/src/components/scroll-area-content.js +2 -2
- package/dist/components/scroll-area/src/components/scroll-area-root.js +9 -12
- package/dist/components/scroll-area/src/components/scroll-area-scrollbar.js +14 -4
- package/dist/components/scroll-area/src/components/scroll-area-viewport.js +2 -2
- package/dist/components/scroll-area/src/context/scroll-area-context.d.ts +17 -2
- package/dist/components/scroll-area/src/context/scroll-area-context.js +23 -6
- package/dist/components/scroll-area/src/hooks/index.d.ts +0 -1
- package/dist/components/scroll-area/src/hooks/use-scroll-state-and-visibility.d.ts +2 -2
- package/dist/components/scroll-area/src/hooks/use-scroll-state-and-visibility.js +30 -75
- package/dist/components/scroll-area/src/hooks/use-thumb.d.ts +1 -1
- package/dist/components/scroll-area/src/hooks/use-thumb.js +25 -28
- package/dist/components/scroll-area/src/types.d.ts +16 -4
- package/dist/index.js +0 -2
- package/package.json +1 -1
- package/dist/components/scroll-area/src/hooks/use-scroll-performance-monitor.d.ts +0 -23
- package/dist/components/scroll-area/src/hooks/use-scroll-performance-monitor.js +0 -123
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import { forwardRef, useState, useId, useMemo, createContext, useCallback, useRef, useEffect, useContext } from "react";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { tcv, tcx } from "../../../shared/utils/tcx/tcx.js";
|
|
4
|
-
var
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
var ScrollAreaStateContext = createContext(null);
|
|
5
|
+
var ScrollAreaConfigContext = createContext(null);
|
|
6
|
+
var ERROR_MESSAGE = "ScrollArea compound components must be used within ScrollArea";
|
|
7
|
+
function useScrollAreaStateContext() {
|
|
8
|
+
const context = useContext(ScrollAreaStateContext);
|
|
9
|
+
if (!context) {
|
|
10
|
+
throw new Error(ERROR_MESSAGE);
|
|
11
|
+
}
|
|
12
|
+
return context;
|
|
13
|
+
}
|
|
14
|
+
function useScrollAreaConfigContext() {
|
|
15
|
+
const context = useContext(ScrollAreaConfigContext);
|
|
7
16
|
if (!context) {
|
|
8
|
-
throw new Error(
|
|
17
|
+
throw new Error(ERROR_MESSAGE);
|
|
9
18
|
}
|
|
10
19
|
return context;
|
|
11
20
|
}
|
|
12
|
-
function
|
|
21
|
+
function useScrollAreaContext() {
|
|
22
|
+
const state = useScrollAreaStateContext();
|
|
23
|
+
const config = useScrollAreaConfigContext();
|
|
24
|
+
return { ...state, ...config };
|
|
25
|
+
}
|
|
26
|
+
function useScrollStateAndVisibility(viewport, content) {
|
|
13
27
|
const [scrollState, setScrollState] = useState({
|
|
14
28
|
scrollLeft: 0,
|
|
15
29
|
scrollTop: 0,
|
|
@@ -23,8 +37,6 @@ function useScrollStateAndVisibility(viewport) {
|
|
|
23
37
|
const scrollTimeoutRef = useRef();
|
|
24
38
|
const rafRef = useRef();
|
|
25
39
|
const resizeObserverRef = useRef();
|
|
26
|
-
const mutationObserverRef = useRef();
|
|
27
|
-
const mutationTimeoutRef = useRef();
|
|
28
40
|
const lastUpdateTimeRef = useRef(0);
|
|
29
41
|
const minUpdateIntervalRef = useRef(16);
|
|
30
42
|
const updateScrollState = useCallback(() => {
|
|
@@ -36,36 +48,36 @@ function useScrollStateAndVisibility(viewport) {
|
|
|
36
48
|
cancelAnimationFrame(rafRef.current);
|
|
37
49
|
}
|
|
38
50
|
rafRef.current = requestAnimationFrame(() => {
|
|
51
|
+
rafRef.current = void 0;
|
|
39
52
|
updateScrollState();
|
|
40
53
|
});
|
|
41
54
|
return;
|
|
42
55
|
}
|
|
43
56
|
if (rafRef.current) {
|
|
44
57
|
cancelAnimationFrame(rafRef.current);
|
|
58
|
+
rafRef.current = void 0;
|
|
45
59
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return prevState;
|
|
68
|
-
});
|
|
60
|
+
const newState = {
|
|
61
|
+
scrollLeft: viewport.scrollLeft,
|
|
62
|
+
scrollTop: viewport.scrollTop,
|
|
63
|
+
scrollWidth: viewport.scrollWidth,
|
|
64
|
+
scrollHeight: viewport.scrollHeight,
|
|
65
|
+
clientWidth: viewport.clientWidth,
|
|
66
|
+
clientHeight: viewport.clientHeight
|
|
67
|
+
};
|
|
68
|
+
setScrollState((prevState) => {
|
|
69
|
+
const scrollLeftChanged = Math.abs(prevState.scrollLeft - newState.scrollLeft) > 0.5;
|
|
70
|
+
const scrollTopChanged = Math.abs(prevState.scrollTop - newState.scrollTop) > 0.5;
|
|
71
|
+
const scrollWidthChanged = prevState.scrollWidth !== newState.scrollWidth;
|
|
72
|
+
const scrollHeightChanged = prevState.scrollHeight !== newState.scrollHeight;
|
|
73
|
+
const clientWidthChanged = prevState.clientWidth !== newState.clientWidth;
|
|
74
|
+
const clientHeightChanged = prevState.clientHeight !== newState.clientHeight;
|
|
75
|
+
const hasChanges = scrollLeftChanged || scrollTopChanged || scrollWidthChanged || scrollHeightChanged || clientWidthChanged || clientHeightChanged;
|
|
76
|
+
if (hasChanges) {
|
|
77
|
+
lastUpdateTimeRef.current = now;
|
|
78
|
+
return newState;
|
|
79
|
+
}
|
|
80
|
+
return prevState;
|
|
69
81
|
});
|
|
70
82
|
}, [viewport]);
|
|
71
83
|
const delayedUpdateScrollState = useCallback(() => {
|
|
@@ -102,54 +114,19 @@ function useScrollStateAndVisibility(viewport) {
|
|
|
102
114
|
passive: true,
|
|
103
115
|
signal,
|
|
104
116
|
capture: false
|
|
105
|
-
// Avoid unnecessary event capture
|
|
106
117
|
});
|
|
107
118
|
window.addEventListener("resize", handleResize, {
|
|
108
119
|
passive: true,
|
|
109
120
|
signal
|
|
110
121
|
});
|
|
111
122
|
if (window.ResizeObserver) {
|
|
112
|
-
resizeObserverRef.current = new ResizeObserver((
|
|
113
|
-
|
|
114
|
-
if (entry.target === viewport) {
|
|
115
|
-
updateScrollState();
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
123
|
+
resizeObserverRef.current = new ResizeObserver(() => {
|
|
124
|
+
updateScrollState();
|
|
119
125
|
});
|
|
120
126
|
resizeObserverRef.current.observe(viewport);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const hasLayoutChanges = mutations.some((mutation) => {
|
|
125
|
-
if (mutation.type === "childList") {
|
|
126
|
-
return mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0;
|
|
127
|
-
}
|
|
128
|
-
if (mutation.type === "attributes") {
|
|
129
|
-
const attr = mutation.attributeName;
|
|
130
|
-
return attr === "style" || attr === "class";
|
|
131
|
-
}
|
|
132
|
-
return mutation.type === "characterData";
|
|
133
|
-
});
|
|
134
|
-
if (!hasLayoutChanges) return;
|
|
135
|
-
if (mutationTimeoutRef.current) {
|
|
136
|
-
clearTimeout(mutationTimeoutRef.current);
|
|
137
|
-
}
|
|
138
|
-
mutationTimeoutRef.current = window.setTimeout(() => {
|
|
139
|
-
updateScrollState();
|
|
140
|
-
}, 16);
|
|
141
|
-
});
|
|
142
|
-
mutationObserverRef.current.observe(viewport, {
|
|
143
|
-
childList: true,
|
|
144
|
-
subtree: true,
|
|
145
|
-
attributes: true,
|
|
146
|
-
attributeFilter: ["style", "class"],
|
|
147
|
-
// Only listen to attributes that affect layout
|
|
148
|
-
characterData: true,
|
|
149
|
-
characterDataOldValue: false,
|
|
150
|
-
// No need for old value, improve performance
|
|
151
|
-
attributeOldValue: false
|
|
152
|
-
});
|
|
127
|
+
if (content) {
|
|
128
|
+
resizeObserverRef.current.observe(content);
|
|
129
|
+
}
|
|
153
130
|
}
|
|
154
131
|
delayedUpdateScrollState();
|
|
155
132
|
return () => {
|
|
@@ -158,10 +135,6 @@ function useScrollStateAndVisibility(viewport) {
|
|
|
158
135
|
clearTimeout(scrollTimeoutRef.current);
|
|
159
136
|
scrollTimeoutRef.current = void 0;
|
|
160
137
|
}
|
|
161
|
-
if (mutationTimeoutRef.current) {
|
|
162
|
-
clearTimeout(mutationTimeoutRef.current);
|
|
163
|
-
mutationTimeoutRef.current = void 0;
|
|
164
|
-
}
|
|
165
138
|
if (rafRef.current) {
|
|
166
139
|
cancelAnimationFrame(rafRef.current);
|
|
167
140
|
rafRef.current = void 0;
|
|
@@ -170,12 +143,8 @@ function useScrollStateAndVisibility(viewport) {
|
|
|
170
143
|
resizeObserverRef.current.disconnect();
|
|
171
144
|
resizeObserverRef.current = void 0;
|
|
172
145
|
}
|
|
173
|
-
if (mutationObserverRef.current) {
|
|
174
|
-
mutationObserverRef.current.disconnect();
|
|
175
|
-
mutationObserverRef.current = void 0;
|
|
176
|
-
}
|
|
177
146
|
};
|
|
178
|
-
}, [viewport, handleScroll, delayedUpdateScrollState]);
|
|
147
|
+
}, [viewport, content, handleScroll, delayedUpdateScrollState, updateScrollState]);
|
|
179
148
|
const handleMouseEnter = useCallback(() => setIsHovering(true), []);
|
|
180
149
|
const handleMouseLeave = useCallback(() => setIsHovering(false), []);
|
|
181
150
|
return {
|
|
@@ -229,16 +198,13 @@ function useThumbDrag(viewport, scrollState, orientation) {
|
|
|
229
198
|
const isDragging = useRef(false);
|
|
230
199
|
const startPos = useRef(0);
|
|
231
200
|
const startScroll = useRef(0);
|
|
232
|
-
const rafId = useRef();
|
|
233
201
|
const cleanupRef = useRef(null);
|
|
202
|
+
const scrollStateRef = useRef(scrollState);
|
|
203
|
+
scrollStateRef.current = scrollState;
|
|
234
204
|
const dragContextRef = useRef(null);
|
|
235
205
|
useEffect(() => {
|
|
236
206
|
return () => {
|
|
237
207
|
isDragging.current = false;
|
|
238
|
-
if (rafId.current) {
|
|
239
|
-
cancelAnimationFrame(rafId.current);
|
|
240
|
-
rafId.current = void 0;
|
|
241
|
-
}
|
|
242
208
|
if (cleanupRef.current) {
|
|
243
209
|
cleanupRef.current();
|
|
244
210
|
cleanupRef.current = null;
|
|
@@ -248,13 +214,21 @@ function useThumbDrag(viewport, scrollState, orientation) {
|
|
|
248
214
|
const handleMouseDown = useCallback(
|
|
249
215
|
(e) => {
|
|
250
216
|
if (!viewport) return;
|
|
217
|
+
const currentScrollState = scrollStateRef.current;
|
|
251
218
|
const target = e.currentTarget;
|
|
252
219
|
const scrollbar = target.closest('[role="scrollbar"]');
|
|
253
220
|
if (!scrollbar) return;
|
|
254
221
|
const scrollbarRect = scrollbar.getBoundingClientRect();
|
|
255
|
-
const scrollableRange = orientation === "vertical" ? Math.max(0,
|
|
222
|
+
const scrollableRange = orientation === "vertical" ? Math.max(0, currentScrollState.scrollHeight - currentScrollState.clientHeight) : Math.max(0, currentScrollState.scrollWidth - currentScrollState.clientWidth);
|
|
256
223
|
const scrollbarRange = orientation === "vertical" ? scrollbarRect.height : scrollbarRect.width;
|
|
257
224
|
if (scrollableRange <= 0 || scrollbarRange <= 0) return;
|
|
225
|
+
const thumbFraction = Math.max(
|
|
226
|
+
0.1,
|
|
227
|
+
orientation === "vertical" ? currentScrollState.clientHeight / currentScrollState.scrollHeight : currentScrollState.clientWidth / currentScrollState.scrollWidth
|
|
228
|
+
);
|
|
229
|
+
const thumbSizePixels = scrollbarRange * thumbFraction;
|
|
230
|
+
const effectiveTrackRange = scrollbarRange - thumbSizePixels;
|
|
231
|
+
if (effectiveTrackRange <= 0) return;
|
|
258
232
|
dragContextRef.current = {
|
|
259
233
|
scrollbarRect,
|
|
260
234
|
scrollableRange,
|
|
@@ -262,34 +236,26 @@ function useThumbDrag(viewport, scrollState, orientation) {
|
|
|
262
236
|
};
|
|
263
237
|
isDragging.current = true;
|
|
264
238
|
startPos.current = orientation === "vertical" ? e.clientY : e.clientX;
|
|
265
|
-
startScroll.current = orientation === "vertical" ?
|
|
266
|
-
const scrollRatio = scrollableRange /
|
|
239
|
+
startScroll.current = orientation === "vertical" ? currentScrollState.scrollTop : currentScrollState.scrollLeft;
|
|
240
|
+
const scrollRatio = scrollableRange / effectiveTrackRange;
|
|
267
241
|
const handleMouseMove = (e2) => {
|
|
268
242
|
if (!isDragging.current || !viewport || !dragContextRef.current) return;
|
|
269
|
-
|
|
270
|
-
|
|
243
|
+
const currentPos = orientation === "vertical" ? e2.clientY : e2.clientX;
|
|
244
|
+
const delta = currentPos - startPos.current;
|
|
245
|
+
const scrollDelta = delta * scrollRatio;
|
|
246
|
+
const newScrollValue = Math.max(
|
|
247
|
+
0,
|
|
248
|
+
Math.min(startScroll.current + scrollDelta, dragContextRef.current.scrollableRange)
|
|
249
|
+
);
|
|
250
|
+
if (orientation === "vertical") {
|
|
251
|
+
viewport.scrollTop = newScrollValue;
|
|
252
|
+
} else {
|
|
253
|
+
viewport.scrollLeft = newScrollValue;
|
|
271
254
|
}
|
|
272
|
-
rafId.current = requestAnimationFrame(() => {
|
|
273
|
-
const currentPos = orientation === "vertical" ? e2.clientY : e2.clientX;
|
|
274
|
-
const delta = currentPos - startPos.current;
|
|
275
|
-
const scrollDelta = delta * scrollRatio;
|
|
276
|
-
const newScrollValue = Math.max(
|
|
277
|
-
0,
|
|
278
|
-
Math.min(startScroll.current + scrollDelta, dragContextRef.current.scrollableRange)
|
|
279
|
-
);
|
|
280
|
-
if (orientation === "vertical") {
|
|
281
|
-
viewport.scrollTop = newScrollValue;
|
|
282
|
-
} else {
|
|
283
|
-
viewport.scrollLeft = newScrollValue;
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
255
|
};
|
|
287
256
|
const handleMouseUp = () => {
|
|
288
257
|
isDragging.current = false;
|
|
289
258
|
dragContextRef.current = null;
|
|
290
|
-
if (rafId.current) {
|
|
291
|
-
cancelAnimationFrame(rafId.current);
|
|
292
|
-
}
|
|
293
259
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
294
260
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
295
261
|
cleanupRef.current = null;
|
|
@@ -303,7 +269,7 @@ function useThumbDrag(viewport, scrollState, orientation) {
|
|
|
303
269
|
document.addEventListener("mouseup", handleMouseUp, { passive: true });
|
|
304
270
|
e.preventDefault();
|
|
305
271
|
},
|
|
306
|
-
[viewport, orientation
|
|
272
|
+
[viewport, orientation]
|
|
307
273
|
);
|
|
308
274
|
return {
|
|
309
275
|
isDragging: isDragging.current,
|
|
@@ -609,6 +575,8 @@ var ScrollAreaScrollbar = forwardRef(
|
|
|
609
575
|
scrollbarXId,
|
|
610
576
|
scrollbarYId
|
|
611
577
|
} = useScrollAreaContext();
|
|
578
|
+
const scrollStateRef = useRef(scrollState);
|
|
579
|
+
scrollStateRef.current = scrollState;
|
|
612
580
|
const hasOverflow = useHasOverflow(scrollState, orientation);
|
|
613
581
|
const shouldShow = useScrollbarShouldShow(type, hasOverflow, isScrolling, isHovering);
|
|
614
582
|
const scrollPercentage = useMemo(() => {
|
|
@@ -619,15 +587,23 @@ var ScrollAreaScrollbar = forwardRef(
|
|
|
619
587
|
const maxScroll = scrollState.scrollWidth - scrollState.clientWidth;
|
|
620
588
|
return maxScroll > 0 ? Math.round(scrollState.scrollLeft / maxScroll * 100) : 0;
|
|
621
589
|
}
|
|
622
|
-
}, [
|
|
590
|
+
}, [
|
|
591
|
+
orientation,
|
|
592
|
+
scrollState.scrollTop,
|
|
593
|
+
scrollState.scrollLeft,
|
|
594
|
+
scrollState.scrollHeight,
|
|
595
|
+
scrollState.clientHeight,
|
|
596
|
+
scrollState.scrollWidth,
|
|
597
|
+
scrollState.clientWidth
|
|
598
|
+
]);
|
|
623
599
|
const handleTrackClick = useCallback(
|
|
624
600
|
(e) => {
|
|
625
601
|
if (!viewport) return;
|
|
626
602
|
if (e.target === e.currentTarget) {
|
|
627
|
-
handleScrollbarTrackClick(e, viewport,
|
|
603
|
+
handleScrollbarTrackClick(e, viewport, scrollStateRef.current, orientation);
|
|
628
604
|
}
|
|
629
605
|
},
|
|
630
|
-
[viewport,
|
|
606
|
+
[viewport, orientation]
|
|
631
607
|
);
|
|
632
608
|
const tv = useMemo(
|
|
633
609
|
() => ScrollTv({
|
|
@@ -746,7 +722,7 @@ var ScrollAreaRoot = forwardRef(
|
|
|
746
722
|
const viewportId = `scroll-viewport${reactId}`;
|
|
747
723
|
const scrollbarXId = `scroll-x${reactId}`;
|
|
748
724
|
const scrollbarYId = `scroll-y${reactId}`;
|
|
749
|
-
const { scrollState, isHovering, isScrolling, handleMouseEnter, handleMouseLeave } = useScrollStateAndVisibility(viewport);
|
|
725
|
+
const { scrollState, isHovering, isScrolling, handleMouseEnter, handleMouseLeave } = useScrollStateAndVisibility(viewport, content);
|
|
750
726
|
const staticConfig = useMemo(
|
|
751
727
|
() => ({
|
|
752
728
|
orientation,
|
|
@@ -757,11 +733,14 @@ var ScrollAreaRoot = forwardRef(
|
|
|
757
733
|
}),
|
|
758
734
|
[orientation, scrollbarMode, hoverBoundary, variant, type]
|
|
759
735
|
);
|
|
760
|
-
const
|
|
736
|
+
const stateValue = useMemo(
|
|
737
|
+
() => ({ scrollState, isHovering, isScrolling }),
|
|
738
|
+
[scrollState, isHovering, isScrolling]
|
|
739
|
+
);
|
|
740
|
+
const configValue = useMemo(
|
|
761
741
|
() => ({
|
|
762
742
|
content,
|
|
763
743
|
orientation: staticConfig.orientation,
|
|
764
|
-
scrollState,
|
|
765
744
|
scrollbarMode: staticConfig.scrollbarMode,
|
|
766
745
|
hoverBoundary: staticConfig.hoverBoundary,
|
|
767
746
|
scrollbarX,
|
|
@@ -777,9 +756,6 @@ var ScrollAreaRoot = forwardRef(
|
|
|
777
756
|
variant: staticConfig.variant,
|
|
778
757
|
viewport,
|
|
779
758
|
type: staticConfig.type,
|
|
780
|
-
isHovering,
|
|
781
|
-
isScrolling,
|
|
782
|
-
// Add ID-related values
|
|
783
759
|
rootId,
|
|
784
760
|
viewportId,
|
|
785
761
|
scrollbarXId,
|
|
@@ -787,14 +763,11 @@ var ScrollAreaRoot = forwardRef(
|
|
|
787
763
|
}),
|
|
788
764
|
[
|
|
789
765
|
content,
|
|
790
|
-
scrollState,
|
|
791
766
|
scrollbarX,
|
|
792
767
|
scrollbarY,
|
|
793
768
|
thumbX,
|
|
794
769
|
thumbY,
|
|
795
770
|
viewport,
|
|
796
|
-
isHovering,
|
|
797
|
-
isScrolling,
|
|
798
771
|
staticConfig,
|
|
799
772
|
rootId,
|
|
800
773
|
viewportId,
|
|
@@ -859,7 +832,7 @@ var ScrollAreaRoot = forwardRef(
|
|
|
859
832
|
}
|
|
860
833
|
return scrollbars;
|
|
861
834
|
}, [orientation]);
|
|
862
|
-
return /* @__PURE__ */ jsx(
|
|
835
|
+
return /* @__PURE__ */ jsx(ScrollAreaConfigContext.Provider, { value: configValue, children: /* @__PURE__ */ jsx(ScrollAreaStateContext.Provider, { value: stateValue, children: /* @__PURE__ */ jsxs(
|
|
863
836
|
"div",
|
|
864
837
|
{
|
|
865
838
|
ref,
|
|
@@ -875,13 +848,13 @@ var ScrollAreaRoot = forwardRef(
|
|
|
875
848
|
autoScrollbars
|
|
876
849
|
]
|
|
877
850
|
}
|
|
878
|
-
) });
|
|
851
|
+
) }) });
|
|
879
852
|
}
|
|
880
853
|
);
|
|
881
854
|
ScrollAreaRoot.displayName = "ScrollArea.Root";
|
|
882
855
|
var ScrollAreaViewport = forwardRef(
|
|
883
856
|
({ className, children, ...props }, ref) => {
|
|
884
|
-
const { setViewport, orientation, viewportId } =
|
|
857
|
+
const { setViewport, orientation, viewportId } = useScrollAreaConfigContext();
|
|
885
858
|
const scrollClass = useMemo(() => {
|
|
886
859
|
switch (orientation) {
|
|
887
860
|
case "horizontal":
|
|
@@ -918,7 +891,7 @@ var ScrollAreaViewport = forwardRef(
|
|
|
918
891
|
ScrollAreaViewport.displayName = "ScrollArea.Viewport";
|
|
919
892
|
var ScrollAreaContent = forwardRef(
|
|
920
893
|
({ as: As = "div", className, children, ...props }, ref) => {
|
|
921
|
-
const { setContent, orientation } =
|
|
894
|
+
const { setContent, orientation } = useScrollAreaConfigContext();
|
|
922
895
|
const setRef = useCallback(
|
|
923
896
|
(node) => {
|
|
924
897
|
setContent(node);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useCallback, useMemo } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { useScrollAreaConfigContext } from "../context/scroll-area-context.js";
|
|
4
4
|
import { tcx } from "../../../../shared/utils/tcx/tcx.js";
|
|
5
5
|
const ScrollAreaContent = forwardRef(
|
|
6
6
|
({ as: As = "div", className, children, ...props }, ref) => {
|
|
7
|
-
const { setContent, orientation } =
|
|
7
|
+
const { setContent, orientation } = useScrollAreaConfigContext();
|
|
8
8
|
const setRef = useCallback(
|
|
9
9
|
(node) => {
|
|
10
10
|
setContent(node);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useState, useId, useMemo } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { ScrollAreaConfigContext, ScrollAreaStateContext } from "../context/scroll-area-context.js";
|
|
4
4
|
import { ScrollTv } from "../tv.js";
|
|
5
5
|
import { ScrollAreaCorner } from "./scroll-area-corner.js";
|
|
6
6
|
import { ScrollAreaScrollbar } from "./scroll-area-scrollbar.js";
|
|
@@ -32,7 +32,7 @@ const ScrollAreaRoot = forwardRef(
|
|
|
32
32
|
const viewportId = `scroll-viewport${reactId}`;
|
|
33
33
|
const scrollbarXId = `scroll-x${reactId}`;
|
|
34
34
|
const scrollbarYId = `scroll-y${reactId}`;
|
|
35
|
-
const { scrollState, isHovering, isScrolling, handleMouseEnter, handleMouseLeave } = useScrollStateAndVisibility(viewport);
|
|
35
|
+
const { scrollState, isHovering, isScrolling, handleMouseEnter, handleMouseLeave } = useScrollStateAndVisibility(viewport, content);
|
|
36
36
|
const staticConfig = useMemo(
|
|
37
37
|
() => ({
|
|
38
38
|
orientation,
|
|
@@ -43,11 +43,14 @@ const ScrollAreaRoot = forwardRef(
|
|
|
43
43
|
}),
|
|
44
44
|
[orientation, scrollbarMode, hoverBoundary, variant, type]
|
|
45
45
|
);
|
|
46
|
-
const
|
|
46
|
+
const stateValue = useMemo(
|
|
47
|
+
() => ({ scrollState, isHovering, isScrolling }),
|
|
48
|
+
[scrollState, isHovering, isScrolling]
|
|
49
|
+
);
|
|
50
|
+
const configValue = useMemo(
|
|
47
51
|
() => ({
|
|
48
52
|
content,
|
|
49
53
|
orientation: staticConfig.orientation,
|
|
50
|
-
scrollState,
|
|
51
54
|
scrollbarMode: staticConfig.scrollbarMode,
|
|
52
55
|
hoverBoundary: staticConfig.hoverBoundary,
|
|
53
56
|
scrollbarX,
|
|
@@ -63,9 +66,6 @@ const ScrollAreaRoot = forwardRef(
|
|
|
63
66
|
variant: staticConfig.variant,
|
|
64
67
|
viewport,
|
|
65
68
|
type: staticConfig.type,
|
|
66
|
-
isHovering,
|
|
67
|
-
isScrolling,
|
|
68
|
-
// Add ID-related values
|
|
69
69
|
rootId,
|
|
70
70
|
viewportId,
|
|
71
71
|
scrollbarXId,
|
|
@@ -73,14 +73,11 @@ const ScrollAreaRoot = forwardRef(
|
|
|
73
73
|
}),
|
|
74
74
|
[
|
|
75
75
|
content,
|
|
76
|
-
scrollState,
|
|
77
76
|
scrollbarX,
|
|
78
77
|
scrollbarY,
|
|
79
78
|
thumbX,
|
|
80
79
|
thumbY,
|
|
81
80
|
viewport,
|
|
82
|
-
isHovering,
|
|
83
|
-
isScrolling,
|
|
84
81
|
staticConfig,
|
|
85
82
|
rootId,
|
|
86
83
|
viewportId,
|
|
@@ -145,7 +142,7 @@ const ScrollAreaRoot = forwardRef(
|
|
|
145
142
|
}
|
|
146
143
|
return scrollbars;
|
|
147
144
|
}, [orientation]);
|
|
148
|
-
return /* @__PURE__ */ jsx(
|
|
145
|
+
return /* @__PURE__ */ jsx(ScrollAreaConfigContext.Provider, { value: configValue, children: /* @__PURE__ */ jsx(ScrollAreaStateContext.Provider, { value: stateValue, children: /* @__PURE__ */ jsxs(
|
|
149
146
|
"div",
|
|
150
147
|
{
|
|
151
148
|
ref,
|
|
@@ -161,7 +158,7 @@ const ScrollAreaRoot = forwardRef(
|
|
|
161
158
|
autoScrollbars
|
|
162
159
|
]
|
|
163
160
|
}
|
|
164
|
-
) });
|
|
161
|
+
) }) });
|
|
165
162
|
}
|
|
166
163
|
);
|
|
167
164
|
ScrollAreaRoot.displayName = "ScrollArea.Root";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { forwardRef, useMemo, useCallback } from "react";
|
|
2
|
+
import { forwardRef, useRef, useMemo, useCallback } from "react";
|
|
3
3
|
import { useScrollAreaContext } from "../context/scroll-area-context.js";
|
|
4
4
|
import { ScrollTv } from "../tv.js";
|
|
5
5
|
import { handleScrollbarTrackClick, getScrollbarPositionStyle } from "../utils/index.js";
|
|
@@ -22,6 +22,8 @@ const ScrollAreaScrollbar = forwardRef(
|
|
|
22
22
|
scrollbarXId,
|
|
23
23
|
scrollbarYId
|
|
24
24
|
} = useScrollAreaContext();
|
|
25
|
+
const scrollStateRef = useRef(scrollState);
|
|
26
|
+
scrollStateRef.current = scrollState;
|
|
25
27
|
const hasOverflow = useHasOverflow(scrollState, orientation);
|
|
26
28
|
const shouldShow = useScrollbarShouldShow(type, hasOverflow, isScrolling, isHovering);
|
|
27
29
|
const scrollPercentage = useMemo(() => {
|
|
@@ -32,15 +34,23 @@ const ScrollAreaScrollbar = forwardRef(
|
|
|
32
34
|
const maxScroll = scrollState.scrollWidth - scrollState.clientWidth;
|
|
33
35
|
return maxScroll > 0 ? Math.round(scrollState.scrollLeft / maxScroll * 100) : 0;
|
|
34
36
|
}
|
|
35
|
-
}, [
|
|
37
|
+
}, [
|
|
38
|
+
orientation,
|
|
39
|
+
scrollState.scrollTop,
|
|
40
|
+
scrollState.scrollLeft,
|
|
41
|
+
scrollState.scrollHeight,
|
|
42
|
+
scrollState.clientHeight,
|
|
43
|
+
scrollState.scrollWidth,
|
|
44
|
+
scrollState.clientWidth
|
|
45
|
+
]);
|
|
36
46
|
const handleTrackClick = useCallback(
|
|
37
47
|
(e) => {
|
|
38
48
|
if (!viewport) return;
|
|
39
49
|
if (e.target === e.currentTarget) {
|
|
40
|
-
handleScrollbarTrackClick(e, viewport,
|
|
50
|
+
handleScrollbarTrackClick(e, viewport, scrollStateRef.current, orientation);
|
|
41
51
|
}
|
|
42
52
|
},
|
|
43
|
-
[viewport,
|
|
53
|
+
[viewport, orientation]
|
|
44
54
|
);
|
|
45
55
|
const tv = useMemo(
|
|
46
56
|
() => ScrollTv({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, useMemo, useCallback } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { useScrollAreaConfigContext } from "../context/scroll-area-context.js";
|
|
4
4
|
import { tcx } from "../../../../shared/utils/tcx/tcx.js";
|
|
5
5
|
const ScrollAreaViewport = forwardRef(
|
|
6
6
|
({ className, children, ...props }, ref) => {
|
|
7
|
-
const { setViewport, orientation, viewportId } =
|
|
7
|
+
const { setViewport, orientation, viewportId } = useScrollAreaConfigContext();
|
|
8
8
|
const scrollClass = useMemo(() => {
|
|
9
9
|
switch (orientation) {
|
|
10
10
|
case "horizontal":
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
-
import { ScrollAreaContextType } from '../types';
|
|
2
|
-
export declare const
|
|
1
|
+
import { ScrollAreaConfigContextType, ScrollAreaContextType, ScrollAreaStateContextType } from '../types';
|
|
2
|
+
export declare const ScrollAreaStateContext: import('react').Context<ScrollAreaStateContextType | null>;
|
|
3
|
+
export declare const ScrollAreaConfigContext: import('react').Context<ScrollAreaConfigContextType | null>;
|
|
4
|
+
/**
|
|
5
|
+
* Access only the frequently-changing state (scrollState, isHovering, isScrolling).
|
|
6
|
+
* Use this in components that need to react to scroll position changes.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useScrollAreaStateContext(): ScrollAreaStateContextType;
|
|
9
|
+
/**
|
|
10
|
+
* Access only the rarely-changing config (orientation, setters, refs, IDs).
|
|
11
|
+
* Use this in components that do NOT need scrollState — they won't re-render on scroll.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useScrollAreaConfigContext(): ScrollAreaConfigContextType;
|
|
14
|
+
/**
|
|
15
|
+
* Combined hook for components that need both state and config (Scrollbar, Thumb, Corner).
|
|
16
|
+
* Maintains backward compatibility with existing useScrollAreaContext() usage.
|
|
17
|
+
*/
|
|
3
18
|
export declare function useScrollAreaContext(): ScrollAreaContextType;
|
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
import { createContext, useContext } from "react";
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const ScrollAreaStateContext = createContext(null);
|
|
3
|
+
const ScrollAreaConfigContext = createContext(null);
|
|
4
|
+
const ERROR_MESSAGE = "ScrollArea compound components must be used within ScrollArea";
|
|
5
|
+
function useScrollAreaStateContext() {
|
|
6
|
+
const context = useContext(ScrollAreaStateContext);
|
|
5
7
|
if (!context) {
|
|
6
|
-
throw new Error(
|
|
8
|
+
throw new Error(ERROR_MESSAGE);
|
|
7
9
|
}
|
|
8
10
|
return context;
|
|
9
11
|
}
|
|
12
|
+
function useScrollAreaConfigContext() {
|
|
13
|
+
const context = useContext(ScrollAreaConfigContext);
|
|
14
|
+
if (!context) {
|
|
15
|
+
throw new Error(ERROR_MESSAGE);
|
|
16
|
+
}
|
|
17
|
+
return context;
|
|
18
|
+
}
|
|
19
|
+
function useScrollAreaContext() {
|
|
20
|
+
const state = useScrollAreaStateContext();
|
|
21
|
+
const config = useScrollAreaConfigContext();
|
|
22
|
+
return { ...state, ...config };
|
|
23
|
+
}
|
|
10
24
|
export {
|
|
11
|
-
|
|
12
|
-
|
|
25
|
+
ScrollAreaConfigContext,
|
|
26
|
+
ScrollAreaStateContext,
|
|
27
|
+
useScrollAreaConfigContext,
|
|
28
|
+
useScrollAreaContext,
|
|
29
|
+
useScrollAreaStateContext
|
|
13
30
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ScrollState } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Merged scroll state and visibility management hook
|
|
3
|
+
* Merged scroll state and visibility management hook
|
|
4
4
|
*/
|
|
5
|
-
export declare function useScrollStateAndVisibility(viewport: HTMLDivElement | null): {
|
|
5
|
+
export declare function useScrollStateAndVisibility(viewport: HTMLDivElement | null, content: HTMLDivElement | null): {
|
|
6
6
|
scrollState: ScrollState;
|
|
7
7
|
isHovering: boolean;
|
|
8
8
|
isScrolling: boolean;
|