mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-17 23:00:37 +03:00
overlayscrollbars-react v0.5.0
This commit is contained in:
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.5.0
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- `OverlayScrollbarsComponent` accepts now the `defer` property
|
||||||
|
- `useOverlayScrollbars` params accept now the `defer` key
|
||||||
|
- `useOverlayScrollbars` will now always try to destroy the instance if the component unmounts.
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- Because initialization can be deferred now, the `initialize` function of the `useOverlayScrollbars` hook isn't returning the instance anymore. Use the `instance` function of the `useOverlayScrollbars` hook instead.
|
||||||
|
|
||||||
## 0.4.0
|
## 0.4.0
|
||||||
|
|
||||||
Depends on `OverlayScrollbars` version `^2.0.0` and `React` version `>=16.8.0`.
|
Depends on `OverlayScrollbars` version `^2.0.0` and `React` version `>=16.8.0`.
|
||||||
@@ -7,8 +19,8 @@ The component was rewritten using `hooks`. ([#218](https://github.com/KingSora/O
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- `OverlayScrollbarsComponent` has now the `events` property
|
- `OverlayScrollbarsComponent` accepts now the `events` property
|
||||||
- `OverlayScrollbarsComponent` has now the `element` property
|
- `OverlayScrollbarsComponent` accepts now the `element` property
|
||||||
- The `useOverlayScrollbars` hook was added for advanced usage
|
- The `useOverlayScrollbars` hook was added for advanced usage
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
|||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
<OverlayScrollbarsComponent>
|
<OverlayScrollbarsComponent defer>
|
||||||
example content
|
example content
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
```
|
```
|
||||||
@@ -70,12 +70,16 @@ Additionally it has three optional properties: `element`, `options` and `events`
|
|||||||
- `element`: accepts a `string` which represents the tag of the root element.
|
- `element`: accepts a `string` which represents the tag of the root element.
|
||||||
- `options`: accepts an `object` which represents the OverlayScrollbars options.
|
- `options`: accepts an `object` which represents the OverlayScrollbars options.
|
||||||
- `events`: accepts an `object` which represents the OverlayScrollbars events.
|
- `events`: accepts an `object` which represents the OverlayScrollbars events.
|
||||||
|
- `defer`: accepts an `boolean` or `object`. Defers the initialization to a point in time when the browser is idle.
|
||||||
|
|
||||||
> __Note__: None of the properties has to be memoized.
|
> __Note__: None of the properties has to be memoized.
|
||||||
|
|
||||||
|
> __Note__: Its **highly recommended** to use the `defer` option whenever possible to defer the initialization of the component to a browser's idle period.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
// example usage
|
// example usage
|
||||||
<OverlayScrollbarsComponent
|
<OverlayScrollbarsComponent
|
||||||
|
defer
|
||||||
element="span"
|
element="span"
|
||||||
options={{ scrollbars: { autoHide: 'scroll' } }}
|
options={{ scrollbars: { autoHide: 'scroll' } }}
|
||||||
events={{ scroll: () => { /* ... */ } }}
|
events={{ scroll: () => { /* ... */ } }}
|
||||||
@@ -100,11 +104,10 @@ import { useOverlayScrollbars } from "overlayscrollbars-react";
|
|||||||
// example usage
|
// example usage
|
||||||
const Component = () => {
|
const Component = () => {
|
||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
const [initialize, instance] = useOverlayScrollbars({ options, events });
|
const [initialize, instance] = useOverlayScrollbars({ options, events, defer });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const osInstance = initialize(ref.current);
|
initialize(ref.current);
|
||||||
return () => osInstance.destroy();
|
|
||||||
}, [initialize]);
|
}, [initialize]);
|
||||||
|
|
||||||
return <div ref={ref} />
|
return <div ref={ref} />
|
||||||
@@ -113,6 +116,8 @@ const Component = () => {
|
|||||||
|
|
||||||
The hook is for advanced usage and lets you control the whole initialization process. This is useful if you want to integrate it with other plugins such as `react-window` or `react-virtualized`.
|
The hook is for advanced usage and lets you control the whole initialization process. This is useful if you want to integrate it with other plugins such as `react-window` or `react-virtualized`.
|
||||||
|
|
||||||
|
The hook will destroy the instance automatically if the component unmounts.
|
||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
Parameters are optional and similar to the `OverlayScrollbarsComponent`.
|
Parameters are optional and similar to the `OverlayScrollbarsComponent`.
|
||||||
@@ -120,12 +125,13 @@ Its an `object` with two optional properties:
|
|||||||
|
|
||||||
- `options`: accepts an `object` which represents the OverlayScrollbars options.
|
- `options`: accepts an `object` which represents the OverlayScrollbars options.
|
||||||
- `events`: accepts an `object` which represents the OverlayScrollbars events.
|
- `events`: accepts an `object` which represents the OverlayScrollbars events.
|
||||||
|
- `defer`: accepts an `boolean` or `object`. Defers the initialization to a point in time when the browser is idle.
|
||||||
|
|
||||||
### Return
|
### Return
|
||||||
|
|
||||||
The `useOverlayScrollbars` hook returns a `tuple` with two values:
|
The `useOverlayScrollbars` hook returns a `tuple` with two values:
|
||||||
|
|
||||||
- The first value is the `initialization` function, it takes one argument which is the `InitializationTarget` and returns the OverlayScrollbars instance.
|
- 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.
|
- The second value is a function which returns the current OverlayScrollbars instance or `null` if not initialized.
|
||||||
|
|
||||||
> __Note__: The identity of both functions is stable and won't change, thus they can safely be used in any dependency array.
|
> __Note__: The identity of both functions is stable and won't change, thus they can safely be used in any dependency array.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "overlayscrollbars-react",
|
"name": "overlayscrollbars-react",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.4.0",
|
"version": "0.5.0",
|
||||||
"description": "OverlayScrollbars for React.",
|
"description": "OverlayScrollbars for React.",
|
||||||
"author": "Rene Haas | KingSora",
|
"author": "Rene Haas | KingSora",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export type OverlayScrollbarsComponentProps<T extends keyof JSX.IntrinsicElement
|
|||||||
options?: PartialOptions | false | null;
|
options?: PartialOptions | false | null;
|
||||||
/** OverlayScrollbars events. */
|
/** OverlayScrollbars events. */
|
||||||
events?: EventListeners | false | null;
|
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 unsupported) */
|
||||||
|
defer?: boolean | IdleRequestOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface OverlayScrollbarsComponentRef<T extends keyof JSX.IntrinsicElements = 'div'> {
|
export interface OverlayScrollbarsComponentRef<T extends keyof JSX.IntrinsicElements = 'div'> {
|
||||||
@@ -25,26 +27,25 @@ const OverlayScrollbarsComponent = <T extends keyof JSX.IntrinsicElements>(
|
|||||||
props: OverlayScrollbarsComponentProps<T>,
|
props: OverlayScrollbarsComponentProps<T>,
|
||||||
ref: ForwardedRef<OverlayScrollbarsComponentRef<T>>
|
ref: ForwardedRef<OverlayScrollbarsComponentRef<T>>
|
||||||
) => {
|
) => {
|
||||||
const { element = 'div', options, events, children, ...other } = props;
|
const { element = 'div', options, events, defer, children, ...other } = props;
|
||||||
const Tag = element;
|
const Tag = element;
|
||||||
const elementRef = useRef<ElementRef<T>>(null);
|
const elementRef = useRef<ElementRef<T>>(null);
|
||||||
const childrenRef = useRef<HTMLDivElement>(null);
|
const childrenRef = useRef<HTMLDivElement>(null);
|
||||||
const [initialize, osInstance] = useOverlayScrollbars({ options, events });
|
const [initialize, osInstance] = useOverlayScrollbars({ options, events, defer });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { current: elm } = elementRef;
|
const { current: elm } = elementRef;
|
||||||
const { current: childrenElm } = childrenRef;
|
const { current: childrenElm } = childrenRef;
|
||||||
if (elm && childrenElm) {
|
if (elm && childrenElm) {
|
||||||
const instance = initialize({
|
initialize({
|
||||||
target: elm as any,
|
target: elm as any,
|
||||||
elements: {
|
elements: {
|
||||||
viewport: childrenElm,
|
viewport: childrenElm,
|
||||||
content: childrenElm,
|
content: childrenElm,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => instance.destroy();
|
|
||||||
}
|
}
|
||||||
|
return () => osInstance()?.destroy();
|
||||||
}, [initialize, element]);
|
}, [initialize, element]);
|
||||||
|
|
||||||
useImperativeHandle(
|
useImperativeHandle(
|
||||||
|
|||||||
@@ -6,36 +6,88 @@ import type {
|
|||||||
OverlayScrollbarsComponentRef,
|
OverlayScrollbarsComponentRef,
|
||||||
} from './OverlayScrollbarsComponent';
|
} from './OverlayScrollbarsComponent';
|
||||||
|
|
||||||
|
type Defer = [
|
||||||
|
requestDefer: (callback: () => any, options?: OverlayScrollbarsComponentProps['defer']) => void,
|
||||||
|
cancelDefer: () => void
|
||||||
|
];
|
||||||
|
|
||||||
export interface UseOverlayScrollbarsParams {
|
export interface UseOverlayScrollbarsParams {
|
||||||
/** OverlayScrollbars options. */
|
/** OverlayScrollbars options. */
|
||||||
options?: OverlayScrollbarsComponentProps['options'];
|
options?: OverlayScrollbarsComponentProps['options'];
|
||||||
/** OverlayScrollbars events. */
|
/** OverlayScrollbars events. */
|
||||||
events?: OverlayScrollbarsComponentProps['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 unsupported) */
|
||||||
|
defer?: OverlayScrollbarsComponentProps['defer'];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UseOverlayScrollbarsInitialization = (
|
export type UseOverlayScrollbarsInitialization = (target: InitializationTarget) => void;
|
||||||
target: InitializationTarget
|
|
||||||
) => OverlayScrollbars;
|
|
||||||
|
|
||||||
export type UseOverlayScrollbarsInstance = () => ReturnType<
|
export type UseOverlayScrollbarsInstance = () => ReturnType<
|
||||||
OverlayScrollbarsComponentRef['osInstance']
|
OverlayScrollbarsComponentRef['osInstance']
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
const createDefer = (): Defer => {
|
||||||
|
/* c8 ignore start */
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
// mock ssr calls with "noop"
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
const noop = () => {};
|
||||||
|
return [noop, noop];
|
||||||
|
}
|
||||||
|
/* c8 ignore end */
|
||||||
|
|
||||||
|
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: 1500 }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
clear,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for advanced usage of OverlayScrollbars. (When the OverlayScrollbarsComponent is not enough)
|
* Hook for advanced usage of OverlayScrollbars. (When the OverlayScrollbarsComponent is not enough)
|
||||||
* @param params Parameters for customization.
|
* @param params Parameters for customization.
|
||||||
* @returns A tuple with two values:
|
* @returns A tuple with two values:
|
||||||
* The first value is the initialization function, it takes one argument which is the `InitializationTarget` and returns the OverlayScrollbars instance.
|
* 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.
|
* The second value is a function which returns the current OverlayScrollbars instance or `null` if not initialized.
|
||||||
*/
|
*/
|
||||||
export const useOverlayScrollbars = (
|
export const useOverlayScrollbars = (
|
||||||
params?: UseOverlayScrollbarsParams
|
params?: UseOverlayScrollbarsParams
|
||||||
): [UseOverlayScrollbarsInitialization, UseOverlayScrollbarsInstance] => {
|
): [UseOverlayScrollbarsInitialization, UseOverlayScrollbarsInstance] => {
|
||||||
const { options, events } = params || {};
|
const { options, events, defer } = params || {};
|
||||||
|
const [requestDefer, cancelDefer] = useMemo<Defer>(createDefer, []);
|
||||||
const instanceRef = useRef<ReturnType<UseOverlayScrollbarsInstance>>(null);
|
const instanceRef = useRef<ReturnType<UseOverlayScrollbarsInstance>>(null);
|
||||||
|
const deferRef = useRef(defer);
|
||||||
const optionsRef = useRef(options);
|
const optionsRef = useRef(options);
|
||||||
const eventsRef = useRef(events);
|
const eventsRef = useRef(events);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
deferRef.current = defer;
|
||||||
|
}, [defer]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { current: instance } = instanceRef;
|
const { current: instance } = instanceRef;
|
||||||
|
|
||||||
@@ -56,24 +108,34 @@ export const useOverlayScrollbars = (
|
|||||||
}
|
}
|
||||||
}, [events]);
|
}, [events]);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => () => {
|
||||||
|
cancelDefer();
|
||||||
|
instanceRef.current?.destroy();
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return useMemo<[UseOverlayScrollbarsInitialization, UseOverlayScrollbarsInstance]>(
|
return useMemo<[UseOverlayScrollbarsInitialization, UseOverlayScrollbarsInstance]>(
|
||||||
() => [
|
() => [
|
||||||
(target: InitializationTarget): OverlayScrollbars => {
|
(target) => {
|
||||||
// if already initialized return the current instance
|
// if already initialized do nothing
|
||||||
const presentInstance = instanceRef.current;
|
const presentInstance = instanceRef.current;
|
||||||
if (OverlayScrollbars.valid(presentInstance)) {
|
if (OverlayScrollbars.valid(presentInstance)) {
|
||||||
return presentInstance;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currDefer = deferRef.current;
|
||||||
const currOptions = optionsRef.current || {};
|
const currOptions = optionsRef.current || {};
|
||||||
const currEvents = eventsRef.current || {};
|
const currEvents = eventsRef.current || {};
|
||||||
const osInstance = (instanceRef.current = OverlayScrollbars(
|
const init = () =>
|
||||||
target,
|
(instanceRef.current = OverlayScrollbars(target, currOptions, currEvents));
|
||||||
currOptions,
|
|
||||||
currEvents
|
|
||||||
));
|
|
||||||
|
|
||||||
return osInstance;
|
if (currDefer) {
|
||||||
|
requestDefer(init, currDefer);
|
||||||
|
} else {
|
||||||
|
init();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
() => instanceRef.current,
|
() => instanceRef.current,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { describe, test, afterEach, expect, vitest } from 'vitest';
|
import { describe, test, afterEach, expect, vitest, vi } from 'vitest';
|
||||||
import { render, screen, cleanup } from '@testing-library/react';
|
import { render, screen, cleanup } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
import { OverlayScrollbars } from 'overlayscrollbars';
|
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||||
@@ -7,6 +7,15 @@ import { OverlayScrollbarsComponent } from '~/overlayscrollbars-react';
|
|||||||
import type { RefObject } from 'react';
|
import type { RefObject } from 'react';
|
||||||
import type { OverlayScrollbarsComponentRef } from '~/overlayscrollbars-react';
|
import type { OverlayScrollbarsComponentRef } from '~/overlayscrollbars-react';
|
||||||
|
|
||||||
|
vi.useFakeTimers({
|
||||||
|
toFake: [
|
||||||
|
'requestAnimationFrame',
|
||||||
|
'cancelAnimationFrame',
|
||||||
|
'requestIdleCallback',
|
||||||
|
'cancelIdleCallback',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
describe('OverlayScrollbarsComponent', () => {
|
describe('OverlayScrollbarsComponent', () => {
|
||||||
afterEach(() => cleanup());
|
afterEach(() => cleanup());
|
||||||
|
|
||||||
@@ -118,6 +127,44 @@ describe('OverlayScrollbarsComponent', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('deferred initialization', () => {
|
||||||
|
test('basic defer', () => {
|
||||||
|
const { container } = render(<OverlayScrollbarsComponent defer />);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(container.firstElementChild! as HTMLElement)).toBeUndefined();
|
||||||
|
|
||||||
|
vi.advanceTimersByTime(2000);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(container.firstElementChild! as HTMLElement)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('options defer', () => {
|
||||||
|
const { container } = render(<OverlayScrollbarsComponent defer={{ timeout: 0 }} />);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(container.firstElementChild! as HTMLElement)).toBeUndefined();
|
||||||
|
|
||||||
|
vi.advanceTimersByTime(2000);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(container.firstElementChild! as HTMLElement)).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('defer with unsupported Idle', () => {
|
||||||
|
const original = window.requestIdleCallback;
|
||||||
|
// @ts-ignore
|
||||||
|
window.requestIdleCallback = undefined;
|
||||||
|
|
||||||
|
const { container } = render(<OverlayScrollbarsComponent defer />);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(container.firstElementChild! as HTMLElement)).toBeUndefined();
|
||||||
|
|
||||||
|
vi.advanceTimersByTime(2000);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(container.firstElementChild! as HTMLElement)).toBeDefined();
|
||||||
|
|
||||||
|
window.requestIdleCallback = original;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('ref', () => {
|
test('ref', () => {
|
||||||
const ref: RefObject<OverlayScrollbarsComponentRef> = { current: null };
|
const ref: RefObject<OverlayScrollbarsComponentRef> = { current: null };
|
||||||
const { container } = render(<OverlayScrollbarsComponent ref={ref} />);
|
const { container } = render(<OverlayScrollbarsComponent ref={ref} />);
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { useRef } from 'react';
|
|||||||
import { describe, test, afterEach, expect } from 'vitest';
|
import { describe, test, afterEach, expect } from 'vitest';
|
||||||
import { render, screen, cleanup } from '@testing-library/react';
|
import { render, screen, cleanup } from '@testing-library/react';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { OverlayScrollbars } from 'overlayscrollbars';
|
||||||
import { useOverlayScrollbars } from '~/overlayscrollbars-react';
|
import { useOverlayScrollbars } from '~/overlayscrollbars-react';
|
||||||
import type { OverlayScrollbars } from 'overlayscrollbars';
|
|
||||||
|
|
||||||
describe('useOverlayScrollbars', () => {
|
describe('useOverlayScrollbars', () => {
|
||||||
afterEach(() => cleanup());
|
afterEach(() => cleanup());
|
||||||
@@ -13,25 +13,22 @@ describe('useOverlayScrollbars', () => {
|
|||||||
const instanceRef = useRef<OverlayScrollbars | null>(null);
|
const instanceRef = useRef<OverlayScrollbars | null>(null);
|
||||||
const [initialize, instance] = useOverlayScrollbars();
|
const [initialize, instance] = useOverlayScrollbars();
|
||||||
return (
|
return (
|
||||||
<>
|
<button
|
||||||
<button
|
onClick={(event) => {
|
||||||
onClick={(event) => {
|
initialize(event.target as HTMLElement);
|
||||||
const osInstance = initialize(event.target as HTMLElement);
|
if (instanceRef.current) {
|
||||||
if (instanceRef.current) {
|
|
||||||
expect(instanceRef.current).toBe(osInstance);
|
|
||||||
expect(instanceRef.current).toBe(instance());
|
|
||||||
}
|
|
||||||
instanceRef.current = osInstance;
|
|
||||||
expect(instanceRef.current).toBe(instance());
|
expect(instanceRef.current).toBe(instance());
|
||||||
}}
|
}
|
||||||
>
|
instanceRef.current = instance();
|
||||||
initialize
|
expect(instanceRef.current).toBe(instance());
|
||||||
</button>
|
}}
|
||||||
</>
|
>
|
||||||
|
initialize
|
||||||
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
render(<Test />);
|
const { unmount } = render(<Test />);
|
||||||
|
|
||||||
const initializeBtn = screen.getByRole('button');
|
const initializeBtn = screen.getByRole('button');
|
||||||
userEvent.click(initializeBtn);
|
userEvent.click(initializeBtn);
|
||||||
@@ -41,5 +38,11 @@ describe('useOverlayScrollbars', () => {
|
|||||||
userEvent.click(initializeBtn);
|
userEvent.click(initializeBtn);
|
||||||
|
|
||||||
expect(snapshot).toBe(initializeBtn.innerHTML);
|
expect(snapshot).toBe(initializeBtn.innerHTML);
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(initializeBtn)).toBeDefined();
|
||||||
|
|
||||||
|
unmount();
|
||||||
|
|
||||||
|
expect(OverlayScrollbars(initializeBtn)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type {
|
|||||||
import type { InitializationTarget } from 'overlayscrollbars';
|
import type { InitializationTarget } from 'overlayscrollbars';
|
||||||
|
|
||||||
type Defer = [
|
type Defer = [
|
||||||
request: (callback: () => any, options?: IdleRequestOptions) => void,
|
defer: (callback: () => any, options?: IdleRequestOptions) => void,
|
||||||
clear: () => void
|
clear: () => void
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ export const useOverlayScrollbarsIdle = (
|
|||||||
(...args: Parameters<UseOverlayScrollbarsInitialization>) => void,
|
(...args: Parameters<UseOverlayScrollbarsInitialization>) => void,
|
||||||
UseOverlayScrollbarsInstance
|
UseOverlayScrollbarsInstance
|
||||||
] => {
|
] => {
|
||||||
const [requestIdle, clearIdle] = useMemo<Defer>(() => createDefer(true), []);
|
const [deferIdle, clearIdle] = useMemo<Defer>(() => createDefer(true), []);
|
||||||
const [requestRAF, clearRAF] = useMemo<Defer>(() => createDefer(), []);
|
const [deferRAF, clearRAF] = useMemo<Defer>(() => createDefer(), []);
|
||||||
const [initialize, instance] = useOverlayScrollbars(params);
|
const [initialize, instance] = useOverlayScrollbars(params);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -50,9 +50,9 @@ export const useOverlayScrollbarsIdle = (
|
|||||||
return useMemo(
|
return useMemo(
|
||||||
() => [
|
() => [
|
||||||
(target: InitializationTarget) => {
|
(target: InitializationTarget) => {
|
||||||
requestIdle(
|
deferIdle(
|
||||||
() => {
|
() => {
|
||||||
requestRAF(() => {
|
deferRAF(() => {
|
||||||
initialize(target);
|
initialize(target);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user