diff --git a/README.md b/README.md index c7a35ff..922ccba 100644 --- a/README.md +++ b/README.md @@ -51,11 +51,11 @@ autoScroll({ selector: "#scroll-container-id" }); > es ```ts -import autoScroll, { generateEscapeScrollUpContext } from "@yrobot/auto-scroll"; +import autoScroll, { escapeWhenUpPlugin } from "@yrobot/auto-scroll"; autoScroll({ selector: "#scroll-container-id", - context: generateEscapeScrollUpContext(), + plugins: [escapeWhenUpPlugin()], }); ``` @@ -64,6 +64,20 @@ autoScroll({ ```ts autoScroll.default({ selector: "#scroll-container-id", - context: autoScroll.generateEscapeScrollUpContext(), + plugins: [autoScroll.escapeWhenUpPlugin()], }); ``` + + diff --git a/package/index.ts b/package/index.ts index 910a839..3bdf8f2 100644 --- a/package/index.ts +++ b/package/index.ts @@ -33,19 +33,21 @@ export type Context = { onUnmount?: OnUnmount; }; +export type Plugin = (config?: T) => Context; + /** - * Generates the context for escaping auto scroll down when user scroll up. + * the auto-scroll plugin for escaping auto scroll down when user scroll up. * * @param {Object} config - The configs. * @param {number} [config.threshold=24] - The threshold value for scroll up distance (default: 24). * @param {number} [config.throttleTime=100] - The throttle time for scroll event (default: 100). * - * @returns {Context} The generated context object. For autoScroll.param.context + * @returns {Context} The generated state object. For autoScroll.param.plugins */ -export function generateEscapeScrollUpContext({ - threshold = 24, - throttleTime = 100, -}: { threshold?: number; throttleTime?: number } = {}) { +export const escapeWhenUpPlugin: Plugin<{ + threshold?: number; + throttleTime?: number; +}> = ({ threshold = 24, throttleTime = 100 } = {}) => { const context: Context = {}; let isEscape = false; const [onScroll] = throttle((evt: Event) => { @@ -62,31 +64,31 @@ export function generateEscapeScrollUpContext({ }; context.escapeHook = () => isEscape; return context; -} +}; /** * @description auto scroll the selector dom to the bottom, when the size of the selector dom has been updated. * * @param {Object} options - The config options for the autoScroll function. * @param {string} options.selector - The selector for the container element. (example: '#container') - * @param {Context} [options.context] - The context for the life cycle hooks of the autoScroll function. [escapeHook,onMount,onUnmount] + * @param {Context[]} [options.plugins] - The plugins for the life cycle hooks of the autoScroll function. [escapeHook,onMount,onUnmount] * @param {number} [options.throttleTime=100] - The throttle time in milliseconds. * @param {number} [options.offset=0] - The offset for the scroll position based on the container.scrollHeight. * * @return {function} The unObserverCallback function. * * @example autoScroll({ selector: "#scroll-container-id" }) - * @example autoScroll({ selector: "#scroll-container-id", context: generateEscapeScrollUpContext() }) + * @example autoScroll({ selector: "#scroll-container-id", plugins: [escapeWhenUpPlugin()] }) */ export default function autoScroll({ selector, throttleTime = 100, - context, + plugins = [], offset = 0, }: { selector: string; throttleTime?: number; - context?: Context; + plugins?: ReturnType[]; offset?: number; }): unObserverCallback { const container = document.querySelector(selector); @@ -94,13 +96,14 @@ export default function autoScroll({ if (container === null) throw new Error(`Element not found with selector [${selector}]`); - const returnOnUnmount = context?.onMount?.(container); + // plugins onMount + const mountReturnFuncList = plugins + .map((plugin) => plugin?.onMount?.(container)) + .filter((result) => typeof result === "function") as OnUnmount[]; + // main auto down scroll hook const [scrollHook] = throttle(() => { - if ( - typeof context?.escapeHook === "function" && - context.escapeHook(container) - ) + if (!!plugins.find((plugin) => plugin?.escapeHook?.(container) === true)) return false; // use requestAnimationFrame for escape ResizeObserver loop requestAnimationFrame(() => { @@ -109,10 +112,10 @@ export default function autoScroll({ return true; }, throttleTime); + // observers const resizeObserver = new ResizeObserver(() => { scrollHook(); }); - const mutationObserver = new MutationObserver(() => { scrollHook(); }); @@ -127,11 +130,12 @@ export default function autoScroll({ subtree: true, childList: true, }); + + // unmount return () => { resizeObserver.disconnect(); mutationObserver.disconnect(); - // unmount - returnOnUnmount?.(container); - context?.onUnmount?.(container); + mountReturnFuncList.forEach((func) => func(container)); + plugins.forEach((plugin) => plugin?.onUnmount?.(container)); }; } diff --git a/website/index.tsx b/website/index.tsx index bc01ade..0d608a8 100644 --- a/website/index.tsx +++ b/website/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useRef, useState } from "react"; import { createRoot } from "react-dom/client"; -import autoScroll, { generateEscapeScrollUpContext } from "../package/index.ts"; +import autoScroll, { escapeWhenUpPlugin } from "../package/index.ts"; import "./index.css"; @@ -32,11 +32,11 @@ import autoScroll from "@yrobot/auto-scroll"; autoScroll({ selector: "#scroll-container-id" });`, escapeScrollUp: ` -import autoScroll, { generateEscapeScrollUpContext } from "@yrobot/auto-scroll"; +import autoScroll, { escapeWhenUpPlugin } from "@yrobot/auto-scroll"; autoScroll({ selector: "#scroll-container-id", - context: generateEscapeScrollUpContext(), + plugins: [escapeWhenUpPlugin()], });`, }; @@ -86,7 +86,7 @@ const EscapeScrollUpDemo = () => { () => autoScroll({ selector: "#escape-scroll-up-list-container", - context: generateEscapeScrollUpContext(), + plugins: [escapeWhenUpPlugin()], }), [] );