@wordpress/compose
Version:
WordPress higher-order components (HOCs).
8 lines (7 loc) • 8.45 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/hooks/use-fixed-window-list/index.ts"],
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useLayoutEffect } from '@wordpress/element';\nimport { getScrollContainer } from '@wordpress/dom';\nimport { PAGEUP, PAGEDOWN, HOME, END } from '@wordpress/keycodes';\n\n/**\n * Internal dependencies\n */\nimport { debounce } from '../../utils/debounce';\n\nconst DEFAULT_INIT_WINDOW_SIZE = 30;\n\ninterface FixedWindowList {\n\t/** Items visible in the current viewport */\n\tvisibleItems: number;\n\t/** Start index of the window */\n\tstart: number;\n\t/** End index of the window */\n\tend: number;\n\t/** Returns true if item is in the window */\n\titemInView: ( index: number ) => boolean;\n}\n\ninterface FixedWindowListOptions {\n\t/** Renders windowOverscan number of items before and after the calculated visible window. */\n\twindowOverscan?: number;\n\t/** When false avoids calculating the window size */\n\tuseWindowing?: boolean;\n\t/** Initial window size to use on first render before we can calculate the window size. */\n\tinitWindowSize?: number;\n\t/** Used to recalculate the window size when the expanded state of a list changes. */\n\texpandedState?: any;\n}\n\n/**\n *\n * @param elementRef Used to find the closest scroll container that contains element.\n * @param itemHeight Fixed item height in pixels\n * @param totalItems Total items in list\n * @param [options] Options object\n * @return Array with the fixed window list and setter\n */\nexport default function useFixedWindowList(\n\telementRef: React.RefObject< HTMLElement >,\n\titemHeight: number,\n\ttotalItems: number,\n\toptions?: FixedWindowListOptions\n): [\n\tFixedWindowList,\n\tReact.Dispatch< React.SetStateAction< FixedWindowList > >,\n] {\n\tconst initWindowSize = options?.initWindowSize ?? DEFAULT_INIT_WINDOW_SIZE;\n\tconst useWindowing = options?.useWindowing ?? true;\n\n\tconst [ fixedListWindow, setFixedListWindow ] = useState< FixedWindowList >(\n\t\t{\n\t\t\tvisibleItems: initWindowSize,\n\t\t\tstart: 0,\n\t\t\tend: initWindowSize,\n\t\t\titemInView: ( index: number ) => {\n\t\t\t\treturn index >= 0 && index <= initWindowSize;\n\t\t\t},\n\t\t}\n\t);\n\n\tuseLayoutEffect( () => {\n\t\tif ( ! useWindowing ) {\n\t\t\treturn;\n\t\t}\n\t\tconst scrollContainer = getScrollContainer( elementRef.current );\n\t\t/**\n\t\t * Measures and sets the window of items to render based on the scroll position\n\t\t *\n\t\t * @param {boolean} [initRender] Indicates if this is the initial render\n\t\t * @return {void}\n\t\t */\n\t\tconst measureWindow = ( initRender?: boolean ) => {\n\t\t\tif ( ! scrollContainer ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst visibleItems = Math.ceil(\n\t\t\t\tscrollContainer.clientHeight / itemHeight\n\t\t\t);\n\t\t\t// Aim to keep opening list view fast, afterward we can optimize for scrolling.\n\t\t\tconst windowOverscan = initRender\n\t\t\t\t? visibleItems\n\t\t\t\t: options?.windowOverscan ?? visibleItems;\n\t\t\tconst firstViewableIndex = Math.floor(\n\t\t\t\tscrollContainer.scrollTop / itemHeight\n\t\t\t);\n\t\t\tconst start = Math.max( 0, firstViewableIndex - windowOverscan );\n\t\t\tconst end = Math.min(\n\t\t\t\ttotalItems - 1,\n\t\t\t\tfirstViewableIndex + visibleItems + windowOverscan\n\t\t\t);\n\t\t\tsetFixedListWindow( ( lastWindow ) => {\n\t\t\t\tconst nextWindow = {\n\t\t\t\t\tvisibleItems,\n\t\t\t\t\tstart,\n\t\t\t\t\tend,\n\t\t\t\t\titemInView: ( index: number ) => {\n\t\t\t\t\t\treturn start <= index && index <= end;\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tif (\n\t\t\t\t\tlastWindow.start !== nextWindow.start ||\n\t\t\t\t\tlastWindow.end !== nextWindow.end ||\n\t\t\t\t\tlastWindow.visibleItems !== nextWindow.visibleItems\n\t\t\t\t) {\n\t\t\t\t\treturn nextWindow;\n\t\t\t\t}\n\t\t\t\treturn lastWindow;\n\t\t\t} );\n\t\t};\n\n\t\tmeasureWindow( true );\n\t\tconst debounceMeasureList = debounce( () => {\n\t\t\tmeasureWindow();\n\t\t}, 16 );\n\t\tscrollContainer?.addEventListener( 'scroll', debounceMeasureList );\n\t\tscrollContainer?.ownerDocument?.defaultView?.addEventListener(\n\t\t\t'resize',\n\t\t\tdebounceMeasureList\n\t\t);\n\t\tscrollContainer?.ownerDocument?.defaultView?.addEventListener(\n\t\t\t'resize',\n\t\t\tdebounceMeasureList\n\t\t);\n\n\t\treturn () => {\n\t\t\tscrollContainer?.removeEventListener(\n\t\t\t\t'scroll',\n\t\t\t\tdebounceMeasureList\n\t\t\t);\n\t\t\tscrollContainer?.ownerDocument?.defaultView?.removeEventListener(\n\t\t\t\t'resize',\n\t\t\t\tdebounceMeasureList\n\t\t\t);\n\t\t};\n\t}, [\n\t\titemHeight,\n\t\telementRef,\n\t\ttotalItems,\n\t\toptions?.expandedState,\n\t\toptions?.windowOverscan,\n\t\tuseWindowing,\n\t] );\n\n\tuseLayoutEffect( () => {\n\t\tif ( ! useWindowing ) {\n\t\t\treturn;\n\t\t}\n\t\tconst scrollContainer = getScrollContainer( elementRef.current );\n\t\tconst handleKeyDown = ( event: KeyboardEvent ) => {\n\t\t\tswitch ( event.keyCode ) {\n\t\t\t\tcase HOME: {\n\t\t\t\t\treturn scrollContainer?.scrollTo( { top: 0 } );\n\t\t\t\t}\n\t\t\t\tcase END: {\n\t\t\t\t\treturn scrollContainer?.scrollTo( {\n\t\t\t\t\t\ttop: totalItems * itemHeight,\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\tcase PAGEUP: {\n\t\t\t\t\treturn scrollContainer?.scrollTo( {\n\t\t\t\t\t\ttop:\n\t\t\t\t\t\t\tscrollContainer.scrollTop -\n\t\t\t\t\t\t\tfixedListWindow.visibleItems * itemHeight,\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\tcase PAGEDOWN: {\n\t\t\t\t\treturn scrollContainer?.scrollTo( {\n\t\t\t\t\t\ttop:\n\t\t\t\t\t\t\tscrollContainer.scrollTop +\n\t\t\t\t\t\t\tfixedListWindow.visibleItems * itemHeight,\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tscrollContainer?.ownerDocument?.defaultView?.addEventListener(\n\t\t\t'keydown',\n\t\t\thandleKeyDown\n\t\t);\n\t\treturn () => {\n\t\t\tscrollContainer?.ownerDocument?.defaultView?.removeEventListener(\n\t\t\t\t'keydown',\n\t\t\t\thandleKeyDown\n\t\t\t);\n\t\t};\n\t}, [\n\t\ttotalItems,\n\t\titemHeight,\n\t\telementRef,\n\t\tfixedListWindow.visibleItems,\n\t\tuseWindowing,\n\t\toptions?.expandedState,\n\t] );\n\n\treturn [ fixedListWindow, setFixedListWindow ];\n}\n"],
"mappings": "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",
"names": []
}