@ai-matrx/design-system 0.18.22 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/content-transfer/alchemy.svg +1 -1
  3. package/dist/content-transfer/copy-transform.svg +1 -0
  4. package/dist/content-transfer/icon.cjs +8 -2
  5. package/dist/content-transfer/icon.cjs.map +1 -1
  6. package/dist/content-transfer/icon.d.cts +5 -3
  7. package/dist/content-transfer/icon.d.ts +5 -3
  8. package/dist/content-transfer/icon.js +8 -2
  9. package/dist/content-transfer/icon.js.map +1 -1
  10. package/dist/content-transfer/portal.svg +1 -0
  11. package/dist/content-transfer.cjs +923 -304
  12. package/dist/content-transfer.cjs.map +1 -1
  13. package/dist/content-transfer.css +17 -74
  14. package/dist/content-transfer.d.cts +14 -3
  15. package/dist/content-transfer.d.ts +14 -3
  16. package/dist/content-transfer.js +929 -305
  17. package/dist/content-transfer.js.map +1 -1
  18. package/dist/data-table/copy-helpers.d.cts +1 -1
  19. package/dist/data-table/copy-helpers.d.ts +1 -1
  20. package/dist/data-table/data-row-inspector.cjs +990 -397
  21. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  22. package/dist/data-table/data-row-inspector.js +988 -390
  23. package/dist/data-table/data-row-inspector.js.map +1 -1
  24. package/dist/data-table/data-row-window.cjs +989 -396
  25. package/dist/data-table/data-row-window.cjs.map +1 -1
  26. package/dist/data-table/data-row-window.js +987 -389
  27. package/dist/data-table/data-row-window.js.map +1 -1
  28. package/dist/data-table/filter-engine.d.cts +1 -1
  29. package/dist/data-table/filter-engine.d.ts +1 -1
  30. package/dist/data-table/host.d.cts +1 -1
  31. package/dist/data-table/host.d.ts +1 -1
  32. package/dist/data-table/index.cjs +1628 -1007
  33. package/dist/data-table/index.cjs.map +1 -1
  34. package/dist/data-table/index.d.cts +2 -2
  35. package/dist/data-table/index.d.ts +2 -2
  36. package/dist/data-table/index.js +1480 -854
  37. package/dist/data-table/index.js.map +1 -1
  38. package/dist/data-table/infer-filter.d.cts +1 -1
  39. package/dist/data-table/infer-filter.d.ts +1 -1
  40. package/dist/data-table/layered-filters.d.cts +1 -1
  41. package/dist/data-table/layered-filters.d.ts +1 -1
  42. package/dist/data-table/pagination.cjs +1 -1
  43. package/dist/data-table/pagination.cjs.map +1 -1
  44. package/dist/data-table/pagination.js +1 -1
  45. package/dist/data-table/pagination.js.map +1 -1
  46. package/dist/data-table/query-control.d.cts +1 -1
  47. package/dist/data-table/query-control.d.ts +1 -1
  48. package/dist/data-table/scroll-pagination.cjs +82 -54
  49. package/dist/data-table/scroll-pagination.cjs.map +1 -1
  50. package/dist/data-table/scroll-pagination.js +82 -54
  51. package/dist/data-table/scroll-pagination.js.map +1 -1
  52. package/dist/data-table/types.d.cts +1 -1
  53. package/dist/data-table/types.d.ts +1 -1
  54. package/dist/data-table/url-state.d.cts +1 -1
  55. package/dist/data-table/url-state.d.ts +1 -1
  56. package/dist/data-table/uuid-cell.cjs +1 -1
  57. package/dist/data-table/uuid-cell.cjs.map +1 -1
  58. package/dist/data-table/uuid-cell.js +1 -1
  59. package/dist/data-table/uuid-cell.js.map +1 -1
  60. package/dist/data-table/xlsx.d.cts +1 -1
  61. package/dist/data-table/xlsx.d.ts +1 -1
  62. package/dist/index.cjs +527 -0
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +1 -0
  65. package/dist/index.d.ts +1 -0
  66. package/dist/index.js +531 -0
  67. package/dist/index.js.map +1 -1
  68. package/dist/tap-target.cjs +636 -0
  69. package/dist/tap-target.cjs.map +1 -0
  70. package/dist/tap-target.css +151 -0
  71. package/dist/tap-target.d.cts +131 -0
  72. package/dist/tap-target.d.ts +131 -0
  73. package/dist/tap-target.js +608 -0
  74. package/dist/tap-target.js.map +1 -0
  75. package/dist/{types-Cbnj1Qlm.d.ts → types-D1m14boM.d.ts} +1 -1
  76. package/dist/{types-CWW4Tur-.d.cts → types-Di6QT0P1.d.cts} +1 -1
  77. package/package.json +14 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/data-table/useScrollPagination.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport type ScrollPaginationContainer =\n | HTMLElement\n | RefObject<HTMLElement | null>\n | null;\n\nexport interface UseScrollPaginationOptions {\n /** Every visible desktop/mobile scroll container that may present this table. */\n containers: readonly ScrollPaginationContainer[];\n /** Immutable identity of every source-affecting query value. */\n queryKey: string;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n loading: boolean;\n /** Automatic scrolling never retries a failed append. */\n error: Error | null;\n loadNextPage: () => Promise<void> | void;\n /** Manual mode exposes the explicit request only; it installs no listeners. */\n mode?: \"scroll\" | \"manual\";\n /** Distance from the bottom at which a qualifying user scroll may append. */\n thresholdPx?: number;\n /** How long an input may authorize the following real scroll movement. */\n intentTimeoutMs?: number;\n enabled?: boolean;\n}\n\nexport interface UseScrollPaginationResult {\n /** For the table's accessible Load more / Retry control. */\n requestNextPage: () => Promise<void>;\n canLoadMore: boolean;\n /** Includes an unexpected loader rejection until the person explicitly retries. */\n error: Error | null;\n}\n\ninterface ScrollIntent {\n queryKey: string;\n container: HTMLElement;\n startTop: number;\n sequence: number;\n expiresAt: number;\n}\n\nconst DEFAULT_THRESHOLD_PX = 96;\nconst DEFAULT_INTENT_TIMEOUT_MS = 1_200;\n\nfunction resolveContainer(container: ScrollPaginationContainer): HTMLElement | null {\n if (!container) return null;\n return container instanceof HTMLElement ? container : container.current;\n}\n\nfunction isVisibleContainer(container: HTMLElement): boolean {\n if (!container.isConnected) return false;\n for (let node: HTMLElement | null = container; node; node = node.parentElement) {\n const style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\") return false;\n }\n return true;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return target.isContentEditable || Boolean(target.closest(\"input, textarea, select, [contenteditable='true']\"));\n}\n\nfunction isDownwardKeyboardInput(event: KeyboardEvent): boolean {\n if (isEditableTarget(event.target)) return false;\n return [\"ArrowDown\", \"PageDown\", \"End\", \" \", \"Spacebar\"].includes(event.key);\n}\n\nfunction isNearBottom(container: HTMLElement, thresholdPx: number): boolean {\n return container.scrollHeight - container.clientHeight - container.scrollTop <= thresholdPx;\n}\n\nfunction isNativeScrollbarPointer(event: PointerEvent, container: HTMLElement): boolean {\n // Overlay scrollbars expose no measurable gutter. Do not guess: Load more is\n // the accessible, reliable fallback there. A content click must never grant\n // permission for a later programmatic scroll to append rows.\n if (event.pointerType !== \"mouse\" || event.button !== 0 || !event.isPrimary) return false;\n const gutterWidth = container.offsetWidth - container.clientWidth;\n if (gutterWidth <= 0 || container.scrollHeight <= container.clientHeight) return false;\n const rect = container.getBoundingClientRect();\n return event.clientX >= rect.right - gutterWidth && event.clientX <= rect.right;\n}\n\n/**\n * Gates automatic append behind a fresh, real downward user scroll. The hook\n * owns neither fetching nor row state: callers feed it the data hook receipt\n * and render its explicit request as the accessible fallback control.\n */\nexport function useScrollPagination({\n containers,\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode = \"scroll\",\n thresholdPx = DEFAULT_THRESHOLD_PX,\n intentTimeoutMs = DEFAULT_INTENT_TIMEOUT_MS,\n enabled = true,\n}: UseScrollPaginationOptions): UseScrollPaginationResult {\n const [requestError, setRequestError] = useState<Error | null>(null);\n const latestRef = useRef({\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n });\n latestRef.current = {\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n };\n\n const intentRef = useRef<ScrollIntent | null>(null);\n const inputSequenceRef = useRef(0);\n const consumedSequenceRef = useRef(0);\n const requestGenerationRef = useRef(0);\n const inFlightGenerationRef = useRef<number | null>(null);\n const requestErrorRef = useRef<Error | null>(null);\n const mountedRef = useRef(false);\n // Listener effects reattach when consumers recreate their container arrays.\n // Keep the last real scroll position with the element, not with one effect.\n const observedTopRef = useRef<WeakMap<HTMLElement, number>>(new WeakMap());\n const effectiveError = error ?? requestError;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const requestNextPage = async () => {\n const current = latestRef.current;\n if (\n !current.enabled ||\n (!current.hasNextPage && effectiveError === null) ||\n current.loading ||\n current.isFetchingNextPage ||\n inFlightGenerationRef.current !== null\n ) {\n return;\n }\n const generation = ++requestGenerationRef.current;\n inFlightGenerationRef.current = generation;\n requestErrorRef.current = null;\n setRequestError(null);\n try {\n await current.loadNextPage();\n } catch (raw) {\n const nextError = raw instanceof Error ? raw : new Error(String(raw));\n if (inFlightGenerationRef.current === generation && latestRef.current.queryKey === current.queryKey) {\n requestErrorRef.current = nextError;\n if (mountedRef.current) setRequestError(nextError);\n }\n } finally {\n if (inFlightGenerationRef.current === generation) {\n inFlightGenerationRef.current = null;\n intentRef.current = null;\n }\n }\n };\n\n useEffect(() => {\n intentRef.current = null;\n observedTopRef.current = new WeakMap();\n consumedSequenceRef.current = inputSequenceRef.current;\n requestErrorRef.current = null;\n setRequestError(null);\n // A query change makes every existing completion stale. Its finally block\n // cannot clear a new request because generations are monotonically unique.\n inFlightGenerationRef.current = null;\n requestGenerationRef.current += 1;\n }, [queryKey]);\n\n useEffect(() => {\n if (mode !== \"scroll\" || !enabled || typeof window === \"undefined\") return;\n\n const attachable = containers\n .map(resolveContainer)\n .filter((container): container is HTMLElement => container !== null);\n\n const setIntent = (container: HTMLElement, startTop: number) => {\n const current = latestRef.current;\n if (!isVisibleContainer(container) || current.loading || current.isFetchingNextPage || inFlightGenerationRef.current !== null) return;\n inputSequenceRef.current += 1;\n intentRef.current = {\n queryKey: latestRef.current.queryKey,\n container,\n // The compositor can advance downward before the passive input\n // listener, while DOM/test callers can move upward before its scroll\n // notification. Either way, the lower position is the only safe\n // baseline for proving that this downward intent caused movement.\n startTop: Math.min(startTop, container.scrollTop),\n sequence: inputSequenceRef.current,\n expiresAt: Date.now() + intentTimeoutMs,\n };\n };\n\n const handleScroll = (container: HTMLElement) => {\n const intent = intentRef.current;\n const current = latestRef.current;\n if (\n !intent ||\n intent.queryKey !== current.queryKey ||\n intent.container !== container ||\n Date.now() > intent.expiresAt ||\n container.scrollTop <= intent.startTop ||\n intent.sequence <= consumedSequenceRef.current ||\n !isVisibleContainer(container) ||\n !isNearBottom(container, current.thresholdPx) ||\n !current.hasNextPage ||\n current.loading ||\n current.isFetchingNextPage ||\n current.error !== null ||\n requestErrorRef.current !== null ||\n inFlightGenerationRef.current !== null\n ) {\n return;\n }\n consumedSequenceRef.current = intent.sequence;\n void requestNextPage();\n };\n\n const cleanups = attachable.map((container) => {\n // A passive wheel listener may run after the compositor has already\n // advanced scrollTop, but before the asynchronous scroll notification.\n // Preserve the last *observed* position so that ordering still proves\n // movement from this trusted input without authorizing scroll-only code.\n if (!observedTopRef.current.has(container)) observedTopRef.current.set(container, container.scrollTop);\n const lastObservedTop = () => observedTopRef.current.get(container) ?? container.scrollTop;\n const onWheel = (event: WheelEvent) => {\n if (event.deltaY > 0 && Math.abs(event.deltaY) > Math.abs(event.deltaX)) {\n setIntent(container, lastObservedTop());\n }\n };\n const onTouchStart = (event: TouchEvent) => {\n const touch = event.touches.item(0);\n if (touch) container.dataset.matrxPaginationTouchY = String(touch.clientY);\n };\n const onTouchMove = (event: TouchEvent) => {\n const touch = event.touches.item(0);\n const startY = Number(container.dataset.matrxPaginationTouchY);\n if (touch && Number.isFinite(startY) && startY - touch.clientY > 0) {\n setIntent(container, lastObservedTop());\n }\n };\n const onTouchEnd = () => {\n delete container.dataset.matrxPaginationTouchY;\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (isDownwardKeyboardInput(event)) setIntent(container, lastObservedTop());\n };\n const onPointerDown = (event: PointerEvent) => {\n if (isNativeScrollbarPointer(event, container)) setIntent(container, lastObservedTop());\n };\n const onScroll = () => {\n handleScroll(container);\n observedTopRef.current.set(container, container.scrollTop);\n };\n\n container.addEventListener(\"wheel\", onWheel, { passive: true });\n container.addEventListener(\"touchstart\", onTouchStart, { passive: true });\n container.addEventListener(\"touchmove\", onTouchMove, { passive: true });\n container.addEventListener(\"touchend\", onTouchEnd, { passive: true });\n container.addEventListener(\"touchcancel\", onTouchEnd, { passive: true });\n container.addEventListener(\"keydown\", onKeyDown);\n container.addEventListener(\"pointerdown\", onPointerDown, { passive: true });\n container.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => {\n delete container.dataset.matrxPaginationTouchY;\n container.removeEventListener(\"wheel\", onWheel);\n container.removeEventListener(\"touchstart\", onTouchStart);\n container.removeEventListener(\"touchmove\", onTouchMove);\n container.removeEventListener(\"touchend\", onTouchEnd);\n container.removeEventListener(\"touchcancel\", onTouchEnd);\n container.removeEventListener(\"keydown\", onKeyDown);\n container.removeEventListener(\"pointerdown\", onPointerDown);\n container.removeEventListener(\"scroll\", onScroll);\n };\n });\n return () => cleanups.forEach((cleanup) => cleanup());\n }, [containers, enabled, intentTimeoutMs, mode]);\n\n return {\n requestNextPage,\n canLoadMore: enabled && !loading && !isFetchingNextPage && (hasNextPage || effectiveError !== null),\n error: effectiveError,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/data-table/useScrollPagination.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport type ScrollPaginationContainer =\n | HTMLElement\n | RefObject<HTMLElement | null>\n | null;\n\nexport interface UseScrollPaginationOptions {\n /** Every visible desktop/mobile scroll container that may present this table. */\n containers: readonly ScrollPaginationContainer[];\n /** Immutable identity of every source-affecting query value. */\n queryKey: string;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n loading: boolean;\n /** Automatic scrolling never retries a failed append. */\n error: Error | null;\n loadNextPage: () => Promise<void> | void;\n /** Manual mode exposes the explicit request only; it installs no listeners. */\n mode?: \"scroll\" | \"manual\";\n /** Distance from the bottom at which a qualifying user scroll may append. */\n thresholdPx?: number;\n /** How long an input may authorize the following real scroll movement. */\n intentTimeoutMs?: number;\n enabled?: boolean;\n}\n\nexport interface UseScrollPaginationResult {\n /** For the table's accessible Load more / Retry control. */\n requestNextPage: () => Promise<void>;\n canLoadMore: boolean;\n /** Includes an unexpected loader rejection until the person explicitly retries. */\n error: Error | null;\n}\n\ninterface ScrollOwner { element: HTMLElement; document: boolean; }\ninterface ScrollIntent {\n queryKey: string;\n source: HTMLElement;\n owner: ScrollOwner;\n startTop: number;\n sequence: number;\n expiresAt: number;\n}\n\nconst DEFAULT_THRESHOLD_PX = 96;\nconst DEFAULT_INTENT_TIMEOUT_MS = 1_200;\n\nfunction resolveContainer(container: ScrollPaginationContainer): HTMLElement | null {\n if (!container) return null;\n return container instanceof HTMLElement ? container : container.current;\n}\n\nfunction isVisibleContainer(container: HTMLElement): boolean {\n if (!container.isConnected) return false;\n for (let node: HTMLElement | null = container; node; node = node.parentElement) {\n const style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\") return false;\n }\n return true;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return target.isContentEditable || Boolean(target.closest(\"input, textarea, select, [contenteditable='true']\"));\n}\n\nfunction isDownwardKeyboardInput(event: KeyboardEvent): boolean {\n if (isEditableTarget(event.target)) return false;\n return [\"ArrowDown\", \"PageDown\", \"End\", \" \", \"Spacebar\"].includes(event.key);\n}\n\nfunction isNearBottom(container: HTMLElement, thresholdPx: number): boolean {\n return container.scrollHeight - container.clientHeight - container.scrollTop <= thresholdPx;\n}\n\nfunction isVerticallyScrollable(element: HTMLElement): boolean {\n const overflowY = window.getComputedStyle(element).overflowY;\n return (overflowY === \"auto\" || overflowY === \"scroll\" || overflowY === \"overlay\") && element.scrollHeight > element.clientHeight;\n}\nfunction resolveScrollOwner(source: HTMLElement): ScrollOwner {\n for (let node: HTMLElement | null = source; node; node = node.parentElement) {\n if ((node === source && node.scrollHeight > node.clientHeight) || isVerticallyScrollable(node)) {\n return { element: node, document: false };\n }\n }\n return { element: document.scrollingElement instanceof HTMLElement ? document.scrollingElement : document.documentElement, document: true };\n}\nfunction ownerScrollTop(owner: ScrollOwner): number {\n return owner.document\n ? window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0\n : owner.element.scrollTop;\n}\nfunction sourceBottomIsNearOwnerViewport(source: HTMLElement, owner: ScrollOwner, thresholdPx: number): boolean {\n if (!owner.document && owner.element === source) return isNearBottom(source, thresholdPx);\n const sourceRect = source.getBoundingClientRect();\n const ownerRect = owner.document ? { top: 0, bottom: window.innerHeight } : owner.element.getBoundingClientRect();\n return sourceRect.bottom > ownerRect.top && sourceRect.top < ownerRect.bottom && sourceRect.bottom <= ownerRect.bottom + thresholdPx;\n}\n\nfunction isNativeScrollbarPointer(event: PointerEvent, container: HTMLElement): boolean {\n // Overlay scrollbars expose no measurable gutter. Do not guess: Load more is\n // the accessible, reliable fallback there. A content click must never grant\n // permission for a later programmatic scroll to append rows.\n if (event.pointerType !== \"mouse\" || event.button !== 0 || !event.isPrimary) return false;\n const gutterWidth = container.offsetWidth - container.clientWidth;\n if (gutterWidth <= 0 || container.scrollHeight <= container.clientHeight) return false;\n const rect = container.getBoundingClientRect();\n return event.clientX >= rect.right - gutterWidth && event.clientX <= rect.right;\n}\n\n/**\n * Gates automatic append behind a fresh, real downward user scroll. The hook\n * owns neither fetching nor row state: callers feed it the data hook receipt\n * and render its explicit request as the accessible fallback control.\n */\nexport function useScrollPagination({\n containers,\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode = \"scroll\",\n thresholdPx = DEFAULT_THRESHOLD_PX,\n intentTimeoutMs = DEFAULT_INTENT_TIMEOUT_MS,\n enabled = true,\n}: UseScrollPaginationOptions): UseScrollPaginationResult {\n const [requestError, setRequestError] = useState<Error | null>(null);\n const latestRef = useRef({\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n });\n latestRef.current = {\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n };\n\n const intentRef = useRef<ScrollIntent | null>(null);\n const inputSequenceRef = useRef(0);\n const consumedSequenceRef = useRef(0);\n const requestGenerationRef = useRef(0);\n const inFlightGenerationRef = useRef<number | null>(null);\n const requestErrorRef = useRef<Error | null>(null);\n const mountedRef = useRef(false);\n // Listener effects reattach when consumers recreate their container arrays.\n // Keep the last real scroll position with the element, not with one effect.\n const observedTopRef = useRef<WeakMap<HTMLElement, number>>(new WeakMap());\n const effectiveError = error ?? requestError;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const requestNextPage = async () => {\n const current = latestRef.current;\n if (\n !current.enabled ||\n (!current.hasNextPage && effectiveError === null) ||\n current.loading ||\n current.isFetchingNextPage ||\n inFlightGenerationRef.current !== null\n ) {\n return;\n }\n const generation = ++requestGenerationRef.current;\n inFlightGenerationRef.current = generation;\n requestErrorRef.current = null;\n setRequestError(null);\n try {\n await current.loadNextPage();\n } catch (raw) {\n const nextError = raw instanceof Error ? raw : new Error(String(raw));\n if (inFlightGenerationRef.current === generation && latestRef.current.queryKey === current.queryKey) {\n requestErrorRef.current = nextError;\n if (mountedRef.current) setRequestError(nextError);\n }\n } finally {\n if (inFlightGenerationRef.current === generation) {\n inFlightGenerationRef.current = null;\n intentRef.current = null;\n }\n }\n };\n\n useEffect(() => {\n intentRef.current = null;\n observedTopRef.current = new WeakMap();\n consumedSequenceRef.current = inputSequenceRef.current;\n requestErrorRef.current = null;\n setRequestError(null);\n // A query change makes every existing completion stale. Its finally block\n // cannot clear a new request because generations are monotonically unique.\n inFlightGenerationRef.current = null;\n requestGenerationRef.current += 1;\n }, [queryKey]);\n\n useEffect(() => {\n if (mode !== \"scroll\" || !enabled || typeof window === \"undefined\") return;\n const attachable = containers.map(resolveContainer).filter((container): container is HTMLElement => container !== null);\n const ownerCleanups = new Map<HTMLElement, () => void>();\n const handleScroll = (source: HTMLElement, owner: ScrollOwner) => {\n const intent = intentRef.current;\n const current = latestRef.current;\n if (!intent || intent.queryKey !== current.queryKey || intent.source !== source || intent.owner.element !== owner.element || intent.owner.document !== owner.document || Date.now() > intent.expiresAt || ownerScrollTop(owner) <= intent.startTop || intent.sequence <= consumedSequenceRef.current || !isVisibleContainer(source) || !sourceBottomIsNearOwnerViewport(source, owner, current.thresholdPx) || !current.hasNextPage || current.loading || current.isFetchingNextPage || current.error !== null || requestErrorRef.current !== null || inFlightGenerationRef.current !== null) return;\n consumedSequenceRef.current = intent.sequence;\n void requestNextPage();\n };\n const ensureOwnerListener = (owner: ScrollOwner) => {\n if (ownerCleanups.has(owner.element)) return;\n const onOwnerScroll = () => {\n const intent = intentRef.current;\n if (intent && intent.owner.element === owner.element && intent.owner.document === owner.document) handleScroll(intent.source, owner);\n observedTopRef.current.set(owner.element, ownerScrollTop(owner));\n };\n if (owner.document) window.addEventListener(\"scroll\", onOwnerScroll, { passive: true });\n else owner.element.addEventListener(\"scroll\", onOwnerScroll, { passive: true });\n ownerCleanups.set(owner.element, () => {\n if (owner.document) window.removeEventListener(\"scroll\", onOwnerScroll);\n else owner.element.removeEventListener(\"scroll\", onOwnerScroll);\n });\n };\n const setIntent = (source: HTMLElement, startTop: number) => {\n const current = latestRef.current;\n const owner = resolveScrollOwner(source);\n if (!isVisibleContainer(source) || current.loading || current.isFetchingNextPage || inFlightGenerationRef.current !== null) return;\n inputSequenceRef.current += 1;\n const currentOwnerTop = ownerScrollTop(owner);\n const observedOwnerTop = observedTopRef.current.get(owner.element) ?? currentOwnerTop;\n observedTopRef.current.set(owner.element, currentOwnerTop);\n intentRef.current = { queryKey: current.queryKey, source, owner, startTop: Math.min(observedOwnerTop, currentOwnerTop), sequence: inputSequenceRef.current, expiresAt: Date.now() + intentTimeoutMs };\n ensureOwnerListener(owner);\n };\n const cleanups = attachable.map((source) => {\n if (!observedTopRef.current.has(source)) observedTopRef.current.set(source, source.scrollTop);\n const lastObservedTop = () => observedTopRef.current.get(source) ?? source.scrollTop;\n const onWheel = (event: WheelEvent) => { if (event.deltaY > 0 && Math.abs(event.deltaY) > Math.abs(event.deltaX)) setIntent(source, lastObservedTop()); };\n const onTouchStart = (event: TouchEvent) => { const touch = event.touches.item(0); if (touch) source.dataset.matrxPaginationTouchY = String(touch.clientY); };\n const onTouchMove = (event: TouchEvent) => { const touch = event.touches.item(0); const startY = Number(source.dataset.matrxPaginationTouchY); if (touch && Number.isFinite(startY) && startY - touch.clientY > 0) setIntent(source, lastObservedTop()); };\n const onTouchEnd = () => { delete source.dataset.matrxPaginationTouchY; };\n const onKeyDown = (event: KeyboardEvent) => { if (isDownwardKeyboardInput(event)) setIntent(source, lastObservedTop()); };\n const onPointerDown = (event: PointerEvent) => { if (isNativeScrollbarPointer(event, source)) setIntent(source, lastObservedTop()); };\n const onScroll = () => { handleScroll(source, { element: source, document: false }); observedTopRef.current.set(source, source.scrollTop); };\n source.addEventListener(\"wheel\", onWheel, { passive: true }); source.addEventListener(\"touchstart\", onTouchStart, { passive: true }); source.addEventListener(\"touchmove\", onTouchMove, { passive: true }); source.addEventListener(\"touchend\", onTouchEnd, { passive: true }); source.addEventListener(\"touchcancel\", onTouchEnd, { passive: true }); source.addEventListener(\"keydown\", onKeyDown); source.addEventListener(\"pointerdown\", onPointerDown, { passive: true }); source.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => { delete source.dataset.matrxPaginationTouchY; source.removeEventListener(\"wheel\", onWheel); source.removeEventListener(\"touchstart\", onTouchStart); source.removeEventListener(\"touchmove\", onTouchMove); source.removeEventListener(\"touchend\", onTouchEnd); source.removeEventListener(\"touchcancel\", onTouchEnd); source.removeEventListener(\"keydown\", onKeyDown); source.removeEventListener(\"pointerdown\", onPointerDown); source.removeEventListener(\"scroll\", onScroll); };\n });\n return () => { cleanups.forEach((cleanup) => cleanup()); ownerCleanups.forEach((cleanup) => cleanup()); };\n }, [containers, enabled, intentTimeoutMs, mode]);\n\n return {\n requestNextPage,\n canLoadMore: enabled && !loading && !isFetchingNextPage && (hasNextPage || effectiveError !== null),\n error: effectiveError,\n };\n}\n"],"mappings":"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","names":[]}
@@ -28,6 +28,27 @@ function isDownwardKeyboardInput(event) {
28
28
  function isNearBottom(container, thresholdPx) {
29
29
  return container.scrollHeight - container.clientHeight - container.scrollTop <= thresholdPx;
30
30
  }
31
+ function isVerticallyScrollable(element) {
32
+ const overflowY = window.getComputedStyle(element).overflowY;
33
+ return (overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay") && element.scrollHeight > element.clientHeight;
34
+ }
35
+ function resolveScrollOwner(source) {
36
+ for (let node = source; node; node = node.parentElement) {
37
+ if (node === source && node.scrollHeight > node.clientHeight || isVerticallyScrollable(node)) {
38
+ return { element: node, document: false };
39
+ }
40
+ }
41
+ return { element: document.scrollingElement instanceof HTMLElement ? document.scrollingElement : document.documentElement, document: true };
42
+ }
43
+ function ownerScrollTop(owner) {
44
+ return owner.document ? window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0 : owner.element.scrollTop;
45
+ }
46
+ function sourceBottomIsNearOwnerViewport(source, owner, thresholdPx) {
47
+ if (!owner.document && owner.element === source) return isNearBottom(source, thresholdPx);
48
+ const sourceRect = source.getBoundingClientRect();
49
+ const ownerRect = owner.document ? { top: 0, bottom: window.innerHeight } : owner.element.getBoundingClientRect();
50
+ return sourceRect.bottom > ownerRect.top && sourceRect.top < ownerRect.bottom && sourceRect.bottom <= ownerRect.bottom + thresholdPx;
51
+ }
31
52
  function isNativeScrollbarPointer(event, container) {
32
53
  if (event.pointerType !== "mouse" || event.button !== 0 || !event.isPrimary) return false;
33
54
  const gutterWidth = container.offsetWidth - container.clientWidth;
@@ -122,84 +143,91 @@ function useScrollPagination({
122
143
  useEffect(() => {
123
144
  if (mode !== "scroll" || !enabled || typeof window === "undefined") return;
124
145
  const attachable = containers.map(resolveContainer).filter((container) => container !== null);
125
- const setIntent = (container, startTop) => {
126
- const current = latestRef.current;
127
- if (!isVisibleContainer(container) || current.loading || current.isFetchingNextPage || inFlightGenerationRef.current !== null) return;
128
- inputSequenceRef.current += 1;
129
- intentRef.current = {
130
- queryKey: latestRef.current.queryKey,
131
- container,
132
- // The compositor can advance downward before the passive input
133
- // listener, while DOM/test callers can move upward before its scroll
134
- // notification. Either way, the lower position is the only safe
135
- // baseline for proving that this downward intent caused movement.
136
- startTop: Math.min(startTop, container.scrollTop),
137
- sequence: inputSequenceRef.current,
138
- expiresAt: Date.now() + intentTimeoutMs
139
- };
140
- };
141
- const handleScroll = (container) => {
146
+ const ownerCleanups = /* @__PURE__ */ new Map();
147
+ const handleScroll = (source, owner) => {
142
148
  const intent = intentRef.current;
143
149
  const current = latestRef.current;
144
- if (!intent || intent.queryKey !== current.queryKey || intent.container !== container || Date.now() > intent.expiresAt || container.scrollTop <= intent.startTop || intent.sequence <= consumedSequenceRef.current || !isVisibleContainer(container) || !isNearBottom(container, current.thresholdPx) || !current.hasNextPage || current.loading || current.isFetchingNextPage || current.error !== null || requestErrorRef.current !== null || inFlightGenerationRef.current !== null) {
145
- return;
146
- }
150
+ if (!intent || intent.queryKey !== current.queryKey || intent.source !== source || intent.owner.element !== owner.element || intent.owner.document !== owner.document || Date.now() > intent.expiresAt || ownerScrollTop(owner) <= intent.startTop || intent.sequence <= consumedSequenceRef.current || !isVisibleContainer(source) || !sourceBottomIsNearOwnerViewport(source, owner, current.thresholdPx) || !current.hasNextPage || current.loading || current.isFetchingNextPage || current.error !== null || requestErrorRef.current !== null || inFlightGenerationRef.current !== null) return;
147
151
  consumedSequenceRef.current = intent.sequence;
148
152
  void requestNextPage();
149
153
  };
150
- const cleanups = attachable.map((container) => {
151
- if (!observedTopRef.current.has(container)) observedTopRef.current.set(container, container.scrollTop);
152
- const lastObservedTop = () => observedTopRef.current.get(container) ?? container.scrollTop;
154
+ const ensureOwnerListener = (owner) => {
155
+ if (ownerCleanups.has(owner.element)) return;
156
+ const onOwnerScroll = () => {
157
+ const intent = intentRef.current;
158
+ if (intent && intent.owner.element === owner.element && intent.owner.document === owner.document) handleScroll(intent.source, owner);
159
+ observedTopRef.current.set(owner.element, ownerScrollTop(owner));
160
+ };
161
+ if (owner.document) window.addEventListener("scroll", onOwnerScroll, { passive: true });
162
+ else owner.element.addEventListener("scroll", onOwnerScroll, { passive: true });
163
+ ownerCleanups.set(owner.element, () => {
164
+ if (owner.document) window.removeEventListener("scroll", onOwnerScroll);
165
+ else owner.element.removeEventListener("scroll", onOwnerScroll);
166
+ });
167
+ };
168
+ const setIntent = (source, startTop) => {
169
+ const current = latestRef.current;
170
+ const owner = resolveScrollOwner(source);
171
+ if (!isVisibleContainer(source) || current.loading || current.isFetchingNextPage || inFlightGenerationRef.current !== null) return;
172
+ inputSequenceRef.current += 1;
173
+ const currentOwnerTop = ownerScrollTop(owner);
174
+ const observedOwnerTop = observedTopRef.current.get(owner.element) ?? currentOwnerTop;
175
+ observedTopRef.current.set(owner.element, currentOwnerTop);
176
+ intentRef.current = { queryKey: current.queryKey, source, owner, startTop: Math.min(observedOwnerTop, currentOwnerTop), sequence: inputSequenceRef.current, expiresAt: Date.now() + intentTimeoutMs };
177
+ ensureOwnerListener(owner);
178
+ };
179
+ const cleanups = attachable.map((source) => {
180
+ if (!observedTopRef.current.has(source)) observedTopRef.current.set(source, source.scrollTop);
181
+ const lastObservedTop = () => observedTopRef.current.get(source) ?? source.scrollTop;
153
182
  const onWheel = (event) => {
154
- if (event.deltaY > 0 && Math.abs(event.deltaY) > Math.abs(event.deltaX)) {
155
- setIntent(container, lastObservedTop());
156
- }
183
+ if (event.deltaY > 0 && Math.abs(event.deltaY) > Math.abs(event.deltaX)) setIntent(source, lastObservedTop());
157
184
  };
158
185
  const onTouchStart = (event) => {
159
186
  const touch = event.touches.item(0);
160
- if (touch) container.dataset.matrxPaginationTouchY = String(touch.clientY);
187
+ if (touch) source.dataset.matrxPaginationTouchY = String(touch.clientY);
161
188
  };
162
189
  const onTouchMove = (event) => {
163
190
  const touch = event.touches.item(0);
164
- const startY = Number(container.dataset.matrxPaginationTouchY);
165
- if (touch && Number.isFinite(startY) && startY - touch.clientY > 0) {
166
- setIntent(container, lastObservedTop());
167
- }
191
+ const startY = Number(source.dataset.matrxPaginationTouchY);
192
+ if (touch && Number.isFinite(startY) && startY - touch.clientY > 0) setIntent(source, lastObservedTop());
168
193
  };
169
194
  const onTouchEnd = () => {
170
- delete container.dataset.matrxPaginationTouchY;
195
+ delete source.dataset.matrxPaginationTouchY;
171
196
  };
172
197
  const onKeyDown = (event) => {
173
- if (isDownwardKeyboardInput(event)) setIntent(container, lastObservedTop());
198
+ if (isDownwardKeyboardInput(event)) setIntent(source, lastObservedTop());
174
199
  };
175
200
  const onPointerDown = (event) => {
176
- if (isNativeScrollbarPointer(event, container)) setIntent(container, lastObservedTop());
201
+ if (isNativeScrollbarPointer(event, source)) setIntent(source, lastObservedTop());
177
202
  };
178
203
  const onScroll = () => {
179
- handleScroll(container);
180
- observedTopRef.current.set(container, container.scrollTop);
204
+ handleScroll(source, { element: source, document: false });
205
+ observedTopRef.current.set(source, source.scrollTop);
181
206
  };
182
- container.addEventListener("wheel", onWheel, { passive: true });
183
- container.addEventListener("touchstart", onTouchStart, { passive: true });
184
- container.addEventListener("touchmove", onTouchMove, { passive: true });
185
- container.addEventListener("touchend", onTouchEnd, { passive: true });
186
- container.addEventListener("touchcancel", onTouchEnd, { passive: true });
187
- container.addEventListener("keydown", onKeyDown);
188
- container.addEventListener("pointerdown", onPointerDown, { passive: true });
189
- container.addEventListener("scroll", onScroll, { passive: true });
207
+ source.addEventListener("wheel", onWheel, { passive: true });
208
+ source.addEventListener("touchstart", onTouchStart, { passive: true });
209
+ source.addEventListener("touchmove", onTouchMove, { passive: true });
210
+ source.addEventListener("touchend", onTouchEnd, { passive: true });
211
+ source.addEventListener("touchcancel", onTouchEnd, { passive: true });
212
+ source.addEventListener("keydown", onKeyDown);
213
+ source.addEventListener("pointerdown", onPointerDown, { passive: true });
214
+ source.addEventListener("scroll", onScroll, { passive: true });
190
215
  return () => {
191
- delete container.dataset.matrxPaginationTouchY;
192
- container.removeEventListener("wheel", onWheel);
193
- container.removeEventListener("touchstart", onTouchStart);
194
- container.removeEventListener("touchmove", onTouchMove);
195
- container.removeEventListener("touchend", onTouchEnd);
196
- container.removeEventListener("touchcancel", onTouchEnd);
197
- container.removeEventListener("keydown", onKeyDown);
198
- container.removeEventListener("pointerdown", onPointerDown);
199
- container.removeEventListener("scroll", onScroll);
216
+ delete source.dataset.matrxPaginationTouchY;
217
+ source.removeEventListener("wheel", onWheel);
218
+ source.removeEventListener("touchstart", onTouchStart);
219
+ source.removeEventListener("touchmove", onTouchMove);
220
+ source.removeEventListener("touchend", onTouchEnd);
221
+ source.removeEventListener("touchcancel", onTouchEnd);
222
+ source.removeEventListener("keydown", onKeyDown);
223
+ source.removeEventListener("pointerdown", onPointerDown);
224
+ source.removeEventListener("scroll", onScroll);
200
225
  };
201
226
  });
202
- return () => cleanups.forEach((cleanup) => cleanup());
227
+ return () => {
228
+ cleanups.forEach((cleanup) => cleanup());
229
+ ownerCleanups.forEach((cleanup) => cleanup());
230
+ };
203
231
  }, [containers, enabled, intentTimeoutMs, mode]);
204
232
  return {
205
233
  requestNextPage,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/data-table/useScrollPagination.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport type ScrollPaginationContainer =\n | HTMLElement\n | RefObject<HTMLElement | null>\n | null;\n\nexport interface UseScrollPaginationOptions {\n /** Every visible desktop/mobile scroll container that may present this table. */\n containers: readonly ScrollPaginationContainer[];\n /** Immutable identity of every source-affecting query value. */\n queryKey: string;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n loading: boolean;\n /** Automatic scrolling never retries a failed append. */\n error: Error | null;\n loadNextPage: () => Promise<void> | void;\n /** Manual mode exposes the explicit request only; it installs no listeners. */\n mode?: \"scroll\" | \"manual\";\n /** Distance from the bottom at which a qualifying user scroll may append. */\n thresholdPx?: number;\n /** How long an input may authorize the following real scroll movement. */\n intentTimeoutMs?: number;\n enabled?: boolean;\n}\n\nexport interface UseScrollPaginationResult {\n /** For the table's accessible Load more / Retry control. */\n requestNextPage: () => Promise<void>;\n canLoadMore: boolean;\n /** Includes an unexpected loader rejection until the person explicitly retries. */\n error: Error | null;\n}\n\ninterface ScrollIntent {\n queryKey: string;\n container: HTMLElement;\n startTop: number;\n sequence: number;\n expiresAt: number;\n}\n\nconst DEFAULT_THRESHOLD_PX = 96;\nconst DEFAULT_INTENT_TIMEOUT_MS = 1_200;\n\nfunction resolveContainer(container: ScrollPaginationContainer): HTMLElement | null {\n if (!container) return null;\n return container instanceof HTMLElement ? container : container.current;\n}\n\nfunction isVisibleContainer(container: HTMLElement): boolean {\n if (!container.isConnected) return false;\n for (let node: HTMLElement | null = container; node; node = node.parentElement) {\n const style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\") return false;\n }\n return true;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return target.isContentEditable || Boolean(target.closest(\"input, textarea, select, [contenteditable='true']\"));\n}\n\nfunction isDownwardKeyboardInput(event: KeyboardEvent): boolean {\n if (isEditableTarget(event.target)) return false;\n return [\"ArrowDown\", \"PageDown\", \"End\", \" \", \"Spacebar\"].includes(event.key);\n}\n\nfunction isNearBottom(container: HTMLElement, thresholdPx: number): boolean {\n return container.scrollHeight - container.clientHeight - container.scrollTop <= thresholdPx;\n}\n\nfunction isNativeScrollbarPointer(event: PointerEvent, container: HTMLElement): boolean {\n // Overlay scrollbars expose no measurable gutter. Do not guess: Load more is\n // the accessible, reliable fallback there. A content click must never grant\n // permission for a later programmatic scroll to append rows.\n if (event.pointerType !== \"mouse\" || event.button !== 0 || !event.isPrimary) return false;\n const gutterWidth = container.offsetWidth - container.clientWidth;\n if (gutterWidth <= 0 || container.scrollHeight <= container.clientHeight) return false;\n const rect = container.getBoundingClientRect();\n return event.clientX >= rect.right - gutterWidth && event.clientX <= rect.right;\n}\n\n/**\n * Gates automatic append behind a fresh, real downward user scroll. The hook\n * owns neither fetching nor row state: callers feed it the data hook receipt\n * and render its explicit request as the accessible fallback control.\n */\nexport function useScrollPagination({\n containers,\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode = \"scroll\",\n thresholdPx = DEFAULT_THRESHOLD_PX,\n intentTimeoutMs = DEFAULT_INTENT_TIMEOUT_MS,\n enabled = true,\n}: UseScrollPaginationOptions): UseScrollPaginationResult {\n const [requestError, setRequestError] = useState<Error | null>(null);\n const latestRef = useRef({\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n });\n latestRef.current = {\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n };\n\n const intentRef = useRef<ScrollIntent | null>(null);\n const inputSequenceRef = useRef(0);\n const consumedSequenceRef = useRef(0);\n const requestGenerationRef = useRef(0);\n const inFlightGenerationRef = useRef<number | null>(null);\n const requestErrorRef = useRef<Error | null>(null);\n const mountedRef = useRef(false);\n // Listener effects reattach when consumers recreate their container arrays.\n // Keep the last real scroll position with the element, not with one effect.\n const observedTopRef = useRef<WeakMap<HTMLElement, number>>(new WeakMap());\n const effectiveError = error ?? requestError;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const requestNextPage = async () => {\n const current = latestRef.current;\n if (\n !current.enabled ||\n (!current.hasNextPage && effectiveError === null) ||\n current.loading ||\n current.isFetchingNextPage ||\n inFlightGenerationRef.current !== null\n ) {\n return;\n }\n const generation = ++requestGenerationRef.current;\n inFlightGenerationRef.current = generation;\n requestErrorRef.current = null;\n setRequestError(null);\n try {\n await current.loadNextPage();\n } catch (raw) {\n const nextError = raw instanceof Error ? raw : new Error(String(raw));\n if (inFlightGenerationRef.current === generation && latestRef.current.queryKey === current.queryKey) {\n requestErrorRef.current = nextError;\n if (mountedRef.current) setRequestError(nextError);\n }\n } finally {\n if (inFlightGenerationRef.current === generation) {\n inFlightGenerationRef.current = null;\n intentRef.current = null;\n }\n }\n };\n\n useEffect(() => {\n intentRef.current = null;\n observedTopRef.current = new WeakMap();\n consumedSequenceRef.current = inputSequenceRef.current;\n requestErrorRef.current = null;\n setRequestError(null);\n // A query change makes every existing completion stale. Its finally block\n // cannot clear a new request because generations are monotonically unique.\n inFlightGenerationRef.current = null;\n requestGenerationRef.current += 1;\n }, [queryKey]);\n\n useEffect(() => {\n if (mode !== \"scroll\" || !enabled || typeof window === \"undefined\") return;\n\n const attachable = containers\n .map(resolveContainer)\n .filter((container): container is HTMLElement => container !== null);\n\n const setIntent = (container: HTMLElement, startTop: number) => {\n const current = latestRef.current;\n if (!isVisibleContainer(container) || current.loading || current.isFetchingNextPage || inFlightGenerationRef.current !== null) return;\n inputSequenceRef.current += 1;\n intentRef.current = {\n queryKey: latestRef.current.queryKey,\n container,\n // The compositor can advance downward before the passive input\n // listener, while DOM/test callers can move upward before its scroll\n // notification. Either way, the lower position is the only safe\n // baseline for proving that this downward intent caused movement.\n startTop: Math.min(startTop, container.scrollTop),\n sequence: inputSequenceRef.current,\n expiresAt: Date.now() + intentTimeoutMs,\n };\n };\n\n const handleScroll = (container: HTMLElement) => {\n const intent = intentRef.current;\n const current = latestRef.current;\n if (\n !intent ||\n intent.queryKey !== current.queryKey ||\n intent.container !== container ||\n Date.now() > intent.expiresAt ||\n container.scrollTop <= intent.startTop ||\n intent.sequence <= consumedSequenceRef.current ||\n !isVisibleContainer(container) ||\n !isNearBottom(container, current.thresholdPx) ||\n !current.hasNextPage ||\n current.loading ||\n current.isFetchingNextPage ||\n current.error !== null ||\n requestErrorRef.current !== null ||\n inFlightGenerationRef.current !== null\n ) {\n return;\n }\n consumedSequenceRef.current = intent.sequence;\n void requestNextPage();\n };\n\n const cleanups = attachable.map((container) => {\n // A passive wheel listener may run after the compositor has already\n // advanced scrollTop, but before the asynchronous scroll notification.\n // Preserve the last *observed* position so that ordering still proves\n // movement from this trusted input without authorizing scroll-only code.\n if (!observedTopRef.current.has(container)) observedTopRef.current.set(container, container.scrollTop);\n const lastObservedTop = () => observedTopRef.current.get(container) ?? container.scrollTop;\n const onWheel = (event: WheelEvent) => {\n if (event.deltaY > 0 && Math.abs(event.deltaY) > Math.abs(event.deltaX)) {\n setIntent(container, lastObservedTop());\n }\n };\n const onTouchStart = (event: TouchEvent) => {\n const touch = event.touches.item(0);\n if (touch) container.dataset.matrxPaginationTouchY = String(touch.clientY);\n };\n const onTouchMove = (event: TouchEvent) => {\n const touch = event.touches.item(0);\n const startY = Number(container.dataset.matrxPaginationTouchY);\n if (touch && Number.isFinite(startY) && startY - touch.clientY > 0) {\n setIntent(container, lastObservedTop());\n }\n };\n const onTouchEnd = () => {\n delete container.dataset.matrxPaginationTouchY;\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (isDownwardKeyboardInput(event)) setIntent(container, lastObservedTop());\n };\n const onPointerDown = (event: PointerEvent) => {\n if (isNativeScrollbarPointer(event, container)) setIntent(container, lastObservedTop());\n };\n const onScroll = () => {\n handleScroll(container);\n observedTopRef.current.set(container, container.scrollTop);\n };\n\n container.addEventListener(\"wheel\", onWheel, { passive: true });\n container.addEventListener(\"touchstart\", onTouchStart, { passive: true });\n container.addEventListener(\"touchmove\", onTouchMove, { passive: true });\n container.addEventListener(\"touchend\", onTouchEnd, { passive: true });\n container.addEventListener(\"touchcancel\", onTouchEnd, { passive: true });\n container.addEventListener(\"keydown\", onKeyDown);\n container.addEventListener(\"pointerdown\", onPointerDown, { passive: true });\n container.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => {\n delete container.dataset.matrxPaginationTouchY;\n container.removeEventListener(\"wheel\", onWheel);\n container.removeEventListener(\"touchstart\", onTouchStart);\n container.removeEventListener(\"touchmove\", onTouchMove);\n container.removeEventListener(\"touchend\", onTouchEnd);\n container.removeEventListener(\"touchcancel\", onTouchEnd);\n container.removeEventListener(\"keydown\", onKeyDown);\n container.removeEventListener(\"pointerdown\", onPointerDown);\n container.removeEventListener(\"scroll\", onScroll);\n };\n });\n return () => cleanups.forEach((cleanup) => cleanup());\n }, [containers, enabled, intentTimeoutMs, mode]);\n\n return {\n requestNextPage,\n canLoadMore: enabled && !loading && !isFetchingNextPage && (hasNextPage || effectiveError !== null),\n error: effectiveError,\n };\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/data-table/useScrollPagination.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport type { RefObject } from \"react\";\n\nexport type ScrollPaginationContainer =\n | HTMLElement\n | RefObject<HTMLElement | null>\n | null;\n\nexport interface UseScrollPaginationOptions {\n /** Every visible desktop/mobile scroll container that may present this table. */\n containers: readonly ScrollPaginationContainer[];\n /** Immutable identity of every source-affecting query value. */\n queryKey: string;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n loading: boolean;\n /** Automatic scrolling never retries a failed append. */\n error: Error | null;\n loadNextPage: () => Promise<void> | void;\n /** Manual mode exposes the explicit request only; it installs no listeners. */\n mode?: \"scroll\" | \"manual\";\n /** Distance from the bottom at which a qualifying user scroll may append. */\n thresholdPx?: number;\n /** How long an input may authorize the following real scroll movement. */\n intentTimeoutMs?: number;\n enabled?: boolean;\n}\n\nexport interface UseScrollPaginationResult {\n /** For the table's accessible Load more / Retry control. */\n requestNextPage: () => Promise<void>;\n canLoadMore: boolean;\n /** Includes an unexpected loader rejection until the person explicitly retries. */\n error: Error | null;\n}\n\ninterface ScrollOwner { element: HTMLElement; document: boolean; }\ninterface ScrollIntent {\n queryKey: string;\n source: HTMLElement;\n owner: ScrollOwner;\n startTop: number;\n sequence: number;\n expiresAt: number;\n}\n\nconst DEFAULT_THRESHOLD_PX = 96;\nconst DEFAULT_INTENT_TIMEOUT_MS = 1_200;\n\nfunction resolveContainer(container: ScrollPaginationContainer): HTMLElement | null {\n if (!container) return null;\n return container instanceof HTMLElement ? container : container.current;\n}\n\nfunction isVisibleContainer(container: HTMLElement): boolean {\n if (!container.isConnected) return false;\n for (let node: HTMLElement | null = container; node; node = node.parentElement) {\n const style = window.getComputedStyle(node);\n if (style.display === \"none\" || style.visibility === \"hidden\") return false;\n }\n return true;\n}\n\nfunction isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n return target.isContentEditable || Boolean(target.closest(\"input, textarea, select, [contenteditable='true']\"));\n}\n\nfunction isDownwardKeyboardInput(event: KeyboardEvent): boolean {\n if (isEditableTarget(event.target)) return false;\n return [\"ArrowDown\", \"PageDown\", \"End\", \" \", \"Spacebar\"].includes(event.key);\n}\n\nfunction isNearBottom(container: HTMLElement, thresholdPx: number): boolean {\n return container.scrollHeight - container.clientHeight - container.scrollTop <= thresholdPx;\n}\n\nfunction isVerticallyScrollable(element: HTMLElement): boolean {\n const overflowY = window.getComputedStyle(element).overflowY;\n return (overflowY === \"auto\" || overflowY === \"scroll\" || overflowY === \"overlay\") && element.scrollHeight > element.clientHeight;\n}\nfunction resolveScrollOwner(source: HTMLElement): ScrollOwner {\n for (let node: HTMLElement | null = source; node; node = node.parentElement) {\n if ((node === source && node.scrollHeight > node.clientHeight) || isVerticallyScrollable(node)) {\n return { element: node, document: false };\n }\n }\n return { element: document.scrollingElement instanceof HTMLElement ? document.scrollingElement : document.documentElement, document: true };\n}\nfunction ownerScrollTop(owner: ScrollOwner): number {\n return owner.document\n ? window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0\n : owner.element.scrollTop;\n}\nfunction sourceBottomIsNearOwnerViewport(source: HTMLElement, owner: ScrollOwner, thresholdPx: number): boolean {\n if (!owner.document && owner.element === source) return isNearBottom(source, thresholdPx);\n const sourceRect = source.getBoundingClientRect();\n const ownerRect = owner.document ? { top: 0, bottom: window.innerHeight } : owner.element.getBoundingClientRect();\n return sourceRect.bottom > ownerRect.top && sourceRect.top < ownerRect.bottom && sourceRect.bottom <= ownerRect.bottom + thresholdPx;\n}\n\nfunction isNativeScrollbarPointer(event: PointerEvent, container: HTMLElement): boolean {\n // Overlay scrollbars expose no measurable gutter. Do not guess: Load more is\n // the accessible, reliable fallback there. A content click must never grant\n // permission for a later programmatic scroll to append rows.\n if (event.pointerType !== \"mouse\" || event.button !== 0 || !event.isPrimary) return false;\n const gutterWidth = container.offsetWidth - container.clientWidth;\n if (gutterWidth <= 0 || container.scrollHeight <= container.clientHeight) return false;\n const rect = container.getBoundingClientRect();\n return event.clientX >= rect.right - gutterWidth && event.clientX <= rect.right;\n}\n\n/**\n * Gates automatic append behind a fresh, real downward user scroll. The hook\n * owns neither fetching nor row state: callers feed it the data hook receipt\n * and render its explicit request as the accessible fallback control.\n */\nexport function useScrollPagination({\n containers,\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode = \"scroll\",\n thresholdPx = DEFAULT_THRESHOLD_PX,\n intentTimeoutMs = DEFAULT_INTENT_TIMEOUT_MS,\n enabled = true,\n}: UseScrollPaginationOptions): UseScrollPaginationResult {\n const [requestError, setRequestError] = useState<Error | null>(null);\n const latestRef = useRef({\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n });\n latestRef.current = {\n queryKey,\n hasNextPage,\n isFetchingNextPage,\n loading,\n error,\n loadNextPage,\n mode,\n thresholdPx,\n enabled,\n };\n\n const intentRef = useRef<ScrollIntent | null>(null);\n const inputSequenceRef = useRef(0);\n const consumedSequenceRef = useRef(0);\n const requestGenerationRef = useRef(0);\n const inFlightGenerationRef = useRef<number | null>(null);\n const requestErrorRef = useRef<Error | null>(null);\n const mountedRef = useRef(false);\n // Listener effects reattach when consumers recreate their container arrays.\n // Keep the last real scroll position with the element, not with one effect.\n const observedTopRef = useRef<WeakMap<HTMLElement, number>>(new WeakMap());\n const effectiveError = error ?? requestError;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const requestNextPage = async () => {\n const current = latestRef.current;\n if (\n !current.enabled ||\n (!current.hasNextPage && effectiveError === null) ||\n current.loading ||\n current.isFetchingNextPage ||\n inFlightGenerationRef.current !== null\n ) {\n return;\n }\n const generation = ++requestGenerationRef.current;\n inFlightGenerationRef.current = generation;\n requestErrorRef.current = null;\n setRequestError(null);\n try {\n await current.loadNextPage();\n } catch (raw) {\n const nextError = raw instanceof Error ? raw : new Error(String(raw));\n if (inFlightGenerationRef.current === generation && latestRef.current.queryKey === current.queryKey) {\n requestErrorRef.current = nextError;\n if (mountedRef.current) setRequestError(nextError);\n }\n } finally {\n if (inFlightGenerationRef.current === generation) {\n inFlightGenerationRef.current = null;\n intentRef.current = null;\n }\n }\n };\n\n useEffect(() => {\n intentRef.current = null;\n observedTopRef.current = new WeakMap();\n consumedSequenceRef.current = inputSequenceRef.current;\n requestErrorRef.current = null;\n setRequestError(null);\n // A query change makes every existing completion stale. Its finally block\n // cannot clear a new request because generations are monotonically unique.\n inFlightGenerationRef.current = null;\n requestGenerationRef.current += 1;\n }, [queryKey]);\n\n useEffect(() => {\n if (mode !== \"scroll\" || !enabled || typeof window === \"undefined\") return;\n const attachable = containers.map(resolveContainer).filter((container): container is HTMLElement => container !== null);\n const ownerCleanups = new Map<HTMLElement, () => void>();\n const handleScroll = (source: HTMLElement, owner: ScrollOwner) => {\n const intent = intentRef.current;\n const current = latestRef.current;\n if (!intent || intent.queryKey !== current.queryKey || intent.source !== source || intent.owner.element !== owner.element || intent.owner.document !== owner.document || Date.now() > intent.expiresAt || ownerScrollTop(owner) <= intent.startTop || intent.sequence <= consumedSequenceRef.current || !isVisibleContainer(source) || !sourceBottomIsNearOwnerViewport(source, owner, current.thresholdPx) || !current.hasNextPage || current.loading || current.isFetchingNextPage || current.error !== null || requestErrorRef.current !== null || inFlightGenerationRef.current !== null) return;\n consumedSequenceRef.current = intent.sequence;\n void requestNextPage();\n };\n const ensureOwnerListener = (owner: ScrollOwner) => {\n if (ownerCleanups.has(owner.element)) return;\n const onOwnerScroll = () => {\n const intent = intentRef.current;\n if (intent && intent.owner.element === owner.element && intent.owner.document === owner.document) handleScroll(intent.source, owner);\n observedTopRef.current.set(owner.element, ownerScrollTop(owner));\n };\n if (owner.document) window.addEventListener(\"scroll\", onOwnerScroll, { passive: true });\n else owner.element.addEventListener(\"scroll\", onOwnerScroll, { passive: true });\n ownerCleanups.set(owner.element, () => {\n if (owner.document) window.removeEventListener(\"scroll\", onOwnerScroll);\n else owner.element.removeEventListener(\"scroll\", onOwnerScroll);\n });\n };\n const setIntent = (source: HTMLElement, startTop: number) => {\n const current = latestRef.current;\n const owner = resolveScrollOwner(source);\n if (!isVisibleContainer(source) || current.loading || current.isFetchingNextPage || inFlightGenerationRef.current !== null) return;\n inputSequenceRef.current += 1;\n const currentOwnerTop = ownerScrollTop(owner);\n const observedOwnerTop = observedTopRef.current.get(owner.element) ?? currentOwnerTop;\n observedTopRef.current.set(owner.element, currentOwnerTop);\n intentRef.current = { queryKey: current.queryKey, source, owner, startTop: Math.min(observedOwnerTop, currentOwnerTop), sequence: inputSequenceRef.current, expiresAt: Date.now() + intentTimeoutMs };\n ensureOwnerListener(owner);\n };\n const cleanups = attachable.map((source) => {\n if (!observedTopRef.current.has(source)) observedTopRef.current.set(source, source.scrollTop);\n const lastObservedTop = () => observedTopRef.current.get(source) ?? source.scrollTop;\n const onWheel = (event: WheelEvent) => { if (event.deltaY > 0 && Math.abs(event.deltaY) > Math.abs(event.deltaX)) setIntent(source, lastObservedTop()); };\n const onTouchStart = (event: TouchEvent) => { const touch = event.touches.item(0); if (touch) source.dataset.matrxPaginationTouchY = String(touch.clientY); };\n const onTouchMove = (event: TouchEvent) => { const touch = event.touches.item(0); const startY = Number(source.dataset.matrxPaginationTouchY); if (touch && Number.isFinite(startY) && startY - touch.clientY > 0) setIntent(source, lastObservedTop()); };\n const onTouchEnd = () => { delete source.dataset.matrxPaginationTouchY; };\n const onKeyDown = (event: KeyboardEvent) => { if (isDownwardKeyboardInput(event)) setIntent(source, lastObservedTop()); };\n const onPointerDown = (event: PointerEvent) => { if (isNativeScrollbarPointer(event, source)) setIntent(source, lastObservedTop()); };\n const onScroll = () => { handleScroll(source, { element: source, document: false }); observedTopRef.current.set(source, source.scrollTop); };\n source.addEventListener(\"wheel\", onWheel, { passive: true }); source.addEventListener(\"touchstart\", onTouchStart, { passive: true }); source.addEventListener(\"touchmove\", onTouchMove, { passive: true }); source.addEventListener(\"touchend\", onTouchEnd, { passive: true }); source.addEventListener(\"touchcancel\", onTouchEnd, { passive: true }); source.addEventListener(\"keydown\", onKeyDown); source.addEventListener(\"pointerdown\", onPointerDown, { passive: true }); source.addEventListener(\"scroll\", onScroll, { passive: true });\n return () => { delete source.dataset.matrxPaginationTouchY; source.removeEventListener(\"wheel\", onWheel); source.removeEventListener(\"touchstart\", onTouchStart); source.removeEventListener(\"touchmove\", onTouchMove); source.removeEventListener(\"touchend\", onTouchEnd); source.removeEventListener(\"touchcancel\", onTouchEnd); source.removeEventListener(\"keydown\", onKeyDown); source.removeEventListener(\"pointerdown\", onPointerDown); source.removeEventListener(\"scroll\", onScroll); };\n });\n return () => { cleanups.forEach((cleanup) => cleanup()); ownerCleanups.forEach((cleanup) => cleanup()); };\n }, [containers, enabled, intentTimeoutMs, mode]);\n\n return {\n requestNextPage,\n canLoadMore: enabled && !loading && !isFetchingNextPage && (hasNextPage || effectiveError !== null),\n error: effectiveError,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,3 +1,3 @@
1
1
  import 'react';
2
- export { A as AnyOfColumnSearch, d as CellEditType, e as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, g as MatrxDataTableCopyConfig, h as MatrxDataTableDetailConfig, i as MatrxDataTableEditConfig, j as MatrxDataTableEmptyState, k as MatrxDataTableFilterUi, l as MatrxDataTableHierarchyConfig, m as MatrxDataTableHierarchyMove, n as MatrxDataTableMobileCardControls, b as MatrxDataTableProps, o as MatrxDataTableQueryControl, p as MatrxDataTableQueryState, q as MatrxDataTableRecordControls, r as MatrxDataTableSelectionConfig, s as MatrxDataTableSourceProcessing, t as MatrxDataTableToolbar, u as MatrxDataTableUrlStateConfig, v as MatrxDataTableWindowConfig, w as MatrxTablePagination, x as SortDirection, S as SortState, y as TableSavedViewsProps, T as TableSearchMatchMode, z as TableViewQuery, c as TableViewSnapshot, B as TextFilterMode, D as ToolbarFacet } from '../types-CWW4Tur-.cjs';
2
+ export { A as AnyOfColumnSearch, h as CellEditType, i as CellEditsMap, d as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, e as MatrxDataTableCopyConfig, j as MatrxDataTableDetailConfig, k as MatrxDataTableEditConfig, l as MatrxDataTableEmptyState, m as MatrxDataTableFilterUi, n as MatrxDataTableHierarchyConfig, o as MatrxDataTableHierarchyMove, p as MatrxDataTableMobileCardControls, f as MatrxDataTableProps, q as MatrxDataTableQueryControl, c as MatrxDataTableQueryState, r as MatrxDataTableRecordControls, s as MatrxDataTableSelectionConfig, t as MatrxDataTableSourceProcessing, u as MatrxDataTableToolbar, v as MatrxDataTableUrlStateConfig, w as MatrxDataTableWindowConfig, x as MatrxTablePagination, y as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, z as TableViewQuery, g as TableViewSnapshot, B as TextFilterMode, D as ToolbarFacet } from '../types-Di6QT0P1.cjs';
3
3
  export { AgentPayloadInput } from './copy-types.cjs';
@@ -1,3 +1,3 @@
1
1
  import 'react';
2
- export { A as AnyOfColumnSearch, d as CellEditType, e as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, g as MatrxDataTableCopyConfig, h as MatrxDataTableDetailConfig, i as MatrxDataTableEditConfig, j as MatrxDataTableEmptyState, k as MatrxDataTableFilterUi, l as MatrxDataTableHierarchyConfig, m as MatrxDataTableHierarchyMove, n as MatrxDataTableMobileCardControls, b as MatrxDataTableProps, o as MatrxDataTableQueryControl, p as MatrxDataTableQueryState, q as MatrxDataTableRecordControls, r as MatrxDataTableSelectionConfig, s as MatrxDataTableSourceProcessing, t as MatrxDataTableToolbar, u as MatrxDataTableUrlStateConfig, v as MatrxDataTableWindowConfig, w as MatrxTablePagination, x as SortDirection, S as SortState, y as TableSavedViewsProps, T as TableSearchMatchMode, z as TableViewQuery, c as TableViewSnapshot, B as TextFilterMode, D as ToolbarFacet } from '../types-Cbnj1Qlm.js';
2
+ export { A as AnyOfColumnSearch, h as CellEditType, i as CellEditsMap, d as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, e as MatrxDataTableCopyConfig, j as MatrxDataTableDetailConfig, k as MatrxDataTableEditConfig, l as MatrxDataTableEmptyState, m as MatrxDataTableFilterUi, n as MatrxDataTableHierarchyConfig, o as MatrxDataTableHierarchyMove, p as MatrxDataTableMobileCardControls, f as MatrxDataTableProps, q as MatrxDataTableQueryControl, c as MatrxDataTableQueryState, r as MatrxDataTableRecordControls, s as MatrxDataTableSelectionConfig, t as MatrxDataTableSourceProcessing, u as MatrxDataTableToolbar, v as MatrxDataTableUrlStateConfig, w as MatrxDataTableWindowConfig, x as MatrxTablePagination, y as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, z as TableViewQuery, g as TableViewSnapshot, B as TextFilterMode, D as ToolbarFacet } from '../types-D1m14boM.js';
3
3
  export { AgentPayloadInput } from './copy-types.js';
@@ -1,4 +1,4 @@
1
- import { S as SortState, p as MatrxDataTableQueryState } from '../types-CWW4Tur-.cjs';
1
+ import { S as SortState, c as MatrxDataTableQueryState } from '../types-Di6QT0P1.cjs';
2
2
  import { UrlHistoryMode } from '@ai-matrx/kit/url-state';
3
3
  import 'react';
4
4
  import './copy-types.cjs';
@@ -1,4 +1,4 @@
1
- import { S as SortState, p as MatrxDataTableQueryState } from '../types-Cbnj1Qlm.js';
1
+ import { S as SortState, c as MatrxDataTableQueryState } from '../types-D1m14boM.js';
2
2
  import { UrlHistoryMode } from '@ai-matrx/kit/url-state';
3
3
  import 'react';
4
4
  import './copy-types.js';
@@ -41,7 +41,7 @@ var import_react3 = require("react");
41
41
  // src/data-table/icons.tsx
42
42
  var import_jsx_runtime = require("react/jsx-runtime");
43
43
  function Icon({ children, ...props }) {
44
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", ...props, children });
44
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children });
45
45
  }
46
46
  var Check = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m5 12 4 4L19 6" }) });
47
47
  var PanelRight = (p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Icon, { ...p, children: [