mirror of
https://github.com/ourongxing/newsnow.git
synced 2025-01-19 03:09:14 +08:00
feat: better overlayscrollbar
This commit is contained in:
parent
a05f0d54b5
commit
d86da2387d
@ -52,7 +52,6 @@
|
|||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"ofetch": "^1.4.1",
|
"ofetch": "^1.4.1",
|
||||||
"overlayscrollbars": "^2.10.0",
|
"overlayscrollbars": "^2.10.0",
|
||||||
"overlayscrollbars-react": "^0.5.6",
|
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-use": "^17.5.1",
|
"react-use": "^17.5.1",
|
||||||
|
85
pnpm-lock.yaml
generated
85
pnpm-lock.yaml
generated
@ -92,18 +92,12 @@ importers:
|
|||||||
md5:
|
md5:
|
||||||
specifier: ^2.3.0
|
specifier: ^2.3.0
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
motion:
|
|
||||||
specifier: ^10.18.0
|
|
||||||
version: 10.18.0
|
|
||||||
ofetch:
|
ofetch:
|
||||||
specifier: ^1.4.1
|
specifier: ^1.4.1
|
||||||
version: 1.4.1
|
version: 1.4.1
|
||||||
overlayscrollbars:
|
overlayscrollbars:
|
||||||
specifier: ^2.10.0
|
specifier: ^2.10.0
|
||||||
version: 2.10.0
|
version: 2.10.0
|
||||||
overlayscrollbars-react:
|
|
||||||
specifier: ^0.5.6
|
|
||||||
version: 0.5.6(overlayscrollbars@2.10.0)(react@18.3.1)
|
|
||||||
react:
|
react:
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@ -1549,24 +1543,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@motionone/animation@10.18.0':
|
|
||||||
resolution: {integrity: sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==}
|
|
||||||
|
|
||||||
'@motionone/dom@10.18.0':
|
|
||||||
resolution: {integrity: sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==}
|
|
||||||
|
|
||||||
'@motionone/easing@10.18.0':
|
|
||||||
resolution: {integrity: sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==}
|
|
||||||
|
|
||||||
'@motionone/generators@10.18.0':
|
|
||||||
resolution: {integrity: sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==}
|
|
||||||
|
|
||||||
'@motionone/types@10.17.1':
|
|
||||||
resolution: {integrity: sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A==}
|
|
||||||
|
|
||||||
'@motionone/utils@10.18.0':
|
|
||||||
resolution: {integrity: sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==}
|
|
||||||
|
|
||||||
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
|
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
|
||||||
resolution: {integrity: sha512-dnurqJdedbU8D1Ngudf10nXvc4BbVSe4ki9U2LUZoGMDGa069t4c87BHRXvcy2By3YpOozORv9/QTMxAQFVOLg==}
|
resolution: {integrity: sha512-dnurqJdedbU8D1Ngudf10nXvc4BbVSe4ki9U2LUZoGMDGa069t4c87BHRXvcy2By3YpOozORv9/QTMxAQFVOLg==}
|
||||||
engines: {node: '>= 10.0'}
|
engines: {node: '>= 10.0'}
|
||||||
@ -3998,9 +3974,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
hey-listen@1.0.8:
|
|
||||||
resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
|
|
||||||
|
|
||||||
hookable@5.5.3:
|
hookable@5.5.3:
|
||||||
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
||||||
|
|
||||||
@ -4635,9 +4608,6 @@ packages:
|
|||||||
mockdate@3.0.5:
|
mockdate@3.0.5:
|
||||||
resolution: {integrity: sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==}
|
resolution: {integrity: sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==}
|
||||||
|
|
||||||
motion@10.18.0:
|
|
||||||
resolution: {integrity: sha512-MVAZZmwM/cp77BrNe1TxTMldxRPjwBNHheU5aPToqT4rJdZxLiADk58H+a0al5jKLxkB0OdgNq6DiVn11cjvIQ==}
|
|
||||||
|
|
||||||
mri@1.2.0:
|
mri@1.2.0:
|
||||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@ -4804,12 +4774,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
overlayscrollbars-react@0.5.6:
|
|
||||||
resolution: {integrity: sha512-E5To04bL5brn9GVCZ36SnfGanxa2I2MDkWoa4Cjo5wol7l+diAgi4DBc983V7l2nOk/OLJ6Feg4kySspQEGDBw==}
|
|
||||||
peerDependencies:
|
|
||||||
overlayscrollbars: ^2.0.0
|
|
||||||
react: '>=16.8.0'
|
|
||||||
|
|
||||||
overlayscrollbars@2.10.0:
|
overlayscrollbars@2.10.0:
|
||||||
resolution: {integrity: sha512-diNMeEafWTE0A4GJfwRpdBp2rE/BEvrhptBdBcDu8/UeytWcdCy9Td8tZWnztJeJ26f8/uHCWfPnPUC/dtgJdw==}
|
resolution: {integrity: sha512-diNMeEafWTE0A4GJfwRpdBp2rE/BEvrhptBdBcDu8/UeytWcdCy9Td8tZWnztJeJ26f8/uHCWfPnPUC/dtgJdw==}
|
||||||
|
|
||||||
@ -7569,41 +7533,6 @@ snapshots:
|
|||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@motionone/animation@10.18.0':
|
|
||||||
dependencies:
|
|
||||||
'@motionone/easing': 10.18.0
|
|
||||||
'@motionone/types': 10.17.1
|
|
||||||
'@motionone/utils': 10.18.0
|
|
||||||
tslib: 2.8.0
|
|
||||||
|
|
||||||
'@motionone/dom@10.18.0':
|
|
||||||
dependencies:
|
|
||||||
'@motionone/animation': 10.18.0
|
|
||||||
'@motionone/generators': 10.18.0
|
|
||||||
'@motionone/types': 10.17.1
|
|
||||||
'@motionone/utils': 10.18.0
|
|
||||||
hey-listen: 1.0.8
|
|
||||||
tslib: 2.8.0
|
|
||||||
|
|
||||||
'@motionone/easing@10.18.0':
|
|
||||||
dependencies:
|
|
||||||
'@motionone/utils': 10.18.0
|
|
||||||
tslib: 2.8.0
|
|
||||||
|
|
||||||
'@motionone/generators@10.18.0':
|
|
||||||
dependencies:
|
|
||||||
'@motionone/types': 10.17.1
|
|
||||||
'@motionone/utils': 10.18.0
|
|
||||||
tslib: 2.8.0
|
|
||||||
|
|
||||||
'@motionone/types@10.17.1': {}
|
|
||||||
|
|
||||||
'@motionone/utils@10.18.0':
|
|
||||||
dependencies:
|
|
||||||
'@motionone/types': 10.17.1
|
|
||||||
hey-listen: 1.0.8
|
|
||||||
tslib: 2.8.0
|
|
||||||
|
|
||||||
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
|
'@napi-rs/pinyin-android-arm-eabi@1.7.5':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@ -10427,8 +10356,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
hey-listen@1.0.8: {}
|
|
||||||
|
|
||||||
hookable@5.5.3: {}
|
hookable@5.5.3: {}
|
||||||
|
|
||||||
hosted-git-info@2.8.9: {}
|
hosted-git-info@2.8.9: {}
|
||||||
@ -11045,13 +10972,6 @@ snapshots:
|
|||||||
|
|
||||||
mockdate@3.0.5: {}
|
mockdate@3.0.5: {}
|
||||||
|
|
||||||
motion@10.18.0:
|
|
||||||
dependencies:
|
|
||||||
'@motionone/animation': 10.18.0
|
|
||||||
'@motionone/dom': 10.18.0
|
|
||||||
'@motionone/types': 10.17.1
|
|
||||||
'@motionone/utils': 10.18.0
|
|
||||||
|
|
||||||
mri@1.2.0: {}
|
mri@1.2.0: {}
|
||||||
|
|
||||||
mrmime@2.0.0: {}
|
mrmime@2.0.0: {}
|
||||||
@ -11303,11 +11223,6 @@ snapshots:
|
|||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
word-wrap: 1.2.5
|
word-wrap: 1.2.5
|
||||||
|
|
||||||
overlayscrollbars-react@0.5.6(overlayscrollbars@2.10.0)(react@18.3.1):
|
|
||||||
dependencies:
|
|
||||||
overlayscrollbars: 2.10.0
|
|
||||||
react: 18.3.1
|
|
||||||
|
|
||||||
overlayscrollbars@2.10.0: {}
|
overlayscrollbars@2.10.0: {}
|
||||||
|
|
||||||
p-limit@2.3.0:
|
p-limit@2.3.0:
|
||||||
|
@ -159,7 +159,7 @@ function NewsCard({ id, setHandleRef }: NewsCardProps) {
|
|||||||
options={{
|
options={{
|
||||||
overflow: { x: "hidden" },
|
overflow: { x: "hidden" },
|
||||||
}}
|
}}
|
||||||
defer={false}
|
defer
|
||||||
>
|
>
|
||||||
<div className={$("transition-opacity-500", isFetching && "op-20")}>
|
<div className={$("transition-opacity-500", isFetching && "op-20")}>
|
||||||
{!!data?.items?.length && (sources[id].type === "hottest" ? <NewsListHot items={data.items} /> : <NewsListTimeLine items={data.items} />)}
|
{!!data?.items?.length && (sources[id].type === "hottest" ? <NewsListHot items={data.items} /> : <NewsListTimeLine items={data.items} />)}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import type { UseOverlayScrollbarsParams } from "overlayscrollbars-react"
|
|
||||||
import { useOverlayScrollbars } from "overlayscrollbars-react"
|
|
||||||
import type { HTMLProps, PropsWithChildren } from "react"
|
import type { HTMLProps, PropsWithChildren } from "react"
|
||||||
import { defu } from "defu"
|
import { defu } from "defu"
|
||||||
import { useMount } from "react-use"
|
import { useMount } from "react-use"
|
||||||
|
import { useOverlayScrollbars } from "./useOverlayScrollbars"
|
||||||
|
import type { UseOverlayScrollbarsParams } from "./useOverlayScrollbars"
|
||||||
import { goToTopAtom } from "~/atoms"
|
import { goToTopAtom } from "~/atoms"
|
||||||
|
import "./style.css"
|
||||||
|
|
||||||
type Props = HTMLProps<HTMLDivElement> & UseOverlayScrollbarsParams
|
type Props = HTMLProps<HTMLDivElement> & UseOverlayScrollbarsParams
|
||||||
const defaultScrollbarParams: UseOverlayScrollbarsParams = {
|
const defaultScrollbarParams: UseOverlayScrollbarsParams = {
|
||||||
@ -15,7 +16,7 @@ const defaultScrollbarParams: UseOverlayScrollbarsParams = {
|
|||||||
defer: true,
|
defer: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OverlayScrollbar({ disabled, children, options, events, defer, ...props }: PropsWithChildren<Props>) {
|
export function OverlayScrollbar({ disabled, children, options, events, defer, className, ...props }: PropsWithChildren<Props>) {
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
const scrollbarParams = useMemo(() => defu<UseOverlayScrollbarsParams, Array<UseOverlayScrollbarsParams> >({
|
const scrollbarParams = useMemo(() => defu<UseOverlayScrollbarsParams, Array<UseOverlayScrollbarsParams> >({
|
||||||
options,
|
options,
|
||||||
@ -23,7 +24,7 @@ export function OverlayScrollbar({ disabled, children, options, events, defer, .
|
|||||||
defer,
|
defer,
|
||||||
}, defaultScrollbarParams), [options, events, defer])
|
}, defaultScrollbarParams), [options, events, defer])
|
||||||
|
|
||||||
const [initialize] = useOverlayScrollbars(scrollbarParams)
|
const [initialize, instance] = useOverlayScrollbars(scrollbarParams)
|
||||||
|
|
||||||
useMount(() => {
|
useMount(() => {
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
@ -37,15 +38,25 @@ export function OverlayScrollbar({ disabled, children, options, events, defer, .
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
if (instance && instance?.state().destroyed) {
|
||||||
|
ref.current.classList.remove("scrollbar-hidden")
|
||||||
|
} else {
|
||||||
|
ref.current.classList.add("scrollbar-hidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [instance])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} {...props}>
|
<div ref={ref} {...props} className={$("overflow-auto scrollbar-hidden", className)}>
|
||||||
{/* 只能有一个 element */}
|
{/* 只能有一个 element */}
|
||||||
<div>{children}</div>
|
<div>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren<HTMLProps<HTMLDivElement>>) {
|
export function GlobalOverlayScrollbar({ children, className, ...props }: PropsWithChildren<HTMLProps<HTMLDivElement>>) {
|
||||||
const ref = useRef<HTMLDivElement>(null)
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
const lastTrigger = useRef(0)
|
const lastTrigger = useRef(0)
|
||||||
const timer = useRef<any>()
|
const timer = useRef<any>()
|
||||||
@ -67,7 +78,7 @@ export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, [setGoToTop])
|
}, [setGoToTop])
|
||||||
const [initialize] = useOverlayScrollbars({
|
const [initialize, instance] = useOverlayScrollbars({
|
||||||
options: {
|
options: {
|
||||||
scrollbars: {
|
scrollbars: {
|
||||||
autoHide: "scroll",
|
autoHide: "scroll",
|
||||||
@ -76,7 +87,7 @@ export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
|
|||||||
events: {
|
events: {
|
||||||
scroll: (_, e) => onScroll(e),
|
scroll: (_, e) => onScroll(e),
|
||||||
},
|
},
|
||||||
defer: false,
|
defer: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
useMount(() => {
|
useMount(() => {
|
||||||
@ -95,8 +106,18 @@ export function GlobalOverlayScrollbar({ children, ...props }: PropsWithChildren
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
if (instance && instance?.state().destroyed) {
|
||||||
|
ref.current.classList.remove("scrollbar-hidden")
|
||||||
|
} else {
|
||||||
|
ref.current?.classList.add("scrollbar-hidden")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [instance])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={ref} {...props}>
|
<div ref={ref} {...props} className={$("overflow-auto scrollbar-hidden", className)}>
|
||||||
<div>{children}</div>
|
<div>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
12
src/components/common/overlay-scrollbar/style.css
Normal file
12
src/components/common/overlay-scrollbar/style.css
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 8px;
|
||||||
|
-webkit-border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-hidden {
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
.scrollbar-hidden::-webkit-scrollbar {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
152
src/components/common/overlay-scrollbar/useOverlayScrollbars.ts
Normal file
152
src/components/common/overlay-scrollbar/useOverlayScrollbars.ts
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
import type { ComponentPropsWithoutRef, ElementRef, ElementType, ForwardedRef } from "react"
|
||||||
|
import { useEffect, useMemo, useRef } from "react"
|
||||||
|
import { OverlayScrollbars } from "overlayscrollbars"
|
||||||
|
import type { EventListeners, InitializationTarget, PartialOptions } from "overlayscrollbars"
|
||||||
|
|
||||||
|
type OverlayScrollbarsComponentBaseProps<T extends ElementType = "div"> =
|
||||||
|
ComponentPropsWithoutRef<T> & {
|
||||||
|
/** Tag of the root element. */
|
||||||
|
element?: T
|
||||||
|
/** OverlayScrollbars options. */
|
||||||
|
options?: PartialOptions | false | null
|
||||||
|
/** OverlayScrollbars events. */
|
||||||
|
events?: EventListeners | false | null
|
||||||
|
/** Whether to defer the initialization to a point in time when the browser is idle. (or to the next frame if `window.requestIdleCallback` is not supported) */
|
||||||
|
defer?: boolean | IdleRequestOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type OverlayScrollbarsComponentProps<T extends ElementType = "div"> =
|
||||||
|
OverlayScrollbarsComponentBaseProps<T> & {
|
||||||
|
ref?: ForwardedRef<OverlayScrollbarsComponentRef<T>>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OverlayScrollbarsComponentRef<T extends ElementType = "div"> {
|
||||||
|
/** Returns the OverlayScrollbars instance or null if not initialized. */
|
||||||
|
osInstance: () => OverlayScrollbars | null
|
||||||
|
/** Returns the root element. */
|
||||||
|
getElement: () => ElementRef<T> | null
|
||||||
|
}
|
||||||
|
|
||||||
|
type Defer = [
|
||||||
|
requestDefer: (callback: () => any, options?: OverlayScrollbarsComponentProps["defer"]) => void,
|
||||||
|
cancelDefer: () => void,
|
||||||
|
]
|
||||||
|
|
||||||
|
export interface UseOverlayScrollbarsParams {
|
||||||
|
/** OverlayScrollbars options. */
|
||||||
|
options?: OverlayScrollbarsComponentProps["options"]
|
||||||
|
/** OverlayScrollbars events. */
|
||||||
|
events?: OverlayScrollbarsComponentProps["events"]
|
||||||
|
/** Whether to defer the initialization to a point in time when the browser is idle. (or to the next frame if `window.requestIdleCallback` is not supported) */
|
||||||
|
defer?: OverlayScrollbarsComponentProps["defer"]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UseOverlayScrollbarsInitialization = (target: InitializationTarget) => void
|
||||||
|
|
||||||
|
export type UseOverlayScrollbarsInstance = () => ReturnType<
|
||||||
|
OverlayScrollbarsComponentRef["osInstance"]
|
||||||
|
>
|
||||||
|
|
||||||
|
function createDefer(): Defer {
|
||||||
|
let idleId: number
|
||||||
|
let rafId: number
|
||||||
|
const wnd = window
|
||||||
|
const idleSupported = typeof wnd.requestIdleCallback === "function"
|
||||||
|
const rAF = wnd.requestAnimationFrame
|
||||||
|
const cAF = wnd.cancelAnimationFrame
|
||||||
|
const rIdle = idleSupported ? wnd.requestIdleCallback : rAF
|
||||||
|
const cIdle = idleSupported ? wnd.cancelIdleCallback : cAF
|
||||||
|
const clear = () => {
|
||||||
|
cIdle(idleId)
|
||||||
|
cAF(rafId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
(callback, options) => {
|
||||||
|
clear()
|
||||||
|
idleId = rIdle(
|
||||||
|
idleSupported
|
||||||
|
? () => {
|
||||||
|
clear()
|
||||||
|
// inside idle its best practice to use rAF to change DOM for best performance
|
||||||
|
rafId = rAF(callback)
|
||||||
|
}
|
||||||
|
: callback,
|
||||||
|
typeof options === "object" ? options : { timeout: 2233 },
|
||||||
|
)
|
||||||
|
},
|
||||||
|
clear,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook for advanced usage of OverlayScrollbars. (When the OverlayScrollbarsComponent is not enough)
|
||||||
|
* @param params Parameters for customization.
|
||||||
|
* @returns A tuple with two values:
|
||||||
|
* The first value is the initialization function, it takes one argument which is the `InitializationTarget`.
|
||||||
|
* The second value is a function which returns the current OverlayScrollbars instance or `null` if not initialized.
|
||||||
|
*/
|
||||||
|
export function useOverlayScrollbars(params?: UseOverlayScrollbarsParams): [UseOverlayScrollbarsInitialization, OverlayScrollbars | null ] {
|
||||||
|
const { options, events, defer } = params || {}
|
||||||
|
const [requestDefer, cancelDefer] = useMemo<Defer>(createDefer, [])
|
||||||
|
// const instanceRef = useRef<ReturnType<UseOverlayScrollbarsInstance>>(null)
|
||||||
|
const [instance, setInstance] = useState<ReturnType<UseOverlayScrollbarsInstance>>(null)
|
||||||
|
const deferRef = useRef(defer)
|
||||||
|
const optionsRef = useRef(options)
|
||||||
|
const eventsRef = useRef(events)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
deferRef.current = defer
|
||||||
|
}, [defer])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
optionsRef.current = options
|
||||||
|
|
||||||
|
if (OverlayScrollbars.valid(instance)) {
|
||||||
|
instance.options(options || {}, true)
|
||||||
|
}
|
||||||
|
}, [options, instance])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
eventsRef.current = events
|
||||||
|
|
||||||
|
if (OverlayScrollbars.valid(instance)) {
|
||||||
|
instance.on(events || {}, true)
|
||||||
|
}
|
||||||
|
}, [events, instance])
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => () => {
|
||||||
|
cancelDefer()
|
||||||
|
instance?.destroy()
|
||||||
|
},
|
||||||
|
[cancelDefer, instance, setInstance],
|
||||||
|
)
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => [
|
||||||
|
(target) => {
|
||||||
|
// if already initialized do nothing
|
||||||
|
const presentInstance = instance
|
||||||
|
if (OverlayScrollbars.valid(presentInstance)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const currDefer = deferRef.current
|
||||||
|
const currOptions = optionsRef.current || {}
|
||||||
|
const currEvents = eventsRef.current || {}
|
||||||
|
const init = () => {
|
||||||
|
setInstance(OverlayScrollbars(target, currOptions, currEvents))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currDefer) {
|
||||||
|
requestDefer(init, currDefer)
|
||||||
|
} else {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
instance,
|
||||||
|
],
|
||||||
|
[instance, requestDefer],
|
||||||
|
)
|
||||||
|
}
|
@ -86,7 +86,7 @@ export function SearchBar() {
|
|||||||
placeholder="搜索你想要的"
|
placeholder="搜索你想要的"
|
||||||
/>
|
/>
|
||||||
<div className="md:flex pt-2">
|
<div className="md:flex pt-2">
|
||||||
<OverlayScrollbar defer={false} className="overflow-y-auto md:min-w-275px">
|
<OverlayScrollbar defer className="overflow-y-auto md:min-w-275px">
|
||||||
<Command.List>
|
<Command.List>
|
||||||
<Command.Empty> 没有找到,可以前往 Github 提 issue </Command.Empty>
|
<Command.Empty> 没有找到,可以前往 Github 提 issue </Command.Empty>
|
||||||
{
|
{
|
||||||
|
@ -4,13 +4,14 @@ import react from "@vitejs/plugin-react-swc"
|
|||||||
import { TanStackRouterVite } from "@tanstack/router-plugin/vite"
|
import { TanStackRouterVite } from "@tanstack/router-plugin/vite"
|
||||||
import unocss from "unocss/vite"
|
import unocss from "unocss/vite"
|
||||||
import unimport from "unimport/unplugin"
|
import unimport from "unimport/unplugin"
|
||||||
|
import dotenv from "dotenv"
|
||||||
import nitro from "./nitro.config"
|
import nitro from "./nitro.config"
|
||||||
import { projectDir } from "./shared/dir"
|
import { projectDir } from "./shared/dir"
|
||||||
import pwa from "./pwa.config"
|
import pwa from "./pwa.config"
|
||||||
|
|
||||||
// dotenv.config({
|
dotenv.config({
|
||||||
// path: join(projectDir, ".env.server"),
|
path: join(projectDir, ".env.server"),
|
||||||
// })
|
})
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user