Refine useMaskedScroll API
This commit is contained in:
parent
5f9a340a25
commit
7518a88d41
@ -164,7 +164,7 @@ export default function CommandKClient({
|
|||||||
}, [mobileViewportHeight]);
|
}, [mobileViewportHeight]);
|
||||||
|
|
||||||
const refScroll = useRef<HTMLDivElement>(null);
|
const refScroll = useRef<HTMLDivElement>(null);
|
||||||
const { maskStyle, updateMask } = useMaskedScroll({
|
const { styleMask, updateMask } = useMaskedScroll({
|
||||||
ref: refScroll,
|
ref: refScroll,
|
||||||
updateMaskOnEvents: false,
|
updateMaskOnEvents: false,
|
||||||
fadeSize: 50,
|
fadeSize: 50,
|
||||||
@ -592,7 +592,7 @@ export default function CommandKClient({
|
|||||||
'mx-3 pt-2 pb-3.5',
|
'mx-3 pt-2 pb-3.5',
|
||||||
'[&>*>*>*]:mt-2.5',
|
'[&>*>*>*]:mt-2.5',
|
||||||
)}
|
)}
|
||||||
style={{ ...maskStyle, maxHeight }}
|
style={{ ...styleMask, maxHeight }}
|
||||||
>
|
>
|
||||||
<div className="-mt-2.5">
|
<div className="-mt-2.5">
|
||||||
<Command.Empty className="mt-1 pl-3 text-dim pb-1">
|
<Command.Empty className="mt-1 pl-3 text-dim pb-1">
|
||||||
|
|||||||
@ -1,26 +1,29 @@
|
|||||||
import clsx from 'clsx/lite';
|
import clsx from 'clsx/lite';
|
||||||
import { HTMLAttributes, useRef } from 'react';
|
import { HTMLAttributes, useRef } from 'react';
|
||||||
import useMaskedScroll, { MaskedScrollExternalProps } from './useMaskedScroll';
|
import useMaskedScroll from './useMaskedScroll';
|
||||||
|
|
||||||
export default function MaskedScroll({
|
export default function MaskedScroll({
|
||||||
direction = 'vertical',
|
direction = 'vertical',
|
||||||
fadeSize,
|
fadeSize,
|
||||||
scrollToEndOnMount,
|
animationDuration,
|
||||||
hideScrollbar,
|
hideScrollbar,
|
||||||
|
updateMaskOnEvents,
|
||||||
|
scrollToEndOnMount,
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: HTMLAttributes<HTMLDivElement> &
|
}: HTMLAttributes<HTMLDivElement> &
|
||||||
MaskedScrollExternalProps & {
|
Parameters<typeof useMaskedScroll>[0]) {
|
||||||
hideScrollbar?: boolean
|
|
||||||
}) {
|
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const { maskStyle } = useMaskedScroll({
|
const { styleMask } = useMaskedScroll({
|
||||||
ref,
|
ref,
|
||||||
direction,
|
direction,
|
||||||
fadeSize,
|
fadeSize,
|
||||||
|
animationDuration,
|
||||||
|
hideScrollbar,
|
||||||
|
updateMaskOnEvents,
|
||||||
scrollToEndOnMount,
|
scrollToEndOnMount,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -31,10 +34,9 @@ MaskedScrollExternalProps & {
|
|||||||
direction === 'vertical'
|
direction === 'vertical'
|
||||||
? 'max-h-full overflow-y-scroll'
|
? 'max-h-full overflow-y-scroll'
|
||||||
: 'max-w-full overflow-x-scroll',
|
: 'max-w-full overflow-x-scroll',
|
||||||
hideScrollbar && '[scrollbar-width:none]',
|
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
style={{ ...maskStyle, ...style }}
|
style={{ ...styleMask, ...style }}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>;
|
</div>;
|
||||||
|
|||||||
@ -6,27 +6,26 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
const CSS_VAR_START = '--mask-start';
|
const CSS_VAR_MASK_COLOR_START = '--mask-color-start';
|
||||||
const CSS_VAR_END = '--mask-end';
|
const CSS_VAR_MASK_COLOR_END = '--mask-color-end';
|
||||||
|
|
||||||
export interface MaskedScrollExternalProps {
|
|
||||||
direction?: 'vertical' | 'horizontal'
|
|
||||||
fadeSize?: number
|
|
||||||
animationDuration?: number
|
|
||||||
scrollToEndOnMount?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function useMaskedScroll({
|
export default function useMaskedScroll({
|
||||||
ref: containerRef,
|
ref: containerRef,
|
||||||
direction = 'vertical',
|
direction = 'vertical',
|
||||||
fadeSize = 24,
|
fadeSize = 24,
|
||||||
animationDuration = 0.3,
|
animationDuration = 0.3,
|
||||||
|
hideScrollbar,
|
||||||
// Disable when calling 'updateMask' explicitly
|
// Disable when calling 'updateMask' explicitly
|
||||||
updateMaskOnEvents = true,
|
updateMaskOnEvents = true,
|
||||||
scrollToEndOnMount,
|
scrollToEndOnMount,
|
||||||
}: MaskedScrollExternalProps & {
|
}: {
|
||||||
ref: RefObject<HTMLDivElement | null>
|
ref: RefObject<HTMLDivElement | null>
|
||||||
updateMaskOnEvents?: boolean
|
updateMaskOnEvents?: boolean
|
||||||
|
direction?: 'vertical' | 'horizontal'
|
||||||
|
fadeSize?: number
|
||||||
|
animationDuration?: number
|
||||||
|
hideScrollbar?: boolean
|
||||||
|
scrollToEndOnMount?: boolean
|
||||||
}) {
|
}) {
|
||||||
const isVertical = direction === 'vertical';
|
const isVertical = direction === 'vertical';
|
||||||
|
|
||||||
@ -39,12 +38,12 @@ export default function useMaskedScroll({
|
|||||||
const end = isVertical
|
const end = isVertical
|
||||||
? (ref.scrollHeight - ref.scrollTop) - ref.clientHeight < 1
|
? (ref.scrollHeight - ref.scrollTop) - ref.clientHeight < 1
|
||||||
: (ref.scrollWidth - ref.scrollLeft) - ref.clientWidth < 1;
|
: (ref.scrollWidth - ref.scrollLeft) - ref.clientWidth < 1;
|
||||||
ref.style.setProperty(CSS_VAR_START, !start
|
ref.style.setProperty(CSS_VAR_MASK_COLOR_START, start
|
||||||
? 'rgba(0, 0, 0, 0)'
|
? 'rgba(0, 0, 0, 1)'
|
||||||
: 'rgba(0, 0, 0, 1)');
|
: 'rgba(0, 0, 0, 0)');
|
||||||
ref.style.setProperty(CSS_VAR_END, !end
|
ref.style.setProperty(CSS_VAR_MASK_COLOR_END, end
|
||||||
? 'rgba(0, 0, 0, 0)'
|
? 'rgba(0, 0, 0, 1)'
|
||||||
: 'rgba(0, 0, 0, 1)');
|
: 'rgba(0, 0, 0, 0)');
|
||||||
}
|
}
|
||||||
}, [containerRef, isVertical]);
|
}, [containerRef, isVertical]);
|
||||||
|
|
||||||
@ -76,13 +75,13 @@ export default function useMaskedScroll({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
try {
|
try {
|
||||||
window.CSS.registerProperty({
|
window.CSS.registerProperty({
|
||||||
name: CSS_VAR_START,
|
name: CSS_VAR_MASK_COLOR_START,
|
||||||
syntax: '<color>',
|
syntax: '<color>',
|
||||||
initialValue: 'rgba(0, 0, 0, 0)',
|
initialValue: 'rgba(0, 0, 0, 0)',
|
||||||
inherits: false,
|
inherits: false,
|
||||||
});
|
});
|
||||||
window.CSS.registerProperty({
|
window.CSS.registerProperty({
|
||||||
name: CSS_VAR_END,
|
name: CSS_VAR_MASK_COLOR_END,
|
||||||
syntax: '<color>',
|
syntax: '<color>',
|
||||||
initialValue: 'rgba(0, 0, 0, 0)',
|
initialValue: 'rgba(0, 0, 0, 0)',
|
||||||
inherits: false,
|
inherits: false,
|
||||||
@ -90,23 +89,24 @@ export default function useMaskedScroll({
|
|||||||
} catch {}
|
} catch {}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const maskStyle: CSSProperties = useMemo(() => {
|
const styleMask: CSSProperties = useMemo(() => {
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const gradientStart = `linear-gradient(to ${isVertical ? 'bottom' : 'right'}, var(${CSS_VAR_START}), black ${fadeSize}px)`;
|
const gradientStart = `linear-gradient(to ${isVertical ? 'bottom' : 'right'}, var(${CSS_VAR_MASK_COLOR_START}), black ${fadeSize}px)`;
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const gradientEnd = `linear-gradient(to ${isVertical ? 'top' : 'left'}, var(${CSS_VAR_END}), black ${fadeSize}px)`;
|
const gradientEnd = `linear-gradient(to ${isVertical ? 'top' : 'left'}, var(${CSS_VAR_MASK_COLOR_END}), black ${fadeSize}px)`;
|
||||||
const maskImage = [gradientStart, gradientEnd].join(', ');
|
const maskImage = [gradientStart, gradientEnd].join(', ');
|
||||||
const transition = [
|
const transition = [
|
||||||
`${CSS_VAR_START} ${animationDuration}s ease-in-out`,
|
`${CSS_VAR_MASK_COLOR_START} ${animationDuration}s ease-in-out`,
|
||||||
`${CSS_VAR_END} ${animationDuration}s ease-in-out`,
|
`${CSS_VAR_MASK_COLOR_END} ${animationDuration}s ease-in-out`,
|
||||||
].join(', ');
|
].join(', ');
|
||||||
return {
|
return {
|
||||||
maskImage,
|
maskImage,
|
||||||
maskComposite: 'intersect',
|
maskComposite: 'intersect',
|
||||||
maskRepeat: 'no-repeat',
|
maskRepeat: 'no-repeat',
|
||||||
transition,
|
transition,
|
||||||
|
...hideScrollbar && { scrollbarWidth: 'none' },
|
||||||
};
|
};
|
||||||
}, [isVertical, fadeSize, animationDuration]);
|
}, [isVertical, fadeSize, animationDuration, hideScrollbar]);
|
||||||
|
|
||||||
return { maskStyle, updateMask };
|
return { styleMask, updateMask };
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user