@trackunit/react-components 0.5.0 → 0.5.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/index.cjs.js +58 -1
- package/index.esm.js +58 -2
- package/package.json +1 -1
- package/src/hooks/index.d.ts +1 -0
- package/src/hooks/useScrollDetection.d.ts +16 -0
package/index.cjs.js
CHANGED
|
@@ -13,8 +13,8 @@ var stringTs = require('string-ts');
|
|
|
13
13
|
var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
|
|
14
14
|
var reactSlot = require('@radix-ui/react-slot');
|
|
15
15
|
var isEqual = require('lodash/isEqual');
|
|
16
|
-
var reactRouter = require('@tanstack/react-router');
|
|
17
16
|
var usehooksTs = require('usehooks-ts');
|
|
17
|
+
var reactRouter = require('@tanstack/react-router');
|
|
18
18
|
var react = require('@floating-ui/react');
|
|
19
19
|
var omit = require('lodash/omit');
|
|
20
20
|
var tailwindMerge = require('tailwind-merge');
|
|
@@ -1309,6 +1309,62 @@ const getWindowSize = () => {
|
|
|
1309
1309
|
}
|
|
1310
1310
|
};
|
|
1311
1311
|
|
|
1312
|
+
const SCROLL_DEBOUNCE_TIME = 50;
|
|
1313
|
+
/**
|
|
1314
|
+
* Hook for getting detecting scroll values.
|
|
1315
|
+
*
|
|
1316
|
+
* @param {useRef} elementRef - Ref hook holding the element that needs to be observed during scrolling
|
|
1317
|
+
* @returns {object} An object containing if the element is scrollable, is at the top, is at the bottom, and its current scroll position.
|
|
1318
|
+
*/
|
|
1319
|
+
const useScrollDetection = (elementRef) => {
|
|
1320
|
+
const [isScrollable, setIsScrollable] = React.useState(false);
|
|
1321
|
+
const [isAtTop, setIsAtTop] = React.useState(true);
|
|
1322
|
+
const [isAtBottom, setIsAtBottom] = React.useState(false);
|
|
1323
|
+
const [scrollPosition, setScrollPosition] = React.useState({ top: 0, bottom: 0 });
|
|
1324
|
+
const observerRef = React.useRef();
|
|
1325
|
+
const checkScrollable = React.useCallback(() => {
|
|
1326
|
+
const element = elementRef.current;
|
|
1327
|
+
if (!element) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
const hasOverflow = element.scrollHeight > element.clientHeight;
|
|
1331
|
+
setIsScrollable(hasOverflow);
|
|
1332
|
+
}, [elementRef]);
|
|
1333
|
+
const checkScrollPosition = React.useCallback(() => {
|
|
1334
|
+
const element = elementRef.current;
|
|
1335
|
+
if (!element) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
const { scrollTop, scrollHeight, clientHeight } = element;
|
|
1339
|
+
setIsAtTop(scrollTop === 0);
|
|
1340
|
+
setIsAtBottom(Math.abs(scrollHeight - scrollTop - clientHeight) < 1);
|
|
1341
|
+
setScrollPosition(prev => ({ ...prev, top: scrollTop, bottom: clientHeight - scrollTop }));
|
|
1342
|
+
}, [elementRef]);
|
|
1343
|
+
const debouncedCheckScrollPosition = usehooksTs.useDebounceCallback(checkScrollPosition, SCROLL_DEBOUNCE_TIME);
|
|
1344
|
+
React.useEffect(() => {
|
|
1345
|
+
const element = elementRef.current;
|
|
1346
|
+
if (!element) {
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
// Initial checks
|
|
1350
|
+
checkScrollable();
|
|
1351
|
+
checkScrollPosition();
|
|
1352
|
+
observerRef.current = new ResizeObserver(() => {
|
|
1353
|
+
checkScrollable();
|
|
1354
|
+
checkScrollPosition();
|
|
1355
|
+
});
|
|
1356
|
+
observerRef.current.observe(element);
|
|
1357
|
+
element.addEventListener("scroll", debouncedCheckScrollPosition);
|
|
1358
|
+
return () => {
|
|
1359
|
+
if (observerRef.current) {
|
|
1360
|
+
observerRef.current.disconnect();
|
|
1361
|
+
}
|
|
1362
|
+
element.removeEventListener("scroll", debouncedCheckScrollPosition);
|
|
1363
|
+
};
|
|
1364
|
+
}, [elementRef, checkScrollable, checkScrollPosition, debouncedCheckScrollPosition]);
|
|
1365
|
+
return { isScrollable, isAtTop, isAtBottom, scrollPosition };
|
|
1366
|
+
};
|
|
1367
|
+
|
|
1312
1368
|
/**
|
|
1313
1369
|
* A useRef that updates its given value whenever it changes.
|
|
1314
1370
|
*
|
|
@@ -4923,6 +4979,7 @@ exports.usePopoverContext = usePopoverContext;
|
|
|
4923
4979
|
exports.usePrevious = usePrevious;
|
|
4924
4980
|
exports.usePrompt = usePrompt;
|
|
4925
4981
|
exports.useResize = useResize;
|
|
4982
|
+
exports.useScrollDetection = useScrollDetection;
|
|
4926
4983
|
exports.useSelfUpdatingRef = useSelfUpdatingRef;
|
|
4927
4984
|
exports.useTimeout = useTimeout;
|
|
4928
4985
|
exports.useViewportSize = useViewportSize;
|
package/index.esm.js
CHANGED
|
@@ -12,8 +12,8 @@ import { snakeCase, titleCase } from 'string-ts';
|
|
|
12
12
|
import { cvaMerge } from '@trackunit/css-class-variance-utilities';
|
|
13
13
|
import { Slottable, Slot } from '@radix-ui/react-slot';
|
|
14
14
|
import isEqual from 'lodash/isEqual';
|
|
15
|
+
import { useDebounceCallback, useCopyToClipboard } from 'usehooks-ts';
|
|
15
16
|
import { Link, useBlocker } from '@tanstack/react-router';
|
|
16
|
-
import { useCopyToClipboard } from 'usehooks-ts';
|
|
17
17
|
import { useFloating, autoUpdate, offset, flip, shift, size, useClick, useDismiss, useHover as useHover$1, useRole, useInteractions, useMergeRefs, FloatingPortal, FloatingFocusManager, arrow, useTransitionStatus, FloatingArrow } from '@floating-ui/react';
|
|
18
18
|
import omit from 'lodash/omit';
|
|
19
19
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -1289,6 +1289,62 @@ const getWindowSize = () => {
|
|
|
1289
1289
|
}
|
|
1290
1290
|
};
|
|
1291
1291
|
|
|
1292
|
+
const SCROLL_DEBOUNCE_TIME = 50;
|
|
1293
|
+
/**
|
|
1294
|
+
* Hook for getting detecting scroll values.
|
|
1295
|
+
*
|
|
1296
|
+
* @param {useRef} elementRef - Ref hook holding the element that needs to be observed during scrolling
|
|
1297
|
+
* @returns {object} An object containing if the element is scrollable, is at the top, is at the bottom, and its current scroll position.
|
|
1298
|
+
*/
|
|
1299
|
+
const useScrollDetection = (elementRef) => {
|
|
1300
|
+
const [isScrollable, setIsScrollable] = useState(false);
|
|
1301
|
+
const [isAtTop, setIsAtTop] = useState(true);
|
|
1302
|
+
const [isAtBottom, setIsAtBottom] = useState(false);
|
|
1303
|
+
const [scrollPosition, setScrollPosition] = useState({ top: 0, bottom: 0 });
|
|
1304
|
+
const observerRef = useRef();
|
|
1305
|
+
const checkScrollable = useCallback(() => {
|
|
1306
|
+
const element = elementRef.current;
|
|
1307
|
+
if (!element) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
const hasOverflow = element.scrollHeight > element.clientHeight;
|
|
1311
|
+
setIsScrollable(hasOverflow);
|
|
1312
|
+
}, [elementRef]);
|
|
1313
|
+
const checkScrollPosition = useCallback(() => {
|
|
1314
|
+
const element = elementRef.current;
|
|
1315
|
+
if (!element) {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
const { scrollTop, scrollHeight, clientHeight } = element;
|
|
1319
|
+
setIsAtTop(scrollTop === 0);
|
|
1320
|
+
setIsAtBottom(Math.abs(scrollHeight - scrollTop - clientHeight) < 1);
|
|
1321
|
+
setScrollPosition(prev => ({ ...prev, top: scrollTop, bottom: clientHeight - scrollTop }));
|
|
1322
|
+
}, [elementRef]);
|
|
1323
|
+
const debouncedCheckScrollPosition = useDebounceCallback(checkScrollPosition, SCROLL_DEBOUNCE_TIME);
|
|
1324
|
+
useEffect(() => {
|
|
1325
|
+
const element = elementRef.current;
|
|
1326
|
+
if (!element) {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
// Initial checks
|
|
1330
|
+
checkScrollable();
|
|
1331
|
+
checkScrollPosition();
|
|
1332
|
+
observerRef.current = new ResizeObserver(() => {
|
|
1333
|
+
checkScrollable();
|
|
1334
|
+
checkScrollPosition();
|
|
1335
|
+
});
|
|
1336
|
+
observerRef.current.observe(element);
|
|
1337
|
+
element.addEventListener("scroll", debouncedCheckScrollPosition);
|
|
1338
|
+
return () => {
|
|
1339
|
+
if (observerRef.current) {
|
|
1340
|
+
observerRef.current.disconnect();
|
|
1341
|
+
}
|
|
1342
|
+
element.removeEventListener("scroll", debouncedCheckScrollPosition);
|
|
1343
|
+
};
|
|
1344
|
+
}, [elementRef, checkScrollable, checkScrollPosition, debouncedCheckScrollPosition]);
|
|
1345
|
+
return { isScrollable, isAtTop, isAtBottom, scrollPosition };
|
|
1346
|
+
};
|
|
1347
|
+
|
|
1292
1348
|
/**
|
|
1293
1349
|
* A useRef that updates its given value whenever it changes.
|
|
1294
1350
|
*
|
|
@@ -4806,4 +4862,4 @@ const cvaClickable = cvaMerge([
|
|
|
4806
4862
|
},
|
|
4807
4863
|
});
|
|
4808
4864
|
|
|
4809
|
-
export { Alert, Badge, Breadcrumb, BreadcrumbContainer, Button, Card, CardBody, CardFooter, CardHeader, Collapse, CompletionStatusIndicator, CopyableText, EmptyState, EmptyValue, ExternalLink, Heading, Icon, IconButton, Indicator, KPICard, MenuDivider, MenuItem, MenuList, MoreMenu, Notice, PackageNameStoryComponent, Page, PageContent, PageHeader, Pagination, Polygon, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonLines, Spacer, Spinner, StarButton, Tab, TabContent, TabList, Tabs, Tag, Text, Timeline, TimelineElement, ToggleGroup, ToggleItem, Tooltip, ValueBar, VirtualizedList, WidgetBody, cvaButton, cvaButtonPrefixSuffix, cvaButtonSpinner, cvaButtonSpinnerContainer, cvaClickable, cvaIconButton, cvaIndicator, cvaIndicatorIcon, cvaIndicatorIconBackground, cvaIndicatorLabel, cvaIndicatorPing, cvaInteractableItem, cvaMenuItem, cvaMenuItemLabel, cvaMenuItemPrefix, cvaMenuItemStyle, cvaMenuItemSuffix, docs, getDevicePixelRatio, getValueBarColorByValue, iconColorNames, iconPalette, setLocalStorage, useClickOutside, useContinuousTimeout, useDebounce, useDevicePixelRatio, useGeometry, useHover, useIsFirstRender, useIsFullscreen, useIsTextCutOff, useLocalStorage, useLocalStorageReducer, useOptionallyElevatedState, useOverflowItems, usePopoverContext, usePrevious, usePrompt, useResize, useSelfUpdatingRef, useTimeout, useViewportSize, useWindowActivity };
|
|
4865
|
+
export { Alert, Badge, Breadcrumb, BreadcrumbContainer, Button, Card, CardBody, CardFooter, CardHeader, Collapse, CompletionStatusIndicator, CopyableText, EmptyState, EmptyValue, ExternalLink, Heading, Icon, IconButton, Indicator, KPICard, MenuDivider, MenuItem, MenuList, MoreMenu, Notice, PackageNameStoryComponent, Page, PageContent, PageHeader, Pagination, Polygon, Popover, PopoverContent, PopoverTitle, PopoverTrigger, Prompt, ROLE_CARD, SectionHeader, Sidebar, SkeletonLines, Spacer, Spinner, StarButton, Tab, TabContent, TabList, Tabs, Tag, Text, Timeline, TimelineElement, ToggleGroup, ToggleItem, Tooltip, ValueBar, VirtualizedList, WidgetBody, cvaButton, cvaButtonPrefixSuffix, cvaButtonSpinner, cvaButtonSpinnerContainer, cvaClickable, cvaIconButton, cvaIndicator, cvaIndicatorIcon, cvaIndicatorIconBackground, cvaIndicatorLabel, cvaIndicatorPing, cvaInteractableItem, cvaMenuItem, cvaMenuItemLabel, cvaMenuItemPrefix, cvaMenuItemStyle, cvaMenuItemSuffix, docs, getDevicePixelRatio, getValueBarColorByValue, iconColorNames, iconPalette, setLocalStorage, useClickOutside, useContinuousTimeout, useDebounce, useDevicePixelRatio, useGeometry, useHover, useIsFirstRender, useIsFullscreen, useIsTextCutOff, useLocalStorage, useLocalStorageReducer, useOptionallyElevatedState, useOverflowItems, usePopoverContext, usePrevious, usePrompt, useResize, useScrollDetection, useSelfUpdatingRef, useTimeout, useViewportSize, useWindowActivity };
|
package/package.json
CHANGED
package/src/hooks/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./useIsTextCutOff";
|
|
|
13
13
|
export * from "./useOptionallyElevatedState";
|
|
14
14
|
export * from "./usePrevious";
|
|
15
15
|
export * from "./useResize";
|
|
16
|
+
export * from "./useScrollDetection";
|
|
16
17
|
export * from "./useSelfUpdatingRef";
|
|
17
18
|
export * from "./useTimeout";
|
|
18
19
|
export * from "./useViewportSize";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Hook for getting detecting scroll values.
|
|
4
|
+
*
|
|
5
|
+
* @param {useRef} elementRef - Ref hook holding the element that needs to be observed during scrolling
|
|
6
|
+
* @returns {object} An object containing if the element is scrollable, is at the top, is at the bottom, and its current scroll position.
|
|
7
|
+
*/
|
|
8
|
+
export declare const useScrollDetection: (elementRef: RefObject<HTMLElement>) => {
|
|
9
|
+
isScrollable: boolean;
|
|
10
|
+
isAtTop: boolean;
|
|
11
|
+
isAtBottom: boolean;
|
|
12
|
+
scrollPosition: {
|
|
13
|
+
top: number;
|
|
14
|
+
bottom: number;
|
|
15
|
+
};
|
|
16
|
+
};
|