mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-25 08:20:36 +03:00
improve react initialization and api
This commit is contained in:
@@ -11,24 +11,36 @@ export type OverlayScrollbarsComponentProps<T extends keyof JSX.IntrinsicElement
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface OverlayScrollbarsComponentRef<T extends keyof JSX.IntrinsicElements = 'div'> {
|
export interface OverlayScrollbarsComponentRef<T extends keyof JSX.IntrinsicElements = 'div'> {
|
||||||
osInstance(): OverlayScrollbars | null;
|
instance(): OverlayScrollbars | null;
|
||||||
osTarget(): ElementRef<T> | null;
|
target(): ElementRef<T> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const OverlayScrollbarsComponent = <T extends keyof JSX.IntrinsicElements>(
|
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, ...other } = props;
|
const { element = 'div', options, events, children, ...other } = props;
|
||||||
const Tag = element;
|
const Tag = element;
|
||||||
|
|
||||||
const osTargetRef = useRef<ElementRef<T>>(null);
|
const osTargetRef = useRef<ElementRef<T>>(null);
|
||||||
|
const osChildrenRef = useRef<HTMLDivElement>(null);
|
||||||
const osInstanceRef = useRef<OverlayScrollbars | null>(null);
|
const osInstanceRef = useRef<OverlayScrollbars | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { current: target } = osTargetRef;
|
const { current: targetElm } = osTargetRef;
|
||||||
if (target) {
|
const { current: childrenElm } = osChildrenRef;
|
||||||
const instance = OverlayScrollbars(target as any, options || {}, events);
|
if (targetElm && childrenElm) {
|
||||||
|
const instance = OverlayScrollbars(
|
||||||
|
{
|
||||||
|
target: targetElm as any,
|
||||||
|
elements: {
|
||||||
|
viewport: childrenElm,
|
||||||
|
content: childrenElm,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
options || {},
|
||||||
|
events
|
||||||
|
);
|
||||||
osInstanceRef.current = instance;
|
osInstanceRef.current = instance;
|
||||||
|
|
||||||
return () => instance.destroy();
|
return () => instance.destroy();
|
||||||
@@ -53,15 +65,19 @@ const OverlayScrollbarsComponent = <T extends keyof JSX.IntrinsicElements>(
|
|||||||
ref,
|
ref,
|
||||||
() => {
|
() => {
|
||||||
return {
|
return {
|
||||||
osInstance: () => osInstanceRef.current,
|
instance: () => osInstanceRef.current,
|
||||||
osTarget: () => osTargetRef.current,
|
target: () => osTargetRef.current,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return <Tag data-overlayscrollbars="" {...other} ref={osTargetRef} />;
|
<Tag data-overlayscrollbars="" {...other} ref={osTargetRef}>
|
||||||
|
<div ref={osChildrenRef}>{children}</div>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const OverlayScrollbarsComponentForwardedRef = forwardRef(OverlayScrollbarsComponent) as <
|
const OverlayScrollbarsComponentForwardedRef = forwardRef(OverlayScrollbarsComponent) as <
|
||||||
|
|||||||
@@ -61,11 +61,11 @@ describe('OverlayScrollbarsComponent', () => {
|
|||||||
const ref: RefObject<OverlayScrollbarsComponentRef> = { current: null };
|
const ref: RefObject<OverlayScrollbarsComponentRef> = { current: null };
|
||||||
const { container } = render(<OverlayScrollbarsComponent ref={ref} />);
|
const { container } = render(<OverlayScrollbarsComponent ref={ref} />);
|
||||||
|
|
||||||
const { osInstance, osTarget } = ref.current!;
|
const { instance, target } = ref.current!;
|
||||||
expect(osInstance).toBeTypeOf('function');
|
expect(instance).toBeTypeOf('function');
|
||||||
expect(osTarget).toBeTypeOf('function');
|
expect(target).toBeTypeOf('function');
|
||||||
expect(OverlayScrollbars.valid(osInstance())).toBe(true);
|
expect(OverlayScrollbars.valid(instance())).toBe(true);
|
||||||
expect(osTarget()).toBe(container.firstElementChild);
|
expect(target()).toBe(container.firstElementChild);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('options', () => {
|
test('options', () => {
|
||||||
@@ -77,13 +77,13 @@ describe('OverlayScrollbarsComponent', () => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const opts = ref.current!.osInstance()!.options();
|
const opts = ref.current!.instance()!.options();
|
||||||
expect(opts.paddingAbsolute).toBe(true);
|
expect(opts.paddingAbsolute).toBe(true);
|
||||||
expect(opts.overflow.y).toBe('hidden');
|
expect(opts.overflow.y).toBe('hidden');
|
||||||
|
|
||||||
rerender(<OverlayScrollbarsComponent options={{ overflow: { x: 'hidden' } }} ref={ref} />);
|
rerender(<OverlayScrollbarsComponent options={{ overflow: { x: 'hidden' } }} ref={ref} />);
|
||||||
|
|
||||||
const newOpts = ref.current!.osInstance()!.options()!;
|
const newOpts = ref.current!.instance()!.options()!;
|
||||||
expect(newOpts.paddingAbsolute).toBe(false); //switches back to default because its not specified in the new options
|
expect(newOpts.paddingAbsolute).toBe(false); //switches back to default because its not specified in the new options
|
||||||
expect(newOpts.overflow.y).toBe('scroll'); //switches back to default because its not specified in the new options
|
expect(newOpts.overflow.y).toBe('scroll'); //switches back to default because its not specified in the new options
|
||||||
expect(newOpts.overflow.x).toBe('hidden');
|
expect(newOpts.overflow.x).toBe('hidden');
|
||||||
@@ -103,7 +103,7 @@ describe('OverlayScrollbarsComponent', () => {
|
|||||||
|
|
||||||
expect(onUpdated).not.toHaveBeenCalled();
|
expect(onUpdated).not.toHaveBeenCalled();
|
||||||
|
|
||||||
ref.current?.osInstance()?.update(true);
|
ref.current!.instance()!.update(true);
|
||||||
expect(onUpdatedInitial).toHaveBeenCalledTimes(1);
|
expect(onUpdatedInitial).toHaveBeenCalledTimes(1);
|
||||||
expect(onUpdated).toHaveBeenCalledTimes(1);
|
expect(onUpdated).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
@@ -111,14 +111,14 @@ describe('OverlayScrollbarsComponent', () => {
|
|||||||
<OverlayScrollbarsComponent events={{ updated: [onUpdated, onUpdatedInitial] }} ref={ref} />
|
<OverlayScrollbarsComponent events={{ updated: [onUpdated, onUpdatedInitial] }} ref={ref} />
|
||||||
);
|
);
|
||||||
|
|
||||||
ref.current?.osInstance()?.update(true);
|
ref.current!.instance()!.update(true);
|
||||||
expect(onUpdatedInitial).toHaveBeenCalledTimes(2);
|
expect(onUpdatedInitial).toHaveBeenCalledTimes(2);
|
||||||
expect(onUpdated).toHaveBeenCalledTimes(2);
|
expect(onUpdated).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
// unregister works with `[]`, `null` or `undefined`
|
// unregister works with `[]`, `null` or `undefined`
|
||||||
rerender(<OverlayScrollbarsComponent events={{ updated: null }} ref={ref} />);
|
rerender(<OverlayScrollbarsComponent events={{ updated: null }} ref={ref} />);
|
||||||
|
|
||||||
ref.current?.osInstance()?.update(true);
|
ref.current!.instance()!.update(true);
|
||||||
expect(onUpdatedInitial).toHaveBeenCalledTimes(2);
|
expect(onUpdatedInitial).toHaveBeenCalledTimes(2);
|
||||||
expect(onUpdated).toHaveBeenCalledTimes(2);
|
expect(onUpdated).toHaveBeenCalledTimes(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export type Initialization = {
|
|||||||
/**
|
/**
|
||||||
* Customizes which elements are generated and used.
|
* Customizes which elements are generated and used.
|
||||||
* If a function is passed to any of the fields, it receives the `target` element as its argument.
|
* If a function is passed to any of the fields, it receives the `target` element as its argument.
|
||||||
|
* Any passed function should be a "pure" function. (same input produces same output)
|
||||||
*/
|
*/
|
||||||
elements: {
|
elements: {
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user