improve react initialization and api

This commit is contained in:
Rene Haas
2022-10-30 23:11:57 +01:00
parent ed7777462a
commit 65c72326b0
3 changed files with 37 additions and 20 deletions
@@ -11,24 +11,36 @@ export type OverlayScrollbarsComponentProps<T extends keyof JSX.IntrinsicElement
};
export interface OverlayScrollbarsComponentRef<T extends keyof JSX.IntrinsicElements = 'div'> {
osInstance(): OverlayScrollbars | null;
osTarget(): ElementRef<T> | null;
instance(): OverlayScrollbars | null;
target(): ElementRef<T> | null;
}
const OverlayScrollbarsComponent = <T extends keyof JSX.IntrinsicElements>(
props: OverlayScrollbarsComponentProps<T>,
ref: ForwardedRef<OverlayScrollbarsComponentRef<T>>
) => {
const { element = 'div', options, events, ...other } = props;
const { element = 'div', options, events, children, ...other } = props;
const Tag = element;
const osTargetRef = useRef<ElementRef<T>>(null);
const osChildrenRef = useRef<HTMLDivElement>(null);
const osInstanceRef = useRef<OverlayScrollbars | null>(null);
useEffect(() => {
const { current: target } = osTargetRef;
if (target) {
const instance = OverlayScrollbars(target as any, options || {}, events);
const { current: targetElm } = osTargetRef;
const { current: childrenElm } = osChildrenRef;
if (targetElm && childrenElm) {
const instance = OverlayScrollbars(
{
target: targetElm as any,
elements: {
viewport: childrenElm,
content: childrenElm,
},
},
options || {},
events
);
osInstanceRef.current = instance;
return () => instance.destroy();
@@ -53,15 +65,19 @@ const OverlayScrollbarsComponent = <T extends keyof JSX.IntrinsicElements>(
ref,
() => {
return {
osInstance: () => osInstanceRef.current,
osTarget: () => osTargetRef.current,
instance: () => osInstanceRef.current,
target: () => osTargetRef.current,
};
},
[]
);
// @ts-ignore
return <Tag data-overlayscrollbars="" {...other} ref={osTargetRef} />;
return (
// @ts-ignore
<Tag data-overlayscrollbars="" {...other} ref={osTargetRef}>
<div ref={osChildrenRef}>{children}</div>
</Tag>
);
};
const OverlayScrollbarsComponentForwardedRef = forwardRef(OverlayScrollbarsComponent) as <
@@ -61,11 +61,11 @@ describe('OverlayScrollbarsComponent', () => {
const ref: RefObject<OverlayScrollbarsComponentRef> = { current: null };
const { container } = render(<OverlayScrollbarsComponent ref={ref} />);
const { osInstance, osTarget } = ref.current!;
expect(osInstance).toBeTypeOf('function');
expect(osTarget).toBeTypeOf('function');
expect(OverlayScrollbars.valid(osInstance())).toBe(true);
expect(osTarget()).toBe(container.firstElementChild);
const { instance, target } = ref.current!;
expect(instance).toBeTypeOf('function');
expect(target).toBeTypeOf('function');
expect(OverlayScrollbars.valid(instance())).toBe(true);
expect(target()).toBe(container.firstElementChild);
});
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.overflow.y).toBe('hidden');
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.overflow.y).toBe('scroll'); //switches back to default because its not specified in the new options
expect(newOpts.overflow.x).toBe('hidden');
@@ -103,7 +103,7 @@ describe('OverlayScrollbarsComponent', () => {
expect(onUpdated).not.toHaveBeenCalled();
ref.current?.osInstance()?.update(true);
ref.current!.instance()!.update(true);
expect(onUpdatedInitial).toHaveBeenCalledTimes(1);
expect(onUpdated).toHaveBeenCalledTimes(1);
@@ -111,14 +111,14 @@ describe('OverlayScrollbarsComponent', () => {
<OverlayScrollbarsComponent events={{ updated: [onUpdated, onUpdatedInitial] }} ref={ref} />
);
ref.current?.osInstance()?.update(true);
ref.current!.instance()!.update(true);
expect(onUpdatedInitial).toHaveBeenCalledTimes(2);
expect(onUpdated).toHaveBeenCalledTimes(2);
// unregister works with `[]`, `null` or `undefined`
rerender(<OverlayScrollbarsComponent events={{ updated: null }} ref={ref} />);
ref.current?.osInstance()?.update(true);
ref.current!.instance()!.update(true);
expect(onUpdatedInitial).toHaveBeenCalledTimes(2);
expect(onUpdated).toHaveBeenCalledTimes(2);
});
@@ -47,6 +47,7 @@ export type Initialization = {
/**
* 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.
* Any passed function should be a "pure" function. (same input produces same output)
*/
elements: {
/**