@aiquants/virtualscroll 1.0.0 → 1.2.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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/TapScrollCircle.tsx","../src/utils.ts","../src/ScrollBar.tsx","../src/logger.ts","../src/ScrollPane.tsx","../src/tapScrollCircleSampleVisual.tsx","../src/useFenwickMapTree.ts","../src/useLruCache.ts","../src/useHeightCache.ts","../src/VirtualScroll.tsx"],"sourcesContent":["/**\n * Provides a touch-friendly tap circle for continuous scrolling interactions.\n * タッチ操作向けのタップサークルを提供し、連続スクロール操作を実現するモジュール。\n */\n\nimport type { CSSProperties, ReactNode, PointerEvent as ReactPointerEvent } from \"react\"\nimport { forwardRef, useCallback, useImperativeHandle, useRef, useState } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport type TapScrollCircleDragState = {\n /** Whether the pointer is actively dragging. / ポインターがドラッグ中かどうか。 */\n active: boolean\n /** Signed horizontal offset from the circle center. / サークル中心からの符号付き水平方向オフセット。 */\n offsetX: number\n /** Signed vertical offset from the circle center. / サークル中心からの符号付き垂直オフセット。 */\n offsetY: number\n /** Absolute distance between pointer and center. / ポインターと中心の距離。 */\n distance: number\n /** Drag direction relative to the circle. / サークルに対するドラッグ方向。 */\n direction: -1 | 0 | 1\n}\n\nexport type TapScrollCircleProps = {\n /** Called whenever the drag state updates. / ドラッグ状態が更新された際に呼び出されるコールバック。 */\n onDragChange: (state: TapScrollCircleDragState) => void\n /** Additional class names for styling. / 追加のスタイル用クラス名。 */\n className?: string\n /** Maximum distance used for visual stretching. / 視覚的な伸縮に使用する最大距離。 */\n maxVisualDistance?: number\n /** Diameter of the circle in pixels. / サークルの直径 (ピクセル)。 */\n size?: number\n /** Additional inline styles. / 追加のインラインスタイル。 */\n style?: CSSProperties\n /** Base opacity applied to the circle. / サークル全体に適用する基準透明度。 */\n opacity: number\n /** Custom rendering logic for the visual contents. / ビジュアル内容を描画するカスタムロジック。 */\n renderVisual?: (props: TapScrollCircleRenderProps) => ReactNode\n}\n\nexport type TapScrollCircleHandle = {\n /**\n * Resets the drag state and releases pointer capture if active.\n *\n * ドラッグ状態をリセットし、必要に応じてポインタキャプチャを解除する。\n */\n reset: () => void\n /**\n * Returns the underlying DOM element of the tap circle.\n *\n * タップサークルの DOM 要素を返す。\n */\n getElement: () => HTMLDivElement | null\n}\n\nconst INITIAL_STATE: TapScrollCircleDragState = {\n active: false,\n offsetX: 0,\n offsetY: 0,\n distance: 0,\n direction: 0,\n}\n\nconst DEAD_ZONE = 6\n\nexport type TapScrollCircleRenderProps = {\n /** Current drag state snapshot. / 現在のドラッグ状態のスナップショット。 */\n dragState: TapScrollCircleDragState\n /** Normalized distance within [0, 1]. / 正規化距離 (0 から 1 の範囲)。 */\n normalizedDistance: number\n /** Relative scale based on size. / サイズに基づく相対スケール。 */\n sizeScale: number\n /** Circle diameter in pixels. / サークル直径 (ピクセル)。 */\n size: number\n /** Applied opacity value. / 適用中の不透明度値。 */\n opacity: number\n}\n\nconst defaultRenderVisual = ({ dragState, normalizedDistance }: TapScrollCircleRenderProps) => {\n const scale = 1 + normalizedDistance * 0.18\n const glow = 0.16 + normalizedDistance * 0.24\n const innerOpacity = 0.38 + normalizedDistance * 0.28\n const baseTransition = dragState.active ? \"80ms ease-out\" : \"220ms ease\"\n\n return (\n <>\n <div\n className=\"absolute inset-0 rounded-full\"\n style={{\n background: \"linear-gradient(140deg, rgba(255,255,255,0.62), rgba(72,72,72,0.48))\",\n boxShadow: `0 0 0 1px rgba(255,255,255,0.28), 0 10px 22px rgba(0,0,0,${glow})`,\n transform: `scale(${scale})`,\n transition: `${baseTransition}, ${dragState.active ? \"80ms\" : \"260ms\"} box-shadow ease`,\n }}\n />\n <div\n className=\"absolute inset-[18%] rounded-full\"\n style={{\n background: \"linear-gradient(140deg, rgba(255,255,255,0.72), rgba(28,28,28,0.58))\",\n boxShadow: \"inset 0 4px 10px rgba(0,0,0,0.24), inset 0 0 2px rgba(255,255,255,0.55)\",\n opacity: innerOpacity,\n transition: dragState.active ? \"120ms opacity ease-out\" : \"220ms opacity ease\",\n }}\n />\n </>\n )\n}\n\n/**\n * A circular touch handle that stretches toward the drag direction.\n * タップした方向へ伸縮するタッチ操作用サークル。\n */\nexport const TapScrollCircle = forwardRef<TapScrollCircleHandle, TapScrollCircleProps>(({ onDragChange, className, maxVisualDistance = 160, size = 40, style, opacity = 1, renderVisual }, ref) => {\n const [dragState, setDragState] = useState<TapScrollCircleDragState>(INITIAL_STATE)\n const pointerIdRef = useRef<number | null>(null)\n const centerRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 })\n const rootRef = useRef<HTMLDivElement>(null)\n\n /**\n * Updates drag state and notifies listeners.\n *\n * ドラッグ状態を更新してリスナーに通知。\n */\n const applyDragState = useCallback((nextState: TapScrollCircleDragState) => {\n setDragState(nextState)\n onDragChange(nextState)\n }, [onDragChange])\n\n const updateDragState = useCallback(\n (clientX: number, clientY: number, capture: boolean = false) => {\n const { x, y } = centerRef.current\n const offsetX = clientX - x\n const offsetY = clientY - y\n const distance = Math.abs(offsetY)\n const direction: -1 | 0 | 1 = distance < DEAD_ZONE ? 0 : offsetY < 0 ? -1 : 1\n applyDragState({\n active: capture || distance >= DEAD_ZONE,\n offsetX,\n offsetY,\n distance,\n direction,\n })\n },\n [applyDragState],\n )\n\n const releasePointerCapture = useCallback((pointerId: number | null) => {\n if (pointerId === null) {\n return\n }\n const element = rootRef.current\n if (element?.hasPointerCapture(pointerId)) {\n element.releasePointerCapture(pointerId)\n }\n }, [])\n\n const resetState = useCallback(\n (releasePointer: boolean = false) => {\n if (releasePointer) {\n releasePointerCapture(pointerIdRef.current)\n }\n pointerIdRef.current = null\n applyDragState(INITIAL_STATE)\n },\n [applyDragState, releasePointerCapture],\n )\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n event.preventDefault()\n event.stopPropagation()\n const element = rootRef.current ?? event.currentTarget\n const { left, top, width, height } = element.getBoundingClientRect()\n centerRef.current = { x: left + width / 2, y: top + height / 2 }\n pointerIdRef.current = event.pointerId\n element.setPointerCapture(event.pointerId)\n updateDragState(event.clientX, event.clientY, true)\n },\n [updateDragState],\n )\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n if (pointerIdRef.current !== event.pointerId) {\n return\n }\n event.preventDefault()\n updateDragState(event.clientX, event.clientY)\n },\n [updateDragState],\n )\n\n const handlePointerUp = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n if (pointerIdRef.current !== event.pointerId) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n resetState(true)\n },\n [resetState],\n )\n\n useImperativeHandle(\n ref,\n () => ({\n reset: () => {\n resetState(true)\n },\n getElement: () => rootRef.current,\n }),\n [resetState],\n )\n\n const clampedOpacity = Math.min(Math.max(opacity, 0), 1)\n const sizeScale = size / 64\n const normalized = Math.min(dragState.distance, maxVisualDistance) / maxVisualDistance\n const pullOffset = dragState.direction * normalized * 10 * sizeScale\n const visualRenderer = renderVisual ?? defaultRenderVisual\n const visualProps: TapScrollCircleRenderProps = {\n dragState,\n normalizedDistance: normalized,\n sizeScale,\n size,\n opacity: clampedOpacity,\n }\n const rootStyle: CSSProperties = {\n ...style,\n width: size,\n height: size,\n transform: `translateY(${pullOffset}px)`\n }\n rootStyle.opacity = clampedOpacity\n return (\n <div\n ref={rootRef}\n className={twMerge(\n \"relative flex touch-none select-none items-center justify-center\",\n \"transition-transform duration-100 ease-out\",\n className,\n )}\n style={rootStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n role=\"presentation\">\n {visualRenderer(visualProps)}\n </div>\n )\n})\n\nTapScrollCircle.displayName = \"TapScrollCircle\"\n","/**\n * Clamps a value between a minimum and maximum value.\n *\n * 指定された値が最小値と最大値の範囲内に収まるように調整。\n *\n * @param value The value to clamp. / クランプする値。\n * @param min The minimum value. / 最小値。\n * @param max The maximum value. / 最大値。\n * @returns The clamped value. / クランプされた値。\n */\nexport const minmax = (value: number, min: number, max: number): number => {\n return Math.min(max, Math.max(min, value))\n}\n","import type { CSSProperties, ReactNode } from \"react\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\nimport { TapScrollCircle, type TapScrollCircleDragState, type TapScrollCircleHandle, type TapScrollCircleRenderProps } from \"./TapScrollCircle.tsx\"\nimport { minmax } from \"./utils.ts\"\n\n/**\n * Captures mouse and touch move events globally to track dragging.\n *\n * ドラッグ操作を追跡するために、マウスとタッチの移動イベントをグローバルにキャプチャ。\n *\n * @param event The initial mouse or touch event. / 初期のマウスまたはタッチイベント。\n * @param onMove A callback function that is called when the pointer moves. / ポインターが移動したときに呼び出されるコールバック関数。\n * @param onEnd A callback function that is called when the pointer is released. / ポインターが離されたときに呼び出されるコールバック関数。\n */\nconst capturePointerMove = (event: React.MouseEvent | React.TouchEvent, onMove: (event: { deltaX: number; deltaY: number }) => void, onEnd?: () => void) => {\n const isTouchEvent = \"touches\" in event.nativeEvent\n const startPosition = isTouchEvent ? (event as React.TouchEvent).nativeEvent.touches[0] : (event as React.MouseEvent).nativeEvent\n\n const handlePointerMove = (moveEvent: MouseEvent | TouchEvent) => {\n // ドラッグ中のデフォルトのブラウザ動作(スクロールなど)を防止\n if (isTouchEvent && moveEvent.cancelable) {\n moveEvent.preventDefault()\n }\n const movePosition = \"touches\" in moveEvent ? moveEvent.touches[0] : moveEvent\n onMove({\n deltaX: movePosition.clientX - startPosition.clientX,\n deltaY: movePosition.clientY - startPosition.clientY,\n })\n }\n\n const handlePointerUp = () => {\n if (isTouchEvent) {\n document.removeEventListener(\"touchmove\", handlePointerMove as (e: TouchEvent) => void)\n document.removeEventListener(\"touchend\", handlePointerUp)\n } else {\n document.removeEventListener(\"mousemove\", handlePointerMove as (e: MouseEvent) => void)\n document.removeEventListener(\"mouseup\", handlePointerUp)\n }\n onEnd?.()\n }\n\n if (isTouchEvent) {\n document.addEventListener(\"touchmove\", handlePointerMove as (e: TouchEvent) => void, { passive: false })\n document.addEventListener(\"touchend\", handlePointerUp)\n } else {\n document.addEventListener(\"mousemove\", handlePointerMove as (e: MouseEvent) => void)\n document.addEventListener(\"mouseup\", handlePointerUp)\n }\n}\n\n/**\n * Options to customize the auxiliary tap scroll circle.\n *\n * タップスクロール用サークルをカスタマイズするためのオプション。\n */\nexport type ScrollBarTapCircleOptions = {\n /** Enable or disable the tap scroll circle. / タップサークルを有効化または無効化。 */\n enabled?: boolean\n /** Circle diameter in pixels. / サークルの直径 (ピクセル)。 */\n size?: number\n /** Horizontal offset in pixels. / 水平方向オフセット (ピクセル)。 */\n offsetX?: number\n /** Vertical offset in pixels. / 垂直方向オフセット (ピクセル)。 */\n offsetY?: number\n /** Additional class names for the circle. / サークルの追加クラス名。 */\n className?: string\n /** Maximum drag distance used for visual feedback. / ビジュアルフィードバックに利用する最大ドラッグ距離。 */\n maxVisualDistance?: number\n /** Maximum speed multiplier relative to viewport size. / ビューポートサイズに対する最大速度倍率。 */\n maxSpeedMultiplier?: number\n /** Base opacity multiplier for the circle visuals. / サークル表示の基準透明度倍率。 */\n opacity?: number\n /** Custom visual renderer for the tap circle. / タップサークルのカスタムビジュアルのレンダラー。 */\n renderVisual?: (props: TapScrollCircleRenderProps) => ReactNode\n}\n\ntype ResolvedTapScrollCircleOptions = Required<Omit<ScrollBarTapCircleOptions, \"className\" | \"maxVisualDistance\" | \"renderVisual\">> & {\n className?: string\n maxVisualDistance: number\n renderVisual?: ScrollBarTapCircleOptions[\"renderVisual\"]\n}\n\ntype TapScrollCancelEventDetail = {\n paneId?: string\n}\n\n/** Custom event name emitted when external interactions should cancel tap scrolling. */\nexport const TAP_SCROLL_CANCEL_EVENT = \"virtualscroll:tap-scroll-cancel\"\n\n/**\n * Props for the ScrollBar component.\n *\n * ScrollBar コンポーネントの Props。\n */\nexport type ScrollBarProps = {\n /** The total size of the content. / コンテンツの総サイズ。 */\n contentSize: number\n /** The size of the visible area. / 表示領域のサイズ。 */\n viewportSize: number\n /** The current scroll position. / 現在のスクロール位置。 */\n scrollPosition: number\n /** A callback function that is called when the scroll position changes. / スクロール位置が変更されたときに呼び出されるコールバック関数。 */\n onScroll?: (scrollPosition: number, prevPosition: number) => void\n /** Whether grabbing the scrollbar thumb is allowed. / スクロールバーのつまみ操作を許可するかどうか。 */\n enableThumbDrag?: boolean\n /** Whether clicking on the track moves the scrollbar. / スクロールバーのトラッククリック操作を許可するかどうか。 */\n enableTrackClick?: boolean\n /** Whether arrow buttons control the scroll position. / 矢印ボタンによるスクロール操作を許可するかどうか。 */\n enableArrowButtons?: boolean\n /** Whether the scrollbar is horizontal. / スクロールバーが水平かどうか。 */\n horizontal?: boolean\n /** The width of the scrollbar. / スクロールバーの幅。 */\n scrollBarWidth?: number\n /** Additional class names for the component. / コンポーネントの追加のクラス名。 */\n className?: string\n /** The ID of the element that the scrollbar controls. / スクロールバーが制御する要素の ID。 */\n ariaControls?: string\n /** Configuration for the tap scroll circle. / タップサークルの設定。 */\n tapScrollCircleOptions?: ScrollBarTapCircleOptions\n /** Total number of scrollable items (optional). / スクロール対象アイテムの総数(任意)。 */\n itemCount?: number\n}\n\n/** The minimum size of the scrollbar thumb. / スクロールバーのつまみの最小サイズ。 */\nconst MIN_THUMB_SIZE = 20\nconst ARROW_HOLD_DELAY = 250\nconst ARROW_HOLD_INTERVAL = 60\nconst MIN_ARROW_STEP = 20\nconst ARROW_STEP_DIVISOR = 20\nconst TAP_SCROLL_MAX_DISTANCE = 220\nconst TAP_SCROLL_INITIAL_STATE: TapScrollCircleDragState = { active: false, offsetX: 0, offsetY: 0, distance: 0, direction: 0 }\n\nconst TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER = 2.2\nconst TAP_SCROLL_AUTO_SPEED_PER_ORDER = 8\nconst TAP_SCROLL_AUTO_SPEED_MAX_MULTIPLIER = 120\n\nconst DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS: ResolvedTapScrollCircleOptions = {\n enabled: true,\n size: 40,\n offsetX: -80,\n offsetY: 0,\n className: undefined,\n maxVisualDistance: TAP_SCROLL_MAX_DISTANCE,\n maxSpeedMultiplier: TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER,\n opacity: 1,\n renderVisual: undefined,\n}\n\n/**\n * Computes the auto-scroll speed multiplier based on item count.\n *\n * アイテム数に応じた自動スクロール速度倍率を算出。\n */\nconst computeAutoTapScrollMaxSpeedMultiplier = (itemCount?: number) => {\n if (!itemCount || itemCount <= 0) {\n return TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER\n }\n\n const clampedCount = Math.max(1, itemCount)\n const ordersOfMagnitude = Math.log10(clampedCount)\n const multiplier = TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER + ordersOfMagnitude * TAP_SCROLL_AUTO_SPEED_PER_ORDER\n return minmax(multiplier, TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER, TAP_SCROLL_AUTO_SPEED_MAX_MULTIPLIER)\n}\n\n/**\n * A custom scrollbar component.\n *\n * カスタムスクロールバーコンポーネント。\n */\nexport const ScrollBar = ({ contentSize, viewportSize, scrollPosition, onScroll, enableThumbDrag = true, enableTrackClick = true, enableArrowButtons = true, horizontal = false, scrollBarWidth = 12, className, ariaControls, tapScrollCircleOptions, itemCount }: ScrollBarProps) => {\n const [isDragging, setIsDragging] = useState(false)\n const [isThumbHovered, setIsThumbHovered] = useState(false)\n const [isTapActive, setIsTapActive] = useState(false)\n const thumbRef = useRef<HTMLDivElement>(null)\n const latestScrollPositionRef = useRef(scrollPosition)\n const arrowHoldIntervalRef = useRef<number | null>(null)\n const arrowHoldTimeoutRef = useRef<number | null>(null)\n const tapDragStateRef = useRef<TapScrollCircleDragState>(TAP_SCROLL_INITIAL_STATE)\n const tapCircleHandleRef = useRef<TapScrollCircleHandle | null>(null)\n const autoScrollFrameRef = useRef<number | null>(null)\n const lastAutoScrollTimestampRef = useRef<number | null>(null)\n const resolvedTapScrollOptions = useMemo<ResolvedTapScrollCircleOptions>(() => {\n const manualMaxSpeedMultiplier = tapScrollCircleOptions?.maxSpeedMultiplier\n const maxSpeedMultiplier = typeof manualMaxSpeedMultiplier === \"number\" ? manualMaxSpeedMultiplier : computeAutoTapScrollMaxSpeedMultiplier(itemCount)\n\n return {\n enabled: tapScrollCircleOptions?.enabled ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.enabled,\n size: tapScrollCircleOptions?.size ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.size,\n offsetX: tapScrollCircleOptions?.offsetX ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.offsetX,\n offsetY: tapScrollCircleOptions?.offsetY ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.offsetY,\n className: tapScrollCircleOptions?.className ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.className,\n maxVisualDistance: tapScrollCircleOptions?.maxVisualDistance ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.maxVisualDistance,\n maxSpeedMultiplier,\n opacity: minmax(tapScrollCircleOptions?.opacity ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.opacity, 0, 1),\n renderVisual: tapScrollCircleOptions?.renderVisual ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.renderVisual,\n }\n }, [itemCount, tapScrollCircleOptions])\n const {\n enabled: tapCircleEnabled,\n size: tapCircleSize,\n offsetX: tapCircleOffsetX,\n offsetY: tapCircleOffsetY,\n className: tapCircleClassName,\n maxVisualDistance: tapCircleMaxDistance,\n maxSpeedMultiplier: tapCircleMaxSpeedMultiplier,\n opacity: tapCircleOpacity,\n renderVisual: tapCircleRenderVisual,\n } = resolvedTapScrollOptions\n const mainSizeKey: \"width\" | \"height\" = horizontal ? \"width\" : \"height\"\n const crossSizeKey: \"width\" | \"height\" = horizontal ? \"height\" : \"width\"\n const positionKey: \"left\" | \"top\" = horizontal ? \"left\" : \"top\"\n const clientCoordinateKey: \"clientX\" | \"clientY\" = horizontal ? \"clientX\" : \"clientY\"\n /**\n * Selects delta value based on orientation.\n *\n * 向きに応じて移動量を選択。\n */\n const selectDelta = (deltaX: number, deltaY: number) => (horizontal ? deltaX : deltaY)\n /**\n * Extracts pointer coordinate based on orientation.\n *\n * 向きに基づいて座標を取得。\n */\n const getPointerCoordinate = (point: { clientX: number; clientY: number }) => point[clientCoordinateKey]\n const arrowLabels = horizontal ? [\"Scroll left\", \"Scroll right\"] : [\"Scroll up\", \"Scroll down\"]\n const arrowIcons = horizontal ? [\"◀\", \"▶\"] : [\"▲\", \"▼\"]\n const directionClass = horizontal ? \"flex flex-row items-stretch\" : \"flex flex-col items-stretch\"\n const effectiveTapMaxDistance = Math.max(tapCircleMaxDistance, 1)\n // 表示領域に対するコンテンツの比率\n const scrollRatio = viewportSize / contentSize\n const arrowButtonLength = scrollBarWidth\n const trackLength = Math.max(viewportSize - arrowButtonLength * 2, 0)\n const rawThumbSize = scrollRatio * trackLength\n const thumbSize = Math.min(Math.max(MIN_THUMB_SIZE, rawThumbSize || 0), trackLength || MIN_THUMB_SIZE)\n // 最大スクロール位置\n const maxScrollPosition = contentSize - viewportSize\n const effectiveTrackLength = Math.max(trackLength - thumbSize, 0)\n const thumbPosition = maxScrollPosition <= 0 || effectiveTrackLength <= 0 ? 0 : (scrollPosition / maxScrollPosition) * effectiveTrackLength\n\n // スクロールバーが表示されるかどうか\n const scrollBarVisible = contentSize > viewportSize\n const canUseArrowButtons = scrollBarVisible && enableArrowButtons\n\n useEffect(() => {\n latestScrollPositionRef.current = scrollPosition\n }, [scrollPosition])\n\n useEffect(() => {\n if (!enableThumbDrag) {\n setIsThumbHovered(false)\n }\n }, [enableThumbDrag])\n\n // ホバーやドラッグの状態に応じてつまみの見た目を更新\n useEffect(() => {\n const element = thumbRef.current\n if (!element) {\n return\n }\n\n const hoverScale = horizontal ? \"scaleY(1.06)\" : \"scaleX(1.06)\"\n const dragScale = horizontal ? \"scaleY(1.12)\" : \"scaleX(1.12)\"\n\n if (!enableThumbDrag) {\n element.style.removeProperty(\"transform\")\n element.style.backgroundColor = \"#7F7F7F\"\n element.style.removeProperty(\"transition\")\n return\n }\n\n if (isDragging) {\n element.style.transform = dragScale\n element.style.backgroundColor = \"#4F4F4F\"\n element.style.transition = \"transform 60ms ease-out\"\n return\n }\n\n element.style.transition = \"transform 80ms ease-out\"\n if (isThumbHovered) {\n element.style.transform = hoverScale\n element.style.backgroundColor = \"#5F5F5F\"\n } else {\n element.style.removeProperty(\"transform\")\n element.style.backgroundColor = \"#7F7F7F\"\n }\n }, [enableThumbDrag, horizontal, isDragging, isThumbHovered])\n\n /**\n * Clears timers controlling arrow auto-repeat.\n *\n * 矢印ボタンの自動リピート用タイマーを解除。\n */\n const clearArrowTimers = useCallback(() => {\n if (arrowHoldIntervalRef.current !== null) {\n window.clearInterval(arrowHoldIntervalRef.current)\n arrowHoldIntervalRef.current = null\n }\n if (arrowHoldTimeoutRef.current !== null) {\n window.clearTimeout(arrowHoldTimeoutRef.current)\n arrowHoldTimeoutRef.current = null\n }\n }, [])\n\n /**\n * Stops the tap circle auto-scroll animation.\n *\n * タップサークルによる自動スクロールを停止。\n */\n const stopAutoScroll = useCallback(() => {\n if (autoScrollFrameRef.current !== null) {\n window.cancelAnimationFrame(autoScrollFrameRef.current)\n autoScrollFrameRef.current = null\n }\n lastAutoScrollTimestampRef.current = null\n }, [])\n\n /**\n * Resets tap circle state and related motion.\n *\n * タップサークルの状態と動作を初期化。\n */\n const resetTapScroll = useCallback(() => {\n tapDragStateRef.current = { ...TAP_SCROLL_INITIAL_STATE }\n setIsTapActive(false)\n tapCircleHandleRef.current?.reset()\n stopAutoScroll()\n }, [stopAutoScroll])\n\n /**\n * Advances tap circle auto-scroll by animation frame.\n *\n * タップサークルの自動スクロールをフレームごとに進行。\n */\n const stepAutoScroll = useCallback(\n (timestamp: number) => {\n const state = tapDragStateRef.current\n if (!state.active || state.direction === 0) {\n stopAutoScroll()\n return\n }\n if (!scrollBarVisible || maxScrollPosition <= 0) {\n stopAutoScroll()\n return\n }\n\n const lastTimestamp = lastAutoScrollTimestampRef.current ?? timestamp\n const deltaSeconds = Math.max((timestamp - lastTimestamp) / 1000, 0)\n lastAutoScrollTimestampRef.current = timestamp\n\n if (deltaSeconds <= 0) {\n autoScrollFrameRef.current = window.requestAnimationFrame(stepAutoScroll)\n return\n }\n\n const normalized = Math.min(state.distance, effectiveTapMaxDistance) / effectiveTapMaxDistance\n const eased = normalized ** 1.1\n const minSpeed = Math.max(viewportSize * 0.2, 40)\n const maxSpeed = Math.max(viewportSize * tapCircleMaxSpeedMultiplier, 1200)\n const speed = minSpeed + (maxSpeed - minSpeed) * eased\n\n const prevPosition = latestScrollPositionRef.current\n const nextPosition = minmax(prevPosition + state.direction * speed * deltaSeconds, 0, maxScrollPosition)\n\n if (nextPosition === prevPosition) {\n stopAutoScroll()\n return\n }\n\n latestScrollPositionRef.current = nextPosition\n onScroll?.(nextPosition, prevPosition)\n\n autoScrollFrameRef.current = window.requestAnimationFrame(stepAutoScroll)\n },\n [effectiveTapMaxDistance, maxScrollPosition, onScroll, scrollBarVisible, stopAutoScroll, tapCircleMaxSpeedMultiplier, viewportSize],\n )\n\n /**\n * Starts tap circle auto-scroll loop.\n *\n * タップサークルによる自動スクロールを開始。\n */\n const startAutoScroll = useCallback(() => {\n if (autoScrollFrameRef.current === null) {\n lastAutoScrollTimestampRef.current = null\n autoScrollFrameRef.current = window.requestAnimationFrame(stepAutoScroll)\n }\n }, [stepAutoScroll])\n\n useEffect(() => {\n return () => {\n clearArrowTimers()\n stopAutoScroll()\n }\n }, [clearArrowTimers, stopAutoScroll])\n\n /**\n * Handles tap circle drag state changes.\n *\n * タップサークルのドラッグ状態変化を処理。\n */\n const handleTapCircleDragChange = useCallback(\n (state: TapScrollCircleDragState) => {\n tapDragStateRef.current = state\n setIsTapActive(state.active)\n if (state.active && state.direction !== 0) {\n startAutoScroll()\n } else {\n stopAutoScroll()\n }\n },\n [startAutoScroll, stopAutoScroll],\n )\n\n useEffect(() => {\n if (!tapCircleEnabled) {\n resetTapScroll()\n }\n }, [resetTapScroll, tapCircleEnabled])\n\n useEffect(() => {\n const handleTapScrollCancel = (event: Event) => {\n const customEvent = event as CustomEvent<TapScrollCancelEventDetail>\n const targetPaneId = customEvent.detail?.paneId\n if (targetPaneId && ariaControls && targetPaneId !== ariaControls) {\n return\n }\n resetTapScroll()\n }\n\n window.addEventListener(TAP_SCROLL_CANCEL_EVENT, handleTapScrollCancel as EventListener)\n return () => {\n window.removeEventListener(TAP_SCROLL_CANCEL_EVENT, handleTapScrollCancel as EventListener)\n }\n }, [ariaControls, resetTapScroll])\n\n useEffect(() => {\n if (!tapCircleEnabled) {\n return\n }\n const handlePointerDown = (event: PointerEvent) => {\n if (!tapDragStateRef.current.active) {\n return\n }\n const targetNode = event.target\n if (!(targetNode instanceof Node)) {\n resetTapScroll()\n return\n }\n const element = tapCircleHandleRef.current?.getElement()\n if (element?.contains(targetNode)) {\n return\n }\n resetTapScroll()\n }\n document.addEventListener(\"pointerdown\", handlePointerDown, true)\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown, true)\n }\n }, [resetTapScroll, tapCircleEnabled])\n\n /**\n * Translates the thumb position to a scroll position.\n *\n * つまみの位置をスクロール位置に変換。\n *\n * @param thumbPosition The position of the thumb. / つまみの位置。\n * @returns The scroll position. / スクロール位置。\n */\n const translateToScrollPosition = (thumbPositionValue: number) => {\n if (!scrollBarVisible || effectiveTrackLength <= 0 || maxScrollPosition <= 0) {\n return 0\n }\n const clampedThumbPosition = minmax(thumbPositionValue, 0, effectiveTrackLength)\n return minmax((clampedThumbPosition / effectiveTrackLength) * maxScrollPosition, 0, maxScrollPosition)\n }\n\n /**\n * Moves scroll position by a fixed step using arrow controls.\n *\n * 矢印操作で一定ステップ分スクロール。\n */\n const scrollByStep = (direction: 1 | -1) => {\n if (!scrollBarVisible || maxScrollPosition <= 0) {\n return\n }\n const step = Math.max(Math.round(viewportSize / ARROW_STEP_DIVISOR), MIN_ARROW_STEP)\n const prev = latestScrollPositionRef.current\n const next = minmax(prev + direction * step, 0, maxScrollPosition)\n if (next === prev) {\n return\n }\n latestScrollPositionRef.current = next\n onScroll?.(next, prev)\n }\n\n /**\n * Handles pointer release on arrow buttons.\n *\n * 矢印ボタン解放時の処理。\n */\n const handleArrowPointerUp = () => {\n clearArrowTimers()\n }\n\n /**\n * Handles pointer press on arrow buttons.\n *\n * 矢印ボタン押下時の処理。\n */\n const handleArrowPointerDown = (direction: 1 | -1) => (event: React.MouseEvent<HTMLButtonElement> | React.TouchEvent<HTMLButtonElement>) => {\n if (!canUseArrowButtons) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n resetTapScroll()\n clearArrowTimers()\n scrollByStep(direction)\n arrowHoldTimeoutRef.current = window.setTimeout(() => {\n arrowHoldIntervalRef.current = window.setInterval(() => {\n scrollByStep(direction)\n }, ARROW_HOLD_INTERVAL)\n }, ARROW_HOLD_DELAY)\n }\n\n /**\n * Handles keyboard activation of arrow buttons.\n *\n * 矢印ボタンのキーボード操作を処理。\n */\n const handleArrowKeyDown = (direction: 1 | -1) => (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (!enableArrowButtons) {\n return\n }\n if (event.key === \"Enter\" || event.key === \" \" || event.key === \"Spacebar\") {\n event.preventDefault()\n scrollByStep(direction)\n }\n }\n\n // スクロールバーのつまみをマウスで押したときのハンドラ\n /**\n * Handles pointer down interaction on the thumb.\n *\n * つまみ押下時のインタラクションを処理。\n */\n const handlePointerDownOnThumb = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n if (!enableThumbDrag) {\n event.preventDefault()\n event.stopPropagation()\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if ((\"button\" in event && event.button !== 0) || event.ctrlKey) {\n return\n }\n // event.preventDefault() // ここでは preventDefault しない\n event.stopPropagation()\n resetTapScroll()\n\n // ドラッグ開始時のつまみの位置\n const startThumbPosition = thumbPosition\n setIsDragging(true)\n setIsThumbHovered(true)\n\n // マウスの移動をキャプチャ\n capturePointerMove(\n event,\n ({ deltaX, deltaY }) => {\n const delta = selectDelta(deltaX, deltaY)\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n },\n () => {\n setIsDragging(false)\n if (thumbRef.current && !thumbRef.current.matches(\":hover\")) {\n setIsThumbHovered(false)\n }\n },\n )\n }\n\n // スクロールバーのトラックをマウスで押したときのハンドラ\n /**\n * Handles pointer down interaction on the track.\n *\n * トラック押下時のインタラクションを処理。\n */\n const handlePointerDownOnTrack = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n if (!enableTrackClick) {\n event.preventDefault()\n event.stopPropagation()\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if ((\"button\" in event && event.button !== 0) || event.ctrlKey) {\n return\n }\n\n const isTouchEvent = \"touches\" in event.nativeEvent\n const position = isTouchEvent ? (event as React.TouchEvent).nativeEvent.touches[0] : (event as React.MouseEvent).nativeEvent\n\n // マウスの初期位置を取得\n const startMousePosition = getPointerCoordinate(position)\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n const clickPositionInTrack = startMousePosition - (horizontal ? rect.left : rect.top)\n resetTapScroll()\n\n // クリックした位置にスクロール\n // つまみはクリック位置の中央に配置\n const startThumbPosition = clickPositionInTrack - thumbSize / 2\n onScroll?.(translateToScrollPosition(startThumbPosition), thumbPosition)\n\n // マウスの移動をキャプチャしてドラッグ操作を処理\n capturePointerMove(event, ({ deltaX, deltaY }) => {\n const delta = selectDelta(deltaX, deltaY)\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n })\n }\n\n const tapCircleOpacityValue = useMemo(() => {\n const baseOpacity = isTapActive ? 1 : 0.8\n return minmax(baseOpacity * tapCircleOpacity, 0, 1)\n }, [isTapActive, tapCircleOpacity])\n\n const tapCircleStyle = useMemo<CSSProperties>(() => {\n const diameter = tapCircleSize\n const baseTop = `calc(50% - ${diameter / 2}px + ${tapCircleOffsetY}px)`\n return {\n left: tapCircleOffsetX,\n top: baseTop,\n }\n }, [tapCircleOffsetX, tapCircleOffsetY, tapCircleSize])\n\n /**\n * Renders an arrow button for scrollbar controls.\n *\n * スクロールバー制御用矢印ボタンを描画。\n */\n const renderArrowButton = (direction: 1 | -1, label: string, icon: string) => (\n <button\n type=\"button\"\n className=\"flex items-center justify-center text-[#313131] text-xs transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#60a5fa] focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50\"\n style={{\n [mainSizeKey]: arrowButtonLength,\n [crossSizeKey]: scrollBarWidth,\n backgroundColor: \"#E0E0E0\",\n }}\n aria-label={label}\n onMouseDown={handleArrowPointerDown(direction)}\n onTouchStart={handleArrowPointerDown(direction)}\n onMouseUp={handleArrowPointerUp}\n onMouseLeave={handleArrowPointerUp}\n onTouchEnd={handleArrowPointerUp}\n onTouchCancel={handleArrowPointerUp}\n onKeyDown={handleArrowKeyDown(direction)}\n aria-disabled={!enableArrowButtons}\n disabled={!canUseArrowButtons}>\n <span aria-hidden=\"true\">{icon}</span>\n </button>\n )\n\n return (\n <div\n className={twMerge(\n \"group relative cursor-default select-none\",\n directionClass,\n className,\n )}\n style={{\n [mainSizeKey]: viewportSize,\n [crossSizeKey]: scrollBarWidth,\n backgroundColor: \"white\",\n userSelect: \"none\",\n position: \"relative\",\n }}\n role=\"scrollbar\"\n tabIndex={-1}\n aria-controls={ariaControls}\n aria-valuenow={scrollPosition}\n aria-valuemin={0}\n aria-valuemax={maxScrollPosition}\n aria-orientation={horizontal ? \"horizontal\" : \"vertical\"}>\n {!horizontal && scrollBarVisible && tapCircleEnabled && (\n <TapScrollCircle\n ref={tapCircleHandleRef}\n className={twMerge(\n \"pointer-events-auto absolute transition-opacity duration-150\",\n tapCircleClassName,\n )}\n size={tapCircleSize}\n maxVisualDistance={effectiveTapMaxDistance}\n style={tapCircleStyle}\n opacity={tapCircleOpacityValue}\n renderVisual={tapCircleRenderVisual}\n onDragChange={handleTapCircleDragChange}\n />\n )}\n {renderArrowButton(-1, arrowLabels[0], arrowIcons[0])}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: スクロールトラックのクリックとドラッグを有効にするため */}\n <div\n className=\"relative flex-1\"\n style={{\n backgroundColor: \"#F5F5F5\",\n borderRadius: scrollBarWidth / 2,\n }}\n onMouseDown={handlePointerDownOnTrack}\n onTouchStart={handlePointerDownOnTrack}\n aria-disabled={!enableTrackClick}>\n {/* コンテンツがビューポートより大きい場合にのみつまみを表示 */}\n {scrollBarVisible && (\n // スクロールバーのつまみの当たり判定を広げるためのラッパー\n <div\n className=\"group absolute\"\n style={{\n [mainSizeKey]: thumbSize,\n [positionKey]: thumbPosition,\n ...(horizontal ? { top: 0, bottom: 0 } : { left: 0, right: 0 }),\n }}\n onMouseDown={handlePointerDownOnThumb}\n onTouchStart={handlePointerDownOnThumb}\n role=\"slider\"\n aria-orientation={horizontal ? \"horizontal\" : \"vertical\"}\n aria-valuenow={scrollPosition}\n aria-valuemin={0}\n aria-valuemax={maxScrollPosition}\n aria-disabled={!enableThumbDrag}\n tabIndex={enableThumbDrag ? 0 : -1}>\n {/* スクロールバーのつまみ(可視部分) */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: スクロールバーのつまみは必要なインタラクションです */}\n <div\n ref={thumbRef}\n className={twMerge(\n \"absolute\",\n horizontal\n ? `inset-x-0 inset-y-[1.5px] group-hover:inset-y-[-0.5px] ${isDragging ? \"-inset-y-0.5\" : \"group-active:-inset-y-0.5\"}`\n : `inset-x-[1.5px] inset-y-0 group-hover:inset-x-[-0.5px] ${isDragging ? \"-inset-x-0.5\" : \"group-active:-inset-x-0.5\"}`,\n )}\n style={{\n backgroundColor: \"#7F7F7F\",\n borderRadius: scrollBarWidth - 1,\n cursor: enableThumbDrag ? \"pointer\" : \"default\",\n ...(horizontal ? {\n left: 0,\n right: 0,\n top: 1.5,\n bottom: 1.5,\n } : {\n top: 0,\n bottom: 0,\n left: 1.5,\n right: 1.5,\n }),\n }}\n onMouseEnter={() => {\n if (enableThumbDrag) {\n setIsThumbHovered(true)\n }\n }}\n onMouseLeave={() => {\n if (enableThumbDrag) {\n setIsThumbHovered(false)\n }\n }}\n />\n </div>\n )}\n </div>\n {renderArrowButton(1, arrowLabels[1], arrowIcons[1])}\n </div>\n )\n}\n","// Simple logger utility for debugging\nexport const Logger = {\n debug(message: string, ...args: unknown[]): void {\n if (typeof window !== \"undefined\" && window.localStorage?.getItem(\"debug\") === \"true\") {\n console.debug(`[VirtualScroll] ${message}`, ...args);\n }\n },\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[VirtualScroll] ${message}`, ...args);\n },\n\n error(message: string, ...args: unknown[]): void {\n console.error(`[VirtualScroll] ${message}`, ...args);\n },\n};\n","import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\nimport { Logger } from \"./logger.ts\"\nimport { ScrollBar, type ScrollBarTapCircleOptions, TAP_SCROLL_CANCEL_EVENT } from \"./ScrollBar.tsx\"\nimport { minmax } from \"./utils.ts\"\n\n/**\n * Props for the ScrollPane component.\n *\n * ScrollPane コンポーネントの Props。\n */\nexport type ScrollPaneProps = {\n /**\n * A function that renders the content of the scroll pane.\n * It receives the current scroll position as an argument.\n *\n * スクロールペインのコンテンツをレンダリングする関数です。\n * 現在のスクロール位置を引数として受け取ります。\n */\n children: (scrollPosition: number) => React.ReactNode\n /** The total size of the content. / コンテンツの総サイズ。 */\n contentSize: number\n /** The size of the visible area. / 表示領域のサイズ。 */\n viewportSize: number\n /** The width of the scrollbar. / スクロールバーの幅。 */\n scrollBarWidth?: number\n /** Whether grabbing the scrollbar thumb is allowed. / スクロールバーのつまみ操作を許可するかどうか。 */\n enableThumbDrag?: boolean\n /** A callback function that is called when the scroll position changes. / スクロール位置が変更されたときに呼び出されるコールバック関数。 */\n onScroll?: (scrollPosition: number, prevPosition: number) => void\n /** Additional class names for the component. / コンポーネントの追加のクラス名。 */\n className?: string\n /** Custom styles for the component. / コンポーネントのカスタムスタイル。 */\n style?: React.CSSProperties\n /** A background element to be rendered behind the content. / コンテンツの背後にレンダリングされる背景要素。 */\n background?: React.ReactNode\n /** Configuration for the tap scroll circle. / タップサークルの設定。 */\n tapScrollCircleOptions?: ScrollBarTapCircleOptions\n /** Configuration for inertia scroll behavior. / 慣性スクロールの設定。 */\n inertiaOptions?: ScrollPaneInertiaOptions\n /** Total number of scrollable items (optional). / スクロール対象アイテムの総数(任意)。 */\n itemCount?: number\n /** Whether clicking the scrollbar track moves the thumb. / スクロールバートラックのクリック操作を許可するかどうか。 */\n enableTrackClick?: boolean\n /** Whether arrow buttons control the scroll position. / 矢印ボタンのスクロール操作を許可するかどうか。 */\n enableArrowButtons?: boolean\n /** Whether dragging the content area scrolls the pane. / コンテンツ領域のドラッグでスクロールさせるかどうか。 */\n enablePointerDrag?: boolean\n}\n\nexport type ScrollPaneInertiaOptions = {\n /** Maximum velocity applied when inertia starts. / 慣性開始時に適用する最大速度。 */\n maxVelocity?: number\n /** Minimum velocity threshold to continue inertia. / 慣性を継続するための最小速度しきい値。 */\n minVelocity?: number\n /** Deceleration applied on every frame. / 各フレームで適用される減速度。 */\n deceleration?: number\n /** Sampling window in milliseconds for pointer velocity calculation. / ポインタの速度計算に用いるミリ秒単位のサンプリング期間。 */\n velocitySampleWindow?: number\n /** Minimum velocity required to start inertia. / 慣性を開始するために必要な最小速度。 */\n startVelocityThreshold?: number\n}\n\ntype ResolvedScrollPaneInertiaOptions = Required<ScrollPaneInertiaOptions>\n\nconst DEFAULT_INERTIA_OPTIONS: ResolvedScrollPaneInertiaOptions = {\n maxVelocity: 6,\n minVelocity: 0.02,\n deceleration: 0.0025,\n velocitySampleWindow: 90,\n startVelocityThreshold: 0.04,\n}\n\ntype ListenerEntry = [string, EventListenerOrEventListenerObject, AddEventListenerOptions | boolean | undefined]\n\n/**\n * Toggles event listeners on a given target.\n *\n * 指定ターゲットにイベントリスナーを追加または削除。\n */\nconst toggleListeners = (target: HTMLElement | Window, entries: ListenerEntry[], action: \"add\" | \"remove\") => {\n for (const [type, listener, options] of entries) {\n if (action === \"add\") {\n target.addEventListener(type, listener, options)\n } else {\n target.removeEventListener(type, listener, options)\n }\n }\n}\n\nexport type ScrollPaneHandle = {\n scrollTo: (newPosition: number) => void\n getScrollPosition: () => number\n getContentSize: () => number\n getViewportSize: () => number\n}\n\n/**\n * A component that provides a scrollable view with a custom scrollbar.\n *\n * カスタムスクロールバーを備えたスクロール可能なビューを提供するコンポーネントです。\n */\nexport const ScrollPane = forwardRef<ScrollPaneHandle, ScrollPaneProps>(({ children, contentSize, viewportSize, scrollBarWidth = 12, enableThumbDrag = true, enableTrackClick = true, enableArrowButtons = true, enablePointerDrag = true, onScroll, className, style, background, tapScrollCircleOptions, inertiaOptions, itemCount }, ref) => {\n const scrollPositionRef = useRef(0)\n const [_, _forceUpdate] = useReducer((x) => x + 1, 0)\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n const contentAreaRef = useRef<HTMLDivElement>(null)\n const inertiaStateRef = useRef<{ frame: number | null; velocity: number; lastTimestamp: number | null }>({\n frame: null,\n velocity: 0,\n lastTimestamp: null,\n })\n\n const resolvedInertiaOptions = useMemo<ResolvedScrollPaneInertiaOptions>(\n () => ({\n maxVelocity: inertiaOptions?.maxVelocity ?? DEFAULT_INERTIA_OPTIONS.maxVelocity,\n minVelocity: inertiaOptions?.minVelocity ?? DEFAULT_INERTIA_OPTIONS.minVelocity,\n deceleration: inertiaOptions?.deceleration ?? DEFAULT_INERTIA_OPTIONS.deceleration,\n velocitySampleWindow: inertiaOptions?.velocitySampleWindow ?? DEFAULT_INERTIA_OPTIONS.velocitySampleWindow,\n startVelocityThreshold: inertiaOptions?.startVelocityThreshold ?? DEFAULT_INERTIA_OPTIONS.startVelocityThreshold,\n }),\n [inertiaOptions],\n )\n\n Logger.debug(\"[ScrollPane] ScrollPane rendered\", { contentSize, viewportSize, scrollBarWidth, className, style, tapScrollCircleOptions, inertiaOptions, enablePointerDrag })\n\n // const size = useMemo(() => ({ contentSize, viewportSize }), [contentSize, viewportSize])\n\n // contentSize と viewportSize を ref として保持\n // const sizeRef = useRef({ contentSize, viewportSize })\n\n const sizeRef = useRef({ contentSize, viewportSize })\n\n const isScrollable = useMemo(() => contentSize > viewportSize, [contentSize, viewportSize])\n\n // useEffect(() => { // useEffect では contentSize や viewportSize の変更が反映される前にレンダリングされて位置がズレる可能性があるため、useLayoutEffect を使用\n // Logger.debug(\"[ScrollPane] ScrollPane size updated\", { contentSize, viewportSize })\n // // サイズが変更されたときに ref を更新\n // sizeRef.current = { contentSize, viewportSize }\n // forceUpdate() // サイズが変更されたときに強制的に再レンダリング\n // }, [contentSize, viewportSize])\n\n // const scrollTo = useCallback(\n // (newPosition: number | ((prev: number) => number)) => {\n // const { contentSize: currentContentSize, viewportSize: currentViewportSize } = sizeRef.current\n // const currentIsScrollable = currentContentSize > currentViewportSize\n // const prevPosition = scrollPositionRef.current\n\n // Logger.debug(\"[ScrollPane] scrollTo called\", { newPosition, currentContentSize, currentViewportSize, currentIsScrollable, prevPosition })\n\n // if (!currentIsScrollable) {\n // // スクロール不可の場合は常に0に\n // if (scrollPositionRef.current !== 0) {\n // scrollPositionRef.current = 0\n // onScroll?.(0, prevPosition)\n // }\n // return\n // }\n // const nextPosition = typeof newPosition === \"function\" ? newPosition(scrollPositionRef.current) : newPosition\n // const newScrollPosition = minmax(nextPosition, 0, currentContentSize - currentViewportSize)\n // if (scrollPositionRef.current !== newScrollPosition) {\n // scrollPositionRef.current = newScrollPosition\n // onScroll?.(newScrollPosition, prevPosition)\n // }\n // },\n // [onScroll]\n // )\n\n const scrollTo = useCallback(\n (newPosition: number | ((prev: number) => number)) => {\n const { contentSize: currentContentSize, viewportSize: currentViewportSize } = sizeRef.current\n const currentIsScrollable = currentContentSize > currentViewportSize\n const prevPosition = scrollPositionRef.current\n\n Logger.debug(\"[ScrollPane] scrollTo called\", { newPosition, contentSize: currentContentSize, viewportSize: currentViewportSize, currentIsScrollable, prevPosition })\n\n if (!currentIsScrollable) {\n // スクロール不可の場合は常に0に\n if (scrollPositionRef.current !== 0) {\n scrollPositionRef.current = 0\n onScroll?.(0, prevPosition)\n }\n return\n }\n const nextPosition = typeof newPosition === \"function\" ? newPosition(scrollPositionRef.current) : newPosition\n const newScrollPosition = minmax(nextPosition, 0, currentContentSize - currentViewportSize)\n if (scrollPositionRef.current !== newScrollPosition) {\n scrollPositionRef.current = newScrollPosition\n onScroll?.(newScrollPosition, prevPosition)\n }\n },\n [onScroll],\n )\n\n const stopInertia = useCallback(() => {\n const state = inertiaStateRef.current\n if (state.frame !== null) {\n cancelAnimationFrame(state.frame)\n }\n state.frame = null\n state.velocity = 0\n state.lastTimestamp = null\n }, [])\n\n const startInertia = useCallback(\n (initialVelocity: number) => {\n if (!isScrollable) {\n return\n }\n\n const { maxVelocity, minVelocity, deceleration, startVelocityThreshold } = resolvedInertiaOptions\n\n const limitedVelocity = minmax(initialVelocity, -maxVelocity, maxVelocity)\n if (Math.abs(limitedVelocity) < startVelocityThreshold) {\n return\n }\n\n stopInertia()\n\n inertiaStateRef.current.velocity = limitedVelocity\n inertiaStateRef.current.lastTimestamp = null\n\n const step = (timestamp: number) => {\n const state = inertiaStateRef.current\n if (state.lastTimestamp === null) {\n state.lastTimestamp = timestamp\n state.frame = requestAnimationFrame(step)\n return\n }\n\n const deltaTime = timestamp - state.lastTimestamp\n state.lastTimestamp = timestamp\n\n if (deltaTime <= 0) {\n state.frame = requestAnimationFrame(step)\n return\n }\n\n const previousVelocity = state.velocity\n let nextVelocity = previousVelocity\n const decelerationAmount = deceleration * deltaTime\n if (previousVelocity > 0) {\n nextVelocity = Math.max(0, previousVelocity - decelerationAmount)\n } else if (previousVelocity < 0) {\n nextVelocity = Math.min(0, previousVelocity + decelerationAmount)\n }\n\n const averageVelocity = (previousVelocity + nextVelocity) / 2\n const distance = averageVelocity * deltaTime\n const previousPosition = scrollPositionRef.current\n\n if (distance !== 0) {\n scrollTo((prevPositionInternal) => prevPositionInternal + distance)\n }\n\n const nextPosition = scrollPositionRef.current\n const { contentSize: currentContentSize, viewportSize: currentViewportSize } = sizeRef.current\n const maxScrollPosition = Math.max(currentContentSize - currentViewportSize, 0)\n\n state.velocity = nextVelocity\n\n const reachedBoundary = nextPosition === previousPosition || (nextPosition <= 0 && nextVelocity <= 0) || (nextPosition >= maxScrollPosition && nextVelocity >= 0)\n\n if (Math.abs(nextVelocity) < minVelocity || reachedBoundary) {\n stopInertia()\n return\n }\n\n state.frame = requestAnimationFrame(step)\n }\n\n inertiaStateRef.current.frame = requestAnimationFrame(step)\n },\n [isScrollable, resolvedInertiaOptions, scrollTo, stopInertia],\n )\n\n useLayoutEffect(() => {\n // contentSize と viewportSize の最新値を保持して scrollTo の参照を安定させる\n sizeRef.current = { contentSize, viewportSize }\n }, [contentSize, viewportSize])\n\n // contentSize または viewportSize が変更されたときにスクロール位置を調整します。\n useLayoutEffect(() => {\n // useEffect では contentSize や viewportSize の変更が反映される前にレンダリングされて位置がズレる可能性があるため、useLayoutEffect を使用。フリッカー防止も。\n if (isScrollable) {\n Logger.debug(\"[ScrollPane] Adjusting scroll position due to content or viewport size change\", { contentSize, viewportSize, scrollPosition: scrollPositionRef.current })\n const maxScrollPosition = minmax(contentSize - viewportSize, 0, contentSize)\n if (scrollPositionRef.current > maxScrollPosition) {\n scrollTo(maxScrollPosition)\n }\n } else {\n scrollTo(0)\n }\n }, [isScrollable, scrollTo, contentSize, viewportSize])\n\n // useEffect(() => {\n // // ホイールイベントのハンドラ\n // const handleWheel = (event: WheelEvent) => {\n // if (!isScrollable) {\n // return\n // }\n\n // event.preventDefault()\n\n // let deltaY = event.deltaY\n\n // // deltaMode に応じてスクロール量を調整\n // if (event.deltaMode === 1) {\n // // DOM_DELTA_LINE: 行単位のスクロール\n // const lineHeight = 16 // 1行のおおよその高さ (ピクセル)\n // deltaY *= lineHeight\n // } else if (event.deltaMode === 2) {\n // // DOM_DELTA_PAGE: ページ単位のスクロール\n // deltaY *= sizeRef.current.viewportSize // ビューポートの高さを基準にスクロール\n // }\n\n // Logger.debug(\"[ScrollPane] wheel event\", { deltaY, scrollPosition: scrollPositionRef.current })\n\n // // スクロール位置を更新\n // scrollTo((prev) => prev + deltaY)\n // }\n\n // const scrollContainer = scrollContainerRef.current\n // if (scrollContainer) {\n // // wheel イベントリスナーを passive: false で登録し、preventDefault を可能にする\n // scrollContainer.addEventListener(\"wheel\", handleWheel, { passive: false })\n // }\n\n // // クリーンアップ関数\n // return () => {\n // if (scrollContainer) {\n // scrollContainer.removeEventListener(\"wheel\", handleWheel)\n // }\n // }\n // }, [isScrollable, scrollTo])\n\n useEffect(() => {\n // ホイールイベントのハンドラ\n const handleWheel = (event: WheelEvent) => {\n if (!isScrollable) {\n return\n }\n\n event.preventDefault()\n\n stopInertia()\n\n let deltaY = event.deltaY\n\n // deltaMode に応じてスクロール量を調整\n if (event.deltaMode === 1) {\n // DOM_DELTA_LINE: 行単位のスクロール\n const lineHeight = 16 // 1行のおおよその高さ (ピクセル)\n deltaY *= lineHeight\n } else if (event.deltaMode === 2) {\n // DOM_DELTA_PAGE: ページ単位のスクロール\n deltaY *= viewportSize // ビューポートの高さを基準にスクロール\n }\n\n Logger.debug(\"[ScrollPane] wheel event\", { deltaY, scrollPosition: scrollPositionRef.current })\n\n // スクロール位置を更新\n scrollTo((prev) => prev + deltaY)\n }\n\n const scrollContainer = scrollContainerRef.current\n if (scrollContainer) {\n // wheel イベントリスナーを passive: false で登録し、preventDefault を可能にする\n scrollContainer.addEventListener(\"wheel\", handleWheel, { passive: false })\n }\n\n // クリーンアップ関数\n return () => {\n if (scrollContainer) {\n scrollContainer.removeEventListener(\"wheel\", handleWheel)\n }\n }\n }, [isScrollable, scrollTo, stopInertia, viewportSize])\n\n useImperativeHandle(\n ref,\n () => ({\n scrollTo,\n getScrollPosition: () => scrollPositionRef.current,\n getContentSize: () => contentSize,\n getViewportSize: () => viewportSize,\n }),\n [scrollTo, contentSize, viewportSize],\n )\n\n const id = useId()\n\n useEffect(() => {\n const element = contentAreaRef.current\n if (!element) {\n return\n }\n\n if (!enablePointerDrag) {\n stopInertia()\n return\n }\n\n const DRAG_ACTIVATION_THRESHOLD = 6\n let dragPointerId: number | null = null\n let dragStartClientY = 0\n let dragStartScroll = 0\n let isDragging = false\n let shouldCancelNextClick = false\n let clickResetTimer: number | null = null\n let velocitySamples: { clientY: number; time: number }[] = []\n\n const resetState = () => {\n dragPointerId = null\n dragStartClientY = 0\n dragStartScroll = 0\n isDragging = false\n velocitySamples = []\n }\n\n const pushVelocitySample = (clientY: number) => {\n const now = performance.now()\n velocitySamples.push({ clientY, time: now })\n velocitySamples = velocitySamples.filter((sample) => now - sample.time <= resolvedInertiaOptions.velocitySampleWindow)\n }\n\n const shouldIgnoreTarget = (target: EventTarget | null) => target instanceof HTMLElement && target.closest(\"[data-scrollpane-ignore-drag='true']\") !== null\n\n const handleClickCapture = (event: MouseEvent) => {\n if (!shouldCancelNextClick) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n shouldCancelNextClick = false\n }\n\n const startDragging = (event: PointerEvent) => {\n if (isDragging) {\n return\n }\n isDragging = true\n shouldCancelNextClick = true\n if (!element.hasPointerCapture(event.pointerId)) {\n element.setPointerCapture(event.pointerId)\n }\n pushVelocitySample(event.clientY)\n }\n\n const handlePointerMove = (event: PointerEvent) => {\n if (dragPointerId !== event.pointerId) {\n return\n }\n\n if (!isDragging) {\n const distanceY = Math.abs(event.clientY - dragStartClientY)\n if (distanceY < DRAG_ACTIVATION_THRESHOLD) {\n return\n }\n startDragging(event)\n if (!isDragging) {\n return\n }\n }\n\n pushVelocitySample(event.clientY)\n\n const deltaY = event.clientY - dragStartClientY\n const nextPosition = dragStartScroll - deltaY\n scrollTo(nextPosition)\n\n if (event.cancelable) {\n event.preventDefault()\n }\n }\n\n const endDrag = (event: PointerEvent) => {\n if (dragPointerId !== event.pointerId) {\n return\n }\n\n if (isDragging && shouldCancelNextClick && event.cancelable) {\n event.preventDefault()\n event.stopPropagation()\n }\n\n if (element.hasPointerCapture(event.pointerId)) {\n element.releasePointerCapture(event.pointerId)\n }\n\n let inertiaVelocity = 0\n if (isDragging && velocitySamples.length >= 2) {\n const lastSample = velocitySamples[velocitySamples.length - 1]\n const firstSample = velocitySamples.find((sample) => lastSample.time - sample.time <= resolvedInertiaOptions.velocitySampleWindow) ?? velocitySamples[0]\n if (lastSample && firstSample && lastSample.time !== firstSample.time) {\n const deltaClientY = lastSample.clientY - firstSample.clientY\n const deltaTime = lastSample.time - firstSample.time\n inertiaVelocity = -(deltaClientY / deltaTime)\n }\n }\n\n resetState()\n\n if (clickResetTimer !== null) {\n window.clearTimeout(clickResetTimer)\n }\n if (shouldCancelNextClick) {\n clickResetTimer = window.setTimeout(() => {\n shouldCancelNextClick = false\n clickResetTimer = null\n }, 0)\n }\n\n if (Math.abs(inertiaVelocity) >= resolvedInertiaOptions.startVelocityThreshold) {\n startInertia(inertiaVelocity)\n }\n }\n\n const handlePointerDown = (event: PointerEvent) => {\n if (!isScrollable) {\n return\n }\n if (event.button !== 0 && event.pointerType === \"mouse\") {\n return\n }\n if (event.ctrlKey || event.metaKey || event.altKey) {\n return\n }\n if (shouldIgnoreTarget(event.target)) {\n return\n }\n\n window.dispatchEvent(new CustomEvent(TAP_SCROLL_CANCEL_EVENT, { detail: { paneId: id } }))\n\n stopInertia()\n\n dragPointerId = event.pointerId\n dragStartClientY = event.clientY\n dragStartScroll = scrollPositionRef.current\n isDragging = false\n shouldCancelNextClick = false\n velocitySamples = []\n }\n\n const handlePointerCancel = (event: PointerEvent) => {\n if (dragPointerId !== event.pointerId) {\n return\n }\n shouldCancelNextClick = false\n if (element.hasPointerCapture(event.pointerId)) {\n element.releasePointerCapture(event.pointerId)\n }\n if (clickResetTimer !== null) {\n window.clearTimeout(clickResetTimer)\n clickResetTimer = null\n }\n resetState()\n }\n\n const elementEntries: ListenerEntry[] = [\n [\"click\", handleClickCapture as EventListenerOrEventListenerObject, true],\n [\"pointerdown\", handlePointerDown as EventListenerOrEventListenerObject, { passive: false }],\n [\"pointermove\", handlePointerMove as EventListenerOrEventListenerObject, { passive: false }],\n [\"pointerup\", endDrag as EventListenerOrEventListenerObject, undefined],\n [\"pointercancel\", handlePointerCancel as EventListenerOrEventListenerObject, undefined],\n ]\n const windowEntries: ListenerEntry[] = [\n [\"pointermove\", handlePointerMove as EventListenerOrEventListenerObject, { passive: false }],\n [\"pointerup\", endDrag as EventListenerOrEventListenerObject, undefined],\n [\"pointercancel\", handlePointerCancel as EventListenerOrEventListenerObject, undefined],\n ]\n\n toggleListeners(element, elementEntries, \"add\")\n toggleListeners(window, windowEntries, \"add\")\n\n return () => {\n toggleListeners(element, elementEntries, \"remove\")\n toggleListeners(window, windowEntries, \"remove\")\n if (dragPointerId !== null && element.hasPointerCapture(dragPointerId)) {\n element.releasePointerCapture(dragPointerId)\n }\n if (clickResetTimer !== null) {\n window.clearTimeout(clickResetTimer)\n }\n stopInertia()\n }\n }, [enablePointerDrag, id, isScrollable, resolvedInertiaOptions, scrollTo, startInertia, stopInertia])\n\n return (\n <div ref={scrollContainerRef} className={twMerge(\"flex\", className)} style={style}>\n <div\n ref={contentAreaRef}\n className=\"relative h-full flex-1 overflow-hidden\"\n style={{ height: viewportSize, ...(enablePointerDrag ? { touchAction: \"none\" } : {}) }}\n id={id}>\n {background}\n {children(scrollPositionRef.current)}\n </div>\n {isScrollable && (\n <ScrollBar\n contentSize={contentSize}\n viewportSize={viewportSize}\n scrollPosition={scrollPositionRef.current}\n onScroll={scrollTo}\n enableThumbDrag={enableThumbDrag}\n enableTrackClick={enableTrackClick}\n enableArrowButtons={enableArrowButtons}\n scrollBarWidth={scrollBarWidth}\n ariaControls={id}\n tapScrollCircleOptions={tapScrollCircleOptions}\n itemCount={itemCount}\n />\n )}\n </div>\n )\n\n // return (\n // <div ref={scrollContainerRef} className={twMerge(\"flex\", className)} style={style}>\n // <div className=\"relative h-full flex-1 overflow-hidden\" style={{ height: viewportSize }} id={id}>\n // {children(scrollPositionRef.current)}\n // </div>\n // {isScrollable && <ScrollBar contentSize={contentSize} viewportSize={sizeRef.current.viewportSize} scrollPosition={scrollPositionRef.current} onScroll={scrollTo} scrollBarWidth={scrollBarWidth} ariaControls={id} />}\n // </div>\n // )\n})\n","/**\n * Provides the sample tap scroll circle visual used for demos.\n * デモ用に使用されるサンプルのタップスクロールビジュアルを提供するモジュール。\n */\n\nimport type { TapScrollCircleProps, TapScrollCircleRenderProps } from \"./TapScrollCircle.tsx\"\n\nconst clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max)\n\nexport const tapScrollCircleSampleVisual: NonNullable<TapScrollCircleProps[\"renderVisual\"]> = ({ dragState, normalizedDistance, sizeScale, size }: TapScrollCircleRenderProps) => {\n const radius = Math.max(size / 2, 1)\n const stretchY = 1 + normalizedDistance * 0.65\n const stretchX = Math.max(0.65, 1 - normalizedDistance * 0.25)\n const tail = dragState.direction * normalizedDistance * 26 * sizeScale\n const pupilScale = 0.8 + normalizedDistance * 0.18\n const tailBase = 3 * sizeScale\n const baseHeight = 6 * sizeScale\n const coreSize = 22 * sizeScale\n const rodHeight = Math.abs(tail) + baseHeight\n const rodTranslate = tail > 0 ? tailBase : -Math.abs(tail) - tailBase\n const rodWidth = Math.max(2.5, 3 * sizeScale)\n const limitedX = clamp(dragState.offsetX, -radius, radius)\n const limitedY = clamp(dragState.offsetY, -radius, radius)\n const pupilRange = radius * 0.35\n const pupilX = (limitedX / radius) * pupilRange\n const pupilY = (limitedY / radius) * pupilRange\n const highlightX = pupilX * 0.45\n const highlightY = pupilY * 0.45\n const highlightSize = Math.max(coreSize * 0.38, 6)\n const highlightOpacity = 0.65 + normalizedDistance * 0.2\n const active = dragState.active\n\n return (\n <>\n <div\n className=\"absolute inset-0 rounded-full border border-white/40 bg-linear-to-br from-[#1d4ed8]/60 via-[#60a5fa]/55 to-[#bfdbfe]/40 shadow-md\"\n style={{\n transform: `scale(${stretchX}, ${stretchY})`,\n transition: active ? \"40ms transform ease-out\" : \"200ms ease transform\",\n }}\n />\n <div\n className=\"absolute top-1/2 left-1/2 rounded-full border border-white/50 bg-white/85\"\n style={{\n width: coreSize,\n height: coreSize,\n transform: `translate(calc(-50% + ${pupilX}px), calc(-50% + ${pupilY}px)) scale(${stretchX}, ${pupilScale * stretchY})`,\n transition: active ? \"70ms transform ease-out\" : \"200ms ease transform\",\n }}\n />\n <div\n className=\"absolute top-1/2 left-1/2 rounded-full bg-white/80\"\n style={{\n width: highlightSize,\n height: highlightSize,\n transform: `translate(calc(-50% + ${highlightX}px), calc(-50% + ${highlightY}px)) scale(${stretchX}, ${stretchY})`,\n opacity: highlightOpacity,\n boxShadow: \"0 0 8px rgba(255,255,255,0.45)\",\n transition: active ? \"120ms opacity 150ms, 120ms transform ease-out ease-out\" : \"220ms ease transform, 240ms opacity ease\",\n }}\n />\n <div\n className=\"absolute top-1/2 left-1/2 rounded-full bg-white/50\"\n style={{\n width: rodWidth,\n height: rodHeight,\n transform: `translate(-50%, ${rodTranslate}px)`,\n opacity: normalizedDistance,\n transition: active ? \"40ms height, 60ms opacity ease-out ease-out\" : \"200ms ease height, 120ms ease opacity\",\n }}\n />\n </>\n )\n}\n","/**\n * @file Fenwick Tree (Binary Indexed Tree) implementation and React hook.\n * @file Fenwick Tree (Binary Indexed Tree) の実装と React フック。\n *\n * @module useFenwickMapTree\n * @description This module provides a FenwickTree (Binary Indexed Tree) data structure\n * and a React hook `useFenwickMapTree` to manage it.\n * This is optimized for virtual scrolling scenarios with dynamically sized items.\n *\n * @description このモジュールは、FenwickTree (バイナリインデックスツリー) データ構造と、\n * それを管理するための React フック `useFenwickMapTree` の提供。\n * 動的なアイテムサイズを持つ仮想スクロールのシナリオに最適化されている。\n */\nimport { useMemo, useRef } from \"react\"\nimport { minmax } from \"./utils.ts\"\n\ntype MaterializeRange = { from: number; to: number }\ntype MaterializeOption = { materialize: boolean; ranges?: MaterializeRange[] }\ntype MaterializeConfig = { materializeOption?: MaterializeOption }\ntype DeltaUpdate = { index: number; change: number }\ntype ValueUpdate = { index: number; value: number }\n\n/**\n * @class FenwickTree\n * @classdesc Implements a Fenwick Tree (or Binary Indexed Tree).\n * This data structure efficiently calculates prefix sums and performs updates in logarithmic time.\n * It is particularly useful for virtual scrolling, where it can manage the offsets of variably sized items.\n *\n * @classdesc Fenwick Tree (バイナリインデックスツリー) の実装。\n * このデータ構造は、接頭辞和の計算と更新を対数時間で効率的に実行。\n * 可変サイズのアイテムのオフセットを管理できるため、特に仮想スクロールで有用。\n */\nexport class FenwickMapTree {\n /**\n * @private\n * @property {Map<number, number>} tree - The Map storing the Fenwick tree structure, specifically the sums of deltas. It is 1-indexed.\n * @property {Map<number, number>} tree - Fenwick Tree 構造を格納する Map。特に差分の合計を保持する。1-indexed。\n */\n private tree!: Map<number, number>\n\n /**\n * @private\n * @property {Map<number, number>} deltas - The Map storing the differences (deltas) from the base value at each index.\n * @property {Map<number, number>} deltas - 各インデックスにおける基準値との差分 (delta) を格納する Map。\n */\n private deltas!: Map<number, number>\n\n /**\n * @private\n * @property {number} size - The number of elements the tree manages.\n * @property {number} size - ツリーが管理する要素数。\n */\n private size!: number\n\n /**\n * @private\n * @property {number} baseValue - The uniform base value for all elements, used to optimize memory.\n * @property {number} baseValue - 全要素の均一な基準値。メモリ最適化のために使用。\n */\n private baseValue!: number\n\n /**\n * @private\n * @property {((index: number) => number) | undefined} valueFn - A function to generate values, stored for lazy initialization.\n * @property {((index: number) => number) | undefined} valueFn - 値を生成するための関数。遅延初期化のために保存される。\n */\n private valueFn?: (index: number) => number\n private total?: number\n\n /**\n * @constructor\n * @description Initializes the Fenwick Tree.\n * @description Fenwick Tree の初期化。\n * @param {number} size - The total number of items.\n * @param {number | ((index: number) => number)} valueOrFn - The value for all elements, or a function to generate values.\n * @param {{ sampleRange?: { from: number; to: number }, materialize?: boolean }} [options] - Optional settings for initialization.\n */\n constructor(size: number, valueOrFn: number | ((index: number) => number), options?: { sampleRange?: { from: number; to: number }; materialize?: boolean }) {\n this.reset(size, valueOrFn, options)\n }\n\n /**\n * @method reset\n * @description Resets the Fenwick Tree with a new size and initial values.\n * @description Fenwick Tree を新しいサイズと初期値でリセット。\n * @param {number} size - The total number of items.\n * @param {number | ((index: number) => number)} valueOrFn - The value for all elements, or a function to generate values.\n * @param {{ sampleRange?: { from: number; to: number }, materialize?: boolean }} [options] - Optional settings for initialization.\n */\n reset(size: number, valueOrFn: number | ((index: number) => number), options?: { sampleRange?: { from: number; to: number }; materialize?: boolean }) {\n this.size = size\n this.tree = new Map()\n this.deltas = new Map()\n this.total = undefined\n\n const isFn = typeof valueOrFn === \"function\"\n if (isFn) {\n this.valueFn = valueOrFn\n if (this.size > 0) {\n // サンプリング範囲を決定する\n const range = options?.sampleRange ?? {\n from: 0,\n to: Math.min(99, this.size - 1),\n }\n // 最頻値と生成された値を取得する\n const { mode, materializedValues } = this._calculateMode(range.from, range.to)\n this.baseValue = mode\n\n // サンプリング範囲の値を具現化する\n if (options?.materialize) {\n for (let i = 0; i < materializedValues.length; i++) {\n const value = materializedValues[i]\n const index = range.from + i\n if (index >= this.size) {\n break\n }\n // _materialize を直接呼ぶ代わりに、計算済みの値を使って更新する\n const change = value - this.baseValue\n this.deltas.set(index, change)\n this._updateTree(index, change)\n }\n }\n } else {\n this.baseValue = 0\n }\n // 具現化が完了した後に total を計算する\n this.total = this.getTotal()\n } else {\n this.valueFn = undefined\n this.baseValue = valueOrFn\n this.total = this.baseValue * this.size\n }\n }\n\n /**\n * @method setValueFn\n * @description Updates the value function and re-initializes the tree.\n * @description 値関数を更新し、ツリーを再初期化する。\n * @param {number | ((index: number) => number)} valueOrFn - The new value for all elements, or a function to generate values.\n */\n setValueFn(valueOrFn: number | ((index: number) => number)) {\n if (typeof valueOrFn === \"function\") {\n this.valueFn = valueOrFn\n } else {\n // If a number is provided, it's treated as a new baseValue,\n // and valueFn is cleared. This case effectively turns the tree\n // into a uniform-value tree, but existing deltas are preserved.\n this.valueFn = undefined\n this.baseValue = valueOrFn\n }\n }\n\n /**\n * @private\n * @method _calculateMode\n * @description Calculates the mode (most frequent value) within a given range of values generated by `valueFn`. If multiple modes exist, it returns their average. If no value appears more than once, it returns the median of the range. This approach helps determine a representative `baseValue` for the Fenwick tree, especially for data with high variance. It also returns the array of values generated within the range for reuse.\n * @description `valueFn` によって生成される値の指定された範囲内の最頻値を計算する。最頻値が複数存在する場合は、それらの平均値を返す。どの値も複数回出現しない場合は、範囲の中央値を返す。このアプローチは、特に分散の大きいデータに対して、Fenwick Tree の代表的な `baseValue` を決定するのに役立つ。また、再利用のために範囲内で生成された値の配列も返す。\n * @param {number} from - The starting index of the range (inclusive).\n * @param {number} to - The ending index of the range (inclusive).\n * @returns {{ mode: number; materializedValues: number[] }} An object containing the calculated mode and the array of generated values.\n */\n private _calculateMode(from: number, to: number): { mode: number; materializedValues: number[] } {\n if (!this.valueFn) {\n return { mode: 0, materializedValues: [] }\n }\n\n const values: number[] = []\n for (let i = from; i <= to; i++) {\n if (i >= this.size) {\n break\n }\n values.push(this.valueFn(i))\n }\n // valueFn で生成した値を再利用するためにコピーを保持する\n const materializedValues = [...values]\n\n if (values.length === 0) {\n return { mode: 0, materializedValues: [] }\n }\n\n // 中央値を計算してデフォルトの最頻値として設定\n values.sort((a, b) => a - b)\n const mid = Math.floor(values.length / 2)\n let mode: number\n if (values.length % 2 === 0) {\n // 偶数個の場合は中央2つの値の平均\n mode = Math.floor((values[mid - 1] + values[mid]) / 2)\n } else {\n // 奇数個の場合は中央の値\n mode = values[mid]\n }\n\n const frequencies = new Map<number, number>()\n let maxFreq = 0\n\n for (const value of values) {\n const count = (frequencies.get(value) ?? 0) + 1\n frequencies.set(value, count)\n if (count > maxFreq) {\n maxFreq = count\n }\n }\n\n if (maxFreq > 1) {\n const modes: number[] = []\n for (const [value, count] of frequencies.entries()) {\n if (count === maxFreq) {\n modes.push(value)\n }\n }\n const sum = modes.reduce((a, b) => a + b, 0)\n mode = Math.floor(sum / modes.length)\n }\n return { mode, materializedValues }\n }\n\n /**\n * @method update\n * @description Updates the value at a given index.\n * @description 指定されたインデックスの値を更新。\n * @param {number} index - The 0-based index to update.\n * @param {number} value - The new value.\n */\n update(index: number, value: number): number | undefined {\n return this.updates([{ index, value }])\n }\n\n /**\n * @method updates\n * @description Updates the values at given indices.\n * @description 指定されたインデックスの値を更新。\n * @param {ValueUpdate[]} updates - An array of updates, each with an index and the new value.\n */\n updates(updates: ValueUpdate[]): number | undefined {\n const deltaUpdates = this._buildDeltaUpdates(updates)\n if (deltaUpdates.length > 0) {\n return this.updateDeltas(deltaUpdates)\n }\n return this.total\n }\n\n /**\n * @method updateDelta\n * @description Updates the delta at a given index and propagates the change through the tree.\n * @description 指定されたインデックスのデルタを更新し、変更をツリーに伝播させる。\n * @param {number} index - The 0-based index to update.\n * @param {number} change - The value to add to the delta at the given index.\n */\n updateDelta(index: number, change: number): number | undefined {\n return this.updateDeltas([{ index, change }])\n }\n\n /**\n * @method updateDeltas\n * @description Updates the deltas at given indices and propagates the changes through the tree.\n * @description 指定されたインデックスのデルタを更新し、変更をツリーに伝播させる。\n * @param {DeltaUpdate[]} updates - An array of updates, each with an index and the change to apply.\n */\n updateDeltas(updates: DeltaUpdate[]): number | undefined {\n for (const { index, change } of updates) {\n if (index < 0 || index >= this.size) {\n throw new Error(`Index ${index} out of bounds`)\n }\n\n // deltas Map を更新\n const currentDelta = this.deltas.get(index) ?? 0\n this.deltas.set(index, currentDelta + change)\n\n // ツリーを更新\n this._updateTree(index, change)\n }\n\n return this.total\n }\n\n /**\n * @private\n * @method _updateTree\n * @description Updates the Fenwick tree and the total sum with a given change.\n * @description Fenwick Tree と合計値を指定された変更で更新する。\n * @param {number} index - The 0-based index that changed.\n * @param {number} change - The change in value.\n */\n private _updateTree(index: number, change: number) {\n if (change === 0) {\n return\n }\n // tree Map を更新\n let treeIndex = index + 1 // Fenwick Tree のアルゴリズムは 1 始まりで設計される\n while (treeIndex <= this.size) {\n this.tree.set(treeIndex, (this.tree.get(treeIndex) ?? 0) + change)\n treeIndex += treeIndex & -treeIndex\n }\n\n // 合計値を更新 (totalが計算済みの場合のみ)\n if (this.total !== undefined) {\n this.total += change\n }\n }\n\n /**\n * @private\n * @method _buildDeltaUpdates\n * @description Converts value updates into delta updates while preserving validation logic.\n * @description 値更新入力を検証しつつデルタ更新へ変換する。\n * @param {ValueUpdate[]} updates - Requested value updates.\n * @returns {DeltaUpdate[]} Sanitized delta updates ready to apply.\n */\n private _buildDeltaUpdates(updates: ValueUpdate[]): DeltaUpdate[] {\n const deltaUpdates: DeltaUpdate[] = []\n for (const { index, value } of updates) {\n if (index < 0 || index >= this.size) {\n throw new Error(`Index ${index} out of bounds`)\n }\n if (value < 0) {\n throw new Error(\"Value cannot be negative.\")\n }\n\n // 現在値を取得して差分を算出\n const oldValue = this.deltas.has(index) ? (this.deltas.get(index) ?? 0) + this.baseValue : this.baseValue\n const change = value - oldValue\n if (change !== 0) {\n deltaUpdates.push({ index, change })\n }\n }\n return deltaUpdates\n }\n\n /**\n * @private\n * @method _materialize\n * @description Materializes the value at a specific index if it hasn't been already.\n * @description 特定のインデックスの値がまだ具現化されていない場合に具現化する。\n * @param {number} index - The 0-based index to materialize.\n * @param {boolean} [updateTree=true] - Whether to update the Fenwick tree after materialization.\n */\n private _materialize(index: number, updateTree = true) {\n if (this.valueFn) {\n // 1. 現在の差分を取得する (存在しなければ 0)\n const oldDelta = this.deltas.get(index) ?? 0\n\n // 2. valueFn から本来の値を計算し、新しい差分を求める\n const value = this.valueFn(index)\n const newDelta = value - this.baseValue\n\n // 3. 差分が実際に変わった場合のみ、ツリーを更新する\n if (newDelta !== oldDelta) {\n this.deltas.set(index, newDelta)\n if (updateTree) {\n // ツリーに反映すべき差分は「新しい差分」と「古い差分」の間の差\n const changeForTree = newDelta - oldDelta\n this._updateTree(index, changeForTree)\n }\n }\n }\n }\n\n /**\n * @private\n * @method _materializeRanges\n * @description Materializes values for provided ranges and optionally a target index, keeping existing semantics for each caller.\n * @description 指定された範囲とターゲットインデックスを既存仕様通りに具現化する。\n * @param {MaterializeOption | undefined} option - Materialization option wrapper.\n * @param {number | undefined} index - Target index for materialization.\n * @param {boolean} [forceIndex=false] - When true, materializes the index even if it is outside the provided ranges.\n */\n private _materializeRanges(option?: MaterializeOption, index?: number, forceIndex = false) {\n if (!(option?.materialize && this.valueFn)) {\n return\n }\n\n const ranges = option.ranges\n if (ranges && ranges.length > 0) {\n for (const range of ranges) {\n const from = range.from\n const to = Math.min(range.to, this.size - 1)\n for (let i = from; i <= to; i++) {\n this._materialize(i)\n }\n }\n\n if (index === undefined) {\n return\n }\n\n if (forceIndex) {\n this._materialize(index)\n return\n }\n\n const first = ranges[0].from\n const last = ranges[ranges.length - 1].to\n if (index >= first && index <= last) {\n this._materialize(index)\n }\n return\n }\n\n if (index !== undefined) {\n this._materialize(index)\n }\n }\n\n /**\n * @private\n * @method _findIndex\n * @description Executes a binary search over prefix sums to find the first index satisfying a boundary condition.\n * @description 累積和に対する二分探索を行い、境界条件を満たす最初のインデックスを求める。\n * @param {number} target - Target cumulative value.\n * @param {MaterializeConfig} options - Materialization setting wrapper.\n * @param {boolean} chooseLowerBound - When true, finds the smallest index meeting or exceeding the target; otherwise finds the largest index not exceeding it.\n * @returns {{ index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined }} Binary search result.\n */\n private _findIndex(\n target: number,\n options: MaterializeConfig = {},\n chooseLowerBound: boolean,\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n if (this.size === 0) {\n return { index: -1, total: this.total ?? 0, cumulative: undefined, currentValue: undefined, safeIndex: undefined }\n }\n\n let low = 0\n let high = this.size - 1\n let ans = -1\n let result:\n | {\n cumulative: number\n total: number | undefined\n currentValue: number\n safeIndex: number\n }\n | undefined\n let finalTotal = this.total\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2)\n result = this.prefixSum(mid, options)\n finalTotal = result.total\n const meetsCondition = chooseLowerBound ? result.cumulative >= target : result.cumulative <= target\n if (meetsCondition) {\n ans = mid\n if (chooseLowerBound) {\n high = mid - 1\n } else {\n low = mid + 1\n }\n } else if (chooseLowerBound) {\n low = mid + 1\n } else {\n high = mid - 1\n }\n }\n\n return { index: ans, total: finalTotal, cumulative: result?.cumulative, currentValue: result?.currentValue, safeIndex: result?.safeIndex }\n }\n\n /**\n * @method prefixSum\n * @description Calculates the cumulative sum up to a given index (inclusive) in O(log n) time.\n * @description 指定されたインデックスまでの累積和を O(log n) で計算。\n * @param {number} index - The 0-based index to prefixSum up to.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @returns {{ cumulative: number; total: number | undefined; currentValue: number; safeIndex: number }} The cumulative sum of values from index 0 to the given index, the total sum, and the value at the given index.\n */\n prefixSum(index: number, options?: MaterializeConfig): { cumulative: number; total: number | undefined; currentValue: number; safeIndex: number } {\n if (index < 0) {\n return { cumulative: 0, total: this.total, currentValue: 0, safeIndex: 0 }\n }\n const safeIndex = minmax(index, 0, this.size - 1)\n\n const materializeOption = options?.materializeOption\n this._materializeRanges(materializeOption, safeIndex, true)\n\n let sum = 0\n let treeIndex = safeIndex + 1 // Fenwick Tree のアルゴリズムは 1 始まりで設計される\n while (treeIndex > 0) {\n const treeNodeValue = this.tree.get(treeIndex) ?? 0\n sum += treeNodeValue\n treeIndex -= treeIndex & -treeIndex\n }\n\n const currentValue = materializeOption?.materialize ? this.get(safeIndex) : (this.deltas.get(safeIndex) || 0) + this.baseValue\n\n // ベース値に基づく合計を加算\n return { cumulative: sum + this.baseValue * (safeIndex + 1), total: this.total, currentValue, safeIndex }\n }\n\n /**\n * @method get\n * @description Gets the value at a specific index.\n * @description 特定のインデックスの値を取得。\n * @param {number} index - The 0-based index to get.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @returns {number} The value at the given index.\n */\n get(index: number, options?: MaterializeConfig): number {\n if (index < 0 || index >= this.size) {\n throw new Error(\"Index out of bounds\")\n }\n\n const materializeOption = options?.materializeOption\n this._materializeRanges(materializeOption, index)\n\n return (this.deltas.get(index) ?? 0) + this.baseValue\n }\n\n /**\n * @method getTotal\n * @description Gets the total sum of all values in the tree.\n * @description ツリー内のすべての値の合計を取得。\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @returns {number} The total sum of all values.\n */\n getTotal(options?: MaterializeConfig): number {\n const materializeOption = options?.materializeOption\n this._materializeRanges(materializeOption)\n\n if (this.total === undefined) {\n if (this.size === 0) {\n this.total = 0\n } else {\n // 具現化は冒頭の処理に任せて高さを計算する\n let total = this.baseValue * this.size\n for (const delta of this.deltas.values()) {\n total += delta\n }\n this.total = total\n const lastPrefix = this.prefixSum(this.getSize() - 1)\n console.assert(lastPrefix.cumulative === lastPrefix.total, \"Inconsistent Fenwick Tree state\")\n }\n }\n\n return this.total\n }\n\n /**\n * @method rebuildTree\n * @description Rebuilds the Fenwick Tree from the existing `baseValue` and `deltas`. This corrects any discrepancies in the tree's internal state, such as those caused by floating-point errors, by recalculating the tree structure and the total sum from the source `deltas`. This method does not re-materialize values from `valueFn`.\n * @description 既存の `baseValue` と `deltas` から Fenwick Tree を再構築します。これにより、`deltas` からツリー構造と合計値を再計算することで、浮動小数点誤差などによって生じた内部状態の不一致を修正します。このメソッドは `valueFn` から値を再具現化しません。\n * @param {object} [options] - Optional settings for rebuilding.\n * @param {boolean} [options.materialize=false] - If true and `valueFn` is provided, re-materializes all values, recalculating `deltas` and `baseValue`.\n */\n rebuildTree(options?: { materialize?: boolean }) {\n if (options?.materialize && this.valueFn) {\n // すべての値を具現化する\n const valueFn = this.valueFn\n this.reset(this.size, (i) => valueFn(i), { materialize: true })\n return\n }\n\n const newTree = new Map<number, number>()\n let newTotal = this.baseValue * this.size\n\n // 既存の deltas を使って新しいツリーを構築し、合計値も同時に再計算する\n for (const [index, delta] of this.deltas.entries()) {\n newTotal += delta\n\n if (delta === 0) {\n continue\n }\n // Fenwick Tree のアルゴリズムは 1 始まりで設計されるため、インデックスを 1 加算する\n let treeIndex = index + 1\n while (treeIndex <= this.size) {\n newTree.set(treeIndex, (newTree.get(treeIndex) ?? 0) + delta)\n treeIndex += treeIndex & -treeIndex\n }\n }\n\n // 最後に状態をアトミックに更新\n this.tree = newTree\n this.total = newTotal\n }\n\n /**\n * @method calculateAccumulatedError\n * @description Compares the cached total sum with a theoretical total calculated directly from the source values (`deltas` and `baseValue`, or `valueFn`). This helps detect any discrepancy in the tree's cached state, which might be caused by floating-point errors or other inconsistencies.\n * @description キャッシュされている合計値と、元の値 (`deltas` と `baseValue`、または `valueFn`) から直接計算した理論上の合計値とを比較します。これにより、浮動小数点数の累積誤差やその他の不整合によって生じる可能性のある、ツリーのキャッシュ状態の不一致を検出できます。\n * @returns {number} The difference between the cached total and the theoretical total.\n */\n calculateAccumulatedError(): number {\n if (this.total === undefined) {\n // total がまだ計算されていない場合は、誤差は 0 とする\n return 0\n }\n\n // 理論上の合計値を計算\n let theoreticalTotal = this.baseValue * this.size\n for (const delta of this.deltas.values()) {\n theoreticalTotal += delta\n }\n\n // キャッシュされている合計値との差を返す\n return this.total - theoreticalTotal\n }\n\n /**\n * @method changeSize\n * @description Changes the size of the Fenwick Tree.\n * @description Fenwick Tree のサイズを変更する。\n * @param {number} newSize - The new size of the tree.\n */\n changeSize(newSize: number) {\n const oldSize = this.size\n if (newSize === oldSize) {\n // サイズが変わらない場合は何もしない\n return\n }\n\n // サイズが小さくなる場合、範囲外の delta を削除する\n if (newSize < oldSize) {\n for (const index of this.deltas.keys()) {\n if (index >= newSize) {\n this.deltas.delete(index)\n }\n }\n }\n\n this.size = newSize\n // サイズ変更後、deltas に基づいてツリー全体を再構築します。\n this.rebuildTree()\n\n const lastPrefix = this.prefixSum(this.getSize() - 1)\n console.assert(lastPrefix.cumulative === lastPrefix.total, \"Inconsistent Fenwick Tree state\")\n }\n\n /**\n * @method getSize\n * @description Gets the size of the tree.\n * @description ツリーのサイズを取得。\n * @returns {number} The total number of items.\n */\n getSize(): number {\n return this.size\n }\n\n /**\n * @method findIndexAtOrAfter\n * @description Finds the first index where the cumulative sum is greater than or equal to a target value.\n * @description 累積和がターゲット値以上になる最初のインデックスを検索。\n * @param {number} target - The target cumulative sum.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @param {MaterializeOption} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {MaterializeRange[]} [options.materializeOption.ranges] - Optional ranges for eager materialization.\n * @returns {{ index: number, total: number | undefined, cumulative: number | undefined, currentValue: number | undefined, safeIndex: number | undefined }} The 0-based index and the total sum, or -1 if not found.\n */\n findIndexAtOrAfter(\n target: number,\n options?: MaterializeConfig,\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n return this._findIndex(target, options ?? {}, true)\n }\n\n /**\n * @method findIndexAtOrBefore\n * @description Finds the last index where the cumulative sum is less than or equal to a target value.\n * @description 累積和がターゲット値以下になる最後のインデックスを検索。\n * @param {number} target - The target cumulative sum.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @param {MaterializeOption} [options.materializeOption] - Options to control materialization。\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values。\n * @param {MaterializeRange[]} [options.materializeOption.ranges] - Optional ranges for eager materialization。\n * @returns {{ index: number, total: number | undefined, cumulative: number | undefined, currentValue: number | undefined, safeIndex: number | undefined }} The 0-based index and the total sum, or -1 if not found.\n */\n findIndexAtOrBefore(\n target: number,\n options?: MaterializeConfig,\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n return this._findIndex(target, options ?? {}, false)\n }\n}\n\n/**\n * @hook useFenwickMapTree\n * @description A React hook that creates and manages a `FenwickMapTree` instance.\n * The tree instance is stable across re-renders. A new tree instance is created\n * if `size` or `valueOrFn` changes.\n * @description `FenwickMapTree` インスタンスを作成・管理する React フック。\n * ツリーインスタンスは再レンダリングされても同一性を維持する。`size` または `valueOrFn` が\n * 変更された場合に新しいインスタンスが作成される。\n * @param {number} size - The total number of items.\n * @param {number | ((index: number) => number)} valueOrFn - The value for all elements, or a function to generate values.\n * @param {number | ((index: number) => number)} valueOrFn - 全要素の均一な値、または値を生成する関数。不要なツリーの再作成を防ぐため、この関数は `useCallback` でメモ化すること。\n * @param {{ sampleRange?: { from: number; to: number } }} [options] - Optional settings for initialization. To prevent unnecessary re-creations of the tree, memoize this object with `useMemo`.\n * @param {{ sampleRange?: { from: number; to: number } }} [options] - 初期化時のオプション設定。不要なツリーの再作成を防ぐため、このオブジェクトは `useMemo` でメモ化すること。\n * @returns {FenwickMapTree} The FenwickMapTree instance.\n * @returns {FenwickMapTree} FenwickMapTree インスタンス。\n */\nexport const useFenwickMapTree = (size: number, valueOrFn: number | ((index: number) => number), options?: { sampleRange?: { from: number; to: number } }): FenwickMapTree => {\n const validSize = Math.max(0, size)\n const prevTreeRef = useRef<FenwickMapTree | null>(null)\n\n const tree = useMemo(() => {\n const newTree = new FenwickMapTree(validSize, valueOrFn, options)\n return newTree\n }, [validSize, valueOrFn, options])\n\n // インスタンスが更新された場合にログを出力\n if (!Object.is(prevTreeRef.current, tree)) {\n console.warn(\"[useFenwickMapTree] instance changed\")\n }\n prevTreeRef.current = tree\n\n return tree\n}\n","/**\n * @module useLruCache\n * @description This module provides a `useLruCache` hook, which implements a Least Recently Used (LRU) cache.\n * It uses a Map for O(1) key-based lookups and a doubly linked list to maintain the order of usage, ensuring that get, set, and eviction operations are all efficient.\n *\n * @description このモジュールは、Least Recently Used (LRU) キャッシュを実装した `useLruCache` フックを提供します。\n * Map を使用した O(1) のキー検索と、使用順序を維持するための双方向連結リストを組み合わせることで、get, set, および削除操作のすべてを効率的に行います。\n */\nimport { useCallback, useEffect, useRef, useState } from \"react\"\n\n/**\n * @class DoublyLinkedListNode\n * @description Represents a node in the doubly linked list. It holds a key-value pair and references to the previous and next nodes.\n * @description 双方向連結リスト内のノードを表します。キーと値のペア、および前後のノードへの参照を保持します。\n */\nclass DoublyLinkedListNode<K, V> {\n key: K\n value: V\n prev: DoublyLinkedListNode<K, V> | null = null\n next: DoublyLinkedListNode<K, V> | null = null\n\n constructor(key: K, value: V) {\n // キーを初期化\n this.key = key\n // 値を初期化\n this.value = value\n }\n}\n\n/**\n * @class DoublyLinkedList\n * @description Implements a doubly linked list to maintain the usage order of cache items.\n * The tail of the list represents the most recently used item, and the head represents the least recently used item.\n * @description キャッシュアイテムの使用順序を維持するための双方向連結リストを実装します。\n * リストの末尾が最も最近使用されたアイテムを、先頭が最も最近使用されていないアイテムを示します。\n */\nclass DoublyLinkedList<K, V> {\n private head: DoublyLinkedListNode<K, V> | null = null\n private tail: DoublyLinkedListNode<K, V> | null = null\n\n /**\n * @method addToTail\n * @description Adds a node to the tail of the list, marking it as the most recently used.\n * @description ノードをリストの末尾に追加し、最も最近使用されたものとしてマークします。\n * @param {DoublyLinkedListNode<K, V>} node - The node to add.\n */\n addToTail(node: DoublyLinkedListNode<K, V>) {\n // リストが既に末尾ノードを持っているかチェック\n if (this.tail) {\n // 既存の末尾ノードの次に新しいノードをリンク\n this.tail.next = node\n // 新しいノードの前に既存の末尾ノードをリンク\n node.prev = this.tail\n // リストの末尾を新しいノードに更新\n this.tail = node\n } else {\n // リストが空の場合、新しいノードが先頭かつ末尾となる\n this.head = this.tail = node\n }\n }\n\n /**\n * @method remove\n * @description Removes a given node from the list.\n * @description 指定されたノードをリストから削除します。\n * @param {DoublyLinkedListNode<K, V>} node - The node to remove.\n */\n remove(node: DoublyLinkedListNode<K, V>) {\n // ノードに前のノードが存在する場合\n if (node.prev) {\n // 前のノードの `next` を、現在のノードの `next` につなぎ直す\n node.prev.next = node.next\n } else {\n // ノードが先頭の場合、リストの先頭を次のノードに更新\n this.head = node.next\n }\n\n // ノードに次のノードが存在する場合\n if (node.next) {\n // 次のノードの `prev` を、現在のノードの `prev` につなぎ直す\n node.next.prev = node.prev\n } else {\n // ノードが末尾の場合、リストの末尾を前のノードに更新\n this.tail = node.prev\n }\n\n // 削除されたノードの参照をクリア\n node.prev = null\n node.next = null\n }\n\n /**\n * @method removeHead\n * @description Removes and returns the head of the list, which is the least recently used item.\n * @description リストの先頭(最も最近使用されていないアイテム)を削除して返します。\n * @returns {DoublyLinkedListNode<K, V> | null} The removed head node, or null if the list is empty.\n */\n removeHead(): DoublyLinkedListNode<K, V> | null {\n // 現在の先頭ノードを保持\n const head = this.head\n // 先頭ノードが存在する場合のみ処理\n if (head) {\n // 先頭ノードをリストから削除\n this.remove(head)\n }\n // 削除したノード(または null)を返す\n return head\n }\n\n /**\n * @method moveToTail\n * @description Moves an existing node to the tail of the list to mark it as most recently used.\n * @description 既存のノードをリストの末尾に移動し、最も最近使用されたものとしてマークします。\n * @param {DoublyLinkedListNode<K, V>} node - The node to move.\n */\n moveToTail(node: DoublyLinkedListNode<K, V>) {\n // ノードを現在の位置から一旦削除\n this.remove(node)\n // ノードをリストの末尾に再追加\n this.addToTail(node)\n }\n}\n\n/**\n * @hook useLruCache\n * @description A custom hook that provides a Least Recently Used (LRU) cache of a specified capacity.\n * It returns an object with methods to interact with the cache (`get`, `set`, `has`, `clear`).\n * @description 指定された容量の LRU (Least Recently Used) キャッシュを提供するカスタムフック。\n * キャッシュを操作するためのメソッド (`get`, `set`, `has`, `clear`) を持つオブジェクトを返します。\n * @param {number} capacity - The maximum capacity of the cache.\n * @returns {{ get: (key: K) => V | undefined, set: (key: K, value: V) => void, has: (key: K) => boolean, clear: () => void }} An object with methods to interact with the cache.\n */\nexport function useLruCache<K, V>(capacity: number) {\n // キャッシュストレージ。キーと双方向連結リストのノードをマッピングする (O(1) アクセス用)\n const cache = useRef(new Map<K, DoublyLinkedListNode<K, V>>())\n // 使用順序を管理する双方向連結リスト (先頭が最も古く、末尾が最も新しい)\n const list = useRef(new DoublyLinkedList<K, V>())\n\n useEffect(() => {\n while (cache.current.size > capacity) {\n const lruNode = list.current.removeHead()\n if (lruNode) {\n cache.current.delete(lruNode.key)\n } else {\n // This should not happen if cache.current.size > 0\n break\n }\n }\n }, [capacity])\n\n /**\n * @function get\n * @description Retrieves a value from the cache for a given key. If found, the item is marked as most recently used.\n * @description 指定されたキーの値を取得します。アイテムが見つかった場合、それは最も最近使用されたものとしてマークされます。\n * @param {K} key - The key of the item to retrieve.\n * @returns {V | undefined} The cached value, or undefined if the key does not exist.\n */\n const get = useCallback((key: K): V | undefined => {\n // Map からノードを効率的に検索\n const node = cache.current.get(key)\n // ノードが存在する場合\n if (node) {\n // アクセスされたノードを使用順序リストの末尾に移動\n list.current.moveToTail(node)\n // ノードの値を返す\n return node.value\n }\n // ノードが存在しない場合は undefined を返す\n return undefined\n }, [])\n\n /**\n * @function set\n * @description Adds or updates a key-value pair in the cache. If the cache is full, it evicts the least recently used item.\n * @description キーと値のペアをキャッシュに追加または更新します。キャッシュが満杯の場合、最も最近使用されていないアイテムが削除されます。\n * @param {K} key - The key of the item to set.\n * @param {V} value - The value of the item to set.\n */\n const set = useCallback(\n (key: K, value: V) => {\n if (capacity <= 0) {\n return\n }\n // キャッシュ内にキーが既に存在するかチェック\n let node = cache.current.get(key)\n\n if (node) {\n // キーが存在する場合、値を更新\n node.value = value\n // アクセスされたので、使用順序リストの末尾に移動\n list.current.moveToTail(node)\n } else {\n // 新しいノードを追加する場合\n // キャッシュが容量上限に達しているかチェック\n if (cache.current.size >= capacity) {\n // 容量オーバーの場合、最も最近使用されていないノード (リストの先頭) を取得して削除\n const lruNode = list.current.removeHead()\n if (lruNode) {\n // Map からも対応するエントリを削除\n cache.current.delete(lruNode.key)\n }\n }\n // 新しいノードを作成\n node = new DoublyLinkedListNode(key, value)\n // 新しいノードを Map に登録\n cache.current.set(key, node)\n // 新しいノードを使用順序リストの末尾に追加\n list.current.addToTail(node)\n }\n },\n [capacity],\n )\n\n /**\n * @function has\n * @description Checks if a key exists in the cache.\n * @description 指定されたキーがキャッシュ内に存在するかどうかを確認します。\n * @param {K} key - The key to check.\n * @returns {boolean} True if the key exists, false otherwise.\n */\n const has = useCallback((key: K): boolean => {\n // Map にキーが存在するかどうかを O(1) でチェック\n return cache.current.has(key)\n }, [])\n\n /**\n * @function clear\n * @description Clears the entire cache, removing all entries.\n * @description キャッシュを完全にクリアし、すべてのエントリを削除します。\n */\n const clear = useCallback(() => {\n // Map をクリア\n cache.current.clear()\n // 双方向連結リストを新しく作成してリセット\n list.current = new DoublyLinkedList<K, V>()\n }, [])\n\n const [handler, setHandler] = useState(() => ({ get, set, has, clear }))\n\n useEffect(() => setHandler({ get, set, has, clear }), [get, set, has, clear])\n\n // キャッシュ操作用の API を返す\n return handler\n}\n","/**\n * @module useHeightCache\n * @description This module provides a hook for caching item heights using an LRU (Least Recently Used) cache.\n * It is designed to be used in virtual scrolling components to optimize performance by storing and retrieving the heights of rendered items.\n *\n * @description このモジュールは、LRU (Least Recently Used) キャッシュを使用してアイテムの高さをキャッシュするためのフックを提供します。\n * 仮想スクロールコンポーネントで使用されることを想定しており、レンダリングされたアイテムの高さを保存および取得することでパフォーマンスを最適化します。\n */\nimport { useLruCache } from \"./useLruCache.ts\"\n\n// LRU キャッシュに保存する高さの測定値の最大数\nconst HEIGHT_CACHE_CAPACITY = 10000\n\n/**\n * A custom hook that provides a cache for storing the heights of items, backed by an LRU cache.\n * This helps in optimizing virtual scrolling by avoiding re-computation of item heights.\n * The key is the item's index (number), and the value is its height (number).\n *\n * LRU キャッシュを利用して、アイテムの高さを保存するためのキャッシュを提供するカスタムフック。\n * これにより、アイテムの高さの再計算を回避し、仮想スクロールを最適化します。\n * キーはアイテムのインデックス (number)、値はその高さ (number) です。\n */\nexport const useHeightCache = () => {\n // useLruCache フックを初期化し、指定された容量でキャッシュインスタンスを作成\n const { get, set, has, clear } = useLruCache<number, number>(HEIGHT_CACHE_CAPACITY)\n\n // キャッシュを操作するための関数 (get, set, has, clear) を返す\n return { get, set, has, clear }\n}\n","import { forwardRef, type ReactNode, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from \"react\"\nimport { Logger } from \"./logger.ts\"\nimport { ScrollPane, type ScrollPaneHandle, type ScrollPaneProps } from \"./ScrollPane.tsx\"\nimport { useFenwickMapTree } from \"./useFenwickMapTree.ts\"\nimport { minmax } from \"./utils.ts\"\n\nexport type VirtualScrollHandle = ScrollPaneHandle & {\n scrollToIndex: (index: number) => void\n getFenwickTreeTotalHeight: () => number\n getFenwickSize: () => number\n}\n\ntype VirtualScrollProps<T> = {\n itemCount: number\n getItem: (index: number) => T\n getItemHeight: (index: number) => number\n viewportSize: number\n overscanCount?: number\n className?: string\n onScroll?: (scrollPosition: number, totalHeight: number) => void\n onRangeChange?: (renderingStartIndex: number, renderingEndIndex: number, visibleStartIndex: number, visibleEndIndex: number, scrollPosition: number, totalHeight: number) => void\n background?: ReactNode\n children: (item: T, index: number) => ReactNode\n initialScrollIndex?: number\n initialScrollOffset?: number\n tapScrollCircleOptions?: ScrollPaneProps[\"tapScrollCircleOptions\"]\n scrollBarWidth?: number\n enableThumbDrag?: ScrollPaneProps[\"enableThumbDrag\"]\n enableTrackClick?: ScrollPaneProps[\"enableTrackClick\"]\n enableArrowButtons?: ScrollPaneProps[\"enableArrowButtons\"]\n enablePointerDrag?: ScrollPaneProps[\"enablePointerDrag\"]\n inertiaOptions?: ScrollPaneProps[\"inertiaOptions\"]\n}\n\nconst sanitizeIndex = (value: number, size: number) => (size <= 0 ? 0 : minmax(value, 0, size - 1))\n\n/**\n * Calculates rendering boundaries from current scroll metrics.\n *\n * 現在のスクロール情報から描画範囲を算出。\n */\nconst computeRenderingRanges = (\n scrollPosition: number,\n viewportSize: number,\n overscanCount: number,\n size: number,\n getItemHeight: (index: number) => number,\n fenwickTree: ReturnType<typeof useFenwickMapTree>,\n) => {\n if (size === 0) {\n return { renderingStartIndex: 0, renderingEndIndex: 0, visibleStartIndex: 0, visibleEndIndex: 0 }\n }\n const { index: rawStartIndex, cumulative, currentValue } = fenwickTree.findIndexAtOrAfter(scrollPosition, { materializeOption: { materialize: false } })\n const baseIndex = rawStartIndex === -1 ? 0 : rawStartIndex\n const adjustedStart = rawStartIndex !== -1 && (cumulative ?? 0) < scrollPosition + (currentValue ?? 0) ? baseIndex + 1 : baseIndex\n const visibleStartIndex = sanitizeIndex(adjustedStart, size)\n const renderingStartIndex = sanitizeIndex(visibleStartIndex - overscanCount, size)\n\n let visibleHeight = 0\n let cursor = visibleStartIndex\n while (cursor < size && visibleHeight < viewportSize) {\n visibleHeight += getItemHeight(cursor)\n cursor++\n }\n const visibleEndIndex = sanitizeIndex(cursor - 1, size)\n const renderingEndIndex = sanitizeIndex(visibleEndIndex + overscanCount, size)\n\n return { renderingStartIndex, renderingEndIndex, visibleStartIndex, visibleEndIndex }\n}\n\nfunction VirtualScrollInner<T>({ itemCount, getItem, getItemHeight, viewportSize, overscanCount = 5, className, onScroll, onRangeChange, children, background, initialScrollIndex, initialScrollOffset, tapScrollCircleOptions, scrollBarWidth, enableThumbDrag, enableTrackClick, enableArrowButtons, enablePointerDrag, inertiaOptions }: VirtualScrollProps<T>, ref: React.Ref<VirtualScrollHandle>) {\n const scrollPaneRef = useRef<VirtualScrollHandle>(null)\n const isMounted = useRef(false)\n\n useEffect(() => {\n isMounted.current = true\n return () => {\n isMounted.current = false\n }\n }, [])\n\n const fenwickTreeInitArgs = useRef({ size: itemCount, valueOrFn: getItemHeight, options: { sampleRange: { from: 0, to: 100 } } })\n const fenwickTree = useFenwickMapTree(fenwickTreeInitArgs.current.size, fenwickTreeInitArgs.current.valueOrFn, fenwickTreeInitArgs.current.options)\n\n const [initialValues] = useState(() => {\n let position = 0\n let total = 0\n if (typeof initialScrollIndex === \"number\") {\n const safeIndex = minmax(initialScrollIndex, 0, itemCount - 1)\n const safeIndexFrom = minmax(safeIndex - overscanCount * 2, 0, itemCount - 1)\n const safeIndexTo = minmax(safeIndex + overscanCount * 2, 0, itemCount - 1)\n const options = initialScrollIndex > 0 ? { materializeOption: { materialize: true, ranges: [{ from: safeIndexFrom, to: safeIndexTo }] } } : undefined\n const { cumulative, total: materializedTotal, currentValue } = fenwickTree.prefixSum(initialScrollIndex, options)\n position = cumulative - currentValue\n total = materializedTotal ?? fenwickTree.getTotal()\n } else if (typeof initialScrollOffset === \"number\") {\n position = initialScrollOffset\n total = fenwickTree.getTotal()\n } else {\n total = fenwickTree.getTotal()\n }\n return { position, total }\n })\n\n const [scrollPosition, setScrollPosition] = useState(initialValues.position)\n const [contentSize, setContentSize] = useState<number>(initialValues.total)\n const [shouldPaneScrollTo, setShouldPaneScrollTo] = useState<number | null>(initialValues.position)\n\n const [fenwickSize, setFenwickSize] = useState<number>(itemCount)\n\n useLayoutEffect(() => {\n fenwickTree.setValueFn(getItemHeight)\n if (fenwickSize !== itemCount) {\n fenwickTree.changeSize(itemCount)\n setFenwickSize(itemCount)\n }\n const totalHeight = fenwickTree.getTotal()\n if (contentSize !== totalHeight) {\n setContentSize(totalHeight)\n }\n }, [fenwickTree, fenwickSize, itemCount, contentSize, getItemHeight])\n\n useLayoutEffect(() => {\n // スクロールより前に、コンテンツのサイズを更新する必要があるので、 useLayoutEffect で同期処理\n if (shouldPaneScrollTo !== null && scrollPaneRef.current) {\n Logger.debug(\"[VirtualScroll] Scrolling to position:\", shouldPaneScrollTo)\n scrollPaneRef.current.scrollTo(shouldPaneScrollTo)\n setShouldPaneScrollTo(null)\n }\n }, [shouldPaneScrollTo])\n\n const scrollToIndex = useCallback(\n (index: number) => {\n if (!scrollPaneRef.current) {\n return\n }\n const safeIndex = sanitizeIndex(index, fenwickSize)\n const safeIndexFrom = sanitizeIndex(safeIndex - overscanCount * 2, fenwickSize)\n const safeIndexTo = sanitizeIndex(safeIndex + overscanCount * 2, fenwickSize)\n const { cumulative: offset, total, currentValue } = fenwickTree.prefixSum(safeIndex, { materializeOption: { materialize: true, ranges: [{ from: safeIndexFrom, to: safeIndexTo }] } })\n\n Logger.debug(\"[VirtualScroll] Scrolling to index:\", safeIndex, \"Offset:\", offset, \"Total height:\", total, \"Current value:\", currentValue, \"safeIndexFrom:\", safeIndexFrom, \"safeIndexTo:\", safeIndexTo)\n\n if (!total) {\n return\n }\n setContentSize(total)\n setShouldPaneScrollTo(offset - currentValue)\n Logger.debug(\"[VirtualScroll] Setting scroll position to:\", offset - currentValue)\n },\n [fenwickTree, overscanCount, fenwickSize],\n )\n\n const scrollTo = useCallback(\n (newPosition: number) => {\n if (!scrollPaneRef.current) {\n return\n }\n const total = fenwickTree.getTotal()\n const safePosition = minmax(Math.floor(newPosition), 0, total)\n const index = fenwickTree.findIndexAtOrAfter(safePosition, { materializeOption: { materialize: false } }).index\n scrollToIndex(index)\n },\n [fenwickTree, scrollToIndex],\n )\n\n const handleScroll = useCallback(\n (newPosition: number, _prevPosition: number) => {\n Logger.debug(\"[VirtualScroll] Scroll position changed:\", newPosition)\n\n // スクロール位置を更新\n setScrollPosition(newPosition)\n // 高さを更新\n const totalHeight = fenwickTree.getTotal()\n // if (contentSize !== totalHeight) {\n // setContentSize(totalHeight)\n // }\n // コールバックを呼び出す\n onScroll?.(newPosition, totalHeight)\n },\n [fenwickTree, onScroll],\n )\n\n // レンダリング範囲を計算\n const renderingRanges = useMemo(() => {\n const ranges = computeRenderingRanges(scrollPosition, viewportSize, overscanCount, fenwickSize, getItemHeight, fenwickTree)\n Logger.debug(\"[VirtualScroll] Calculated rendering range:\", {\n ...ranges,\n scrollPosition,\n renderingContentSize: fenwickTree.getTotal(),\n overscanCount,\n viewportSize,\n })\n return ranges\n }, [scrollPosition, viewportSize, overscanCount, fenwickSize, getItemHeight, fenwickTree])\n\n // レンダリング範囲が変更されたらコールバックを呼ぶ\n useEffect(() => {\n const scrollPaneScrollPosition = scrollPaneRef.current?.getScrollPosition() ?? 0\n Logger.debug(\"[VirtualScroll] Range change effect triggered\", {\n renderingStartIndex: renderingRanges.renderingStartIndex,\n renderingEndIndex: renderingRanges.renderingEndIndex,\n visibleStartIndex: renderingRanges.visibleStartIndex,\n visibleEndIndex: renderingRanges.visibleEndIndex,\n scrollPosition,\n contentSize,\n scrollPaneScrollPosition,\n })\n onRangeChange?.(renderingRanges.renderingStartIndex, renderingRanges.renderingEndIndex, renderingRanges.visibleStartIndex, renderingRanges.visibleEndIndex, scrollPosition, contentSize)\n }, [renderingRanges.renderingStartIndex, renderingRanges.renderingEndIndex, renderingRanges.visibleStartIndex, renderingRanges.visibleEndIndex, onRangeChange, scrollPosition, contentSize])\n\n const renderVisibleItems = useCallback(\n (currentScrollPosition: number) => {\n const { renderingStartIndex, renderingEndIndex } = renderingRanges\n Logger.debug(\"[VirtualScroll] Rendering visible items\", { currentScrollPosition, renderingStartIndex, renderingEndIndex, fenwickSize, viewportSize })\n\n if (fenwickSize === 0) {\n return (\n <div className=\"absolute w-full\" style={{ top: 0 }}>\n <div className=\"text-center text-gray-500\">No items</div>\n </div>\n )\n }\n\n const safeRenderingStartIndex = sanitizeIndex(renderingStartIndex, fenwickSize)\n const { cumulative, currentValue: oldHeight } = fenwickTree.prefixSum(safeRenderingStartIndex, { materializeOption: { materialize: false } })\n const startPosition = cumulative - oldHeight // スクロール位置を調整\n\n const visibleItems: Array<{ item: T; height: number; index: number }> = []\n const toUpdateHeights: Array<{ index: number; value: number }> = []\n\n for (let i = renderingStartIndex; i <= renderingEndIndex; i++) {\n const newHeight = getItemHeight(i)\n visibleItems.push({ item: getItem(i), height: newHeight, index: i })\n const oldHeight = fenwickTree.get(i)\n if (oldHeight !== newHeight) {\n toUpdateHeights.push({ index: i, value: newHeight })\n }\n }\n\n if (toUpdateHeights.length > 0) {\n // レンダリング中に状態を更新しないように、更新処理をマイクロタスクにスケジュールする\n Promise.resolve().then(() => {\n const total = fenwickTree.updates(toUpdateHeights)\n if (total) {\n setContentSize(total)\n Logger.debug(\"[VirtualScroll] Updated heights for items\", toUpdateHeights, \"New total height:\", total)\n }\n })\n }\n\n // 全体の高さがビューポートより小さい場合は、topを0に固定\n const containerTop = contentSize < viewportSize ? 0 : startPosition - currentScrollPosition\n\n Logger.debug(\"[VirtualScroll] Rendering items\", { visibleItems, containerTop })\n\n return (\n <div className=\"absolute w-full\" style={{ top: containerTop }}>\n {visibleItems.map(({ item, index: actualIndex }) => {\n const safeActualIndex = sanitizeIndex(actualIndex, fenwickSize)\n const { cumulative, currentValue: currentHeight } = fenwickTree.prefixSum(safeActualIndex, { materializeOption: { materialize: false } })\n const actualOffset = cumulative - currentHeight\n\n return (\n <div\n key={actualIndex}\n data-index={actualIndex}\n style={{\n position: \"absolute\",\n top: actualOffset - startPosition,\n width: \"100%\",\n }}>\n {children(item, actualIndex)}\n </div>\n )\n })}\n </div>\n )\n },\n [getItem, children, contentSize, viewportSize, renderingRanges, fenwickTree, fenwickSize, getItemHeight],\n )\n\n useImperativeHandle(ref, () => ({\n getScrollPosition: () => scrollPaneRef.current?.getScrollPosition() ?? -1,\n getContentSize: () => scrollPaneRef.current?.getContentSize() ?? -1,\n getViewportSize: () => scrollPaneRef.current?.getViewportSize() ?? -1,\n scrollTo,\n scrollToIndex,\n getFenwickTreeTotalHeight: () => fenwickTree.getTotal(),\n getFenwickSize: () => fenwickTree.getSize(),\n }), [scrollTo, scrollToIndex, fenwickTree])\n\n return (\n <ScrollPane\n ref={scrollPaneRef}\n contentSize={contentSize}\n viewportSize={viewportSize}\n className={className}\n onScroll={handleScroll}\n background={background}\n tapScrollCircleOptions={tapScrollCircleOptions}\n inertiaOptions={inertiaOptions}\n itemCount={itemCount}\n scrollBarWidth={scrollBarWidth}\n enableThumbDrag={enableThumbDrag}\n enableTrackClick={enableTrackClick}\n enableArrowButtons={enableArrowButtons}\n enablePointerDrag={enablePointerDrag}>\n {renderVisibleItems}\n </ScrollPane>\n )\n}\n\nexport const VirtualScroll = forwardRef(VirtualScrollInner) as <T>(props: VirtualScrollProps<T> & { ref?: React.Ref<VirtualScrollHandle> }) => React.ReactElement\n"],"names":["INITIAL_STATE","DEAD_ZONE","defaultRenderVisual","dragState","normalizedDistance","scale","glow","innerOpacity","baseTransition","jsxs","Fragment","jsx","TapScrollCircle","forwardRef","onDragChange","className","maxVisualDistance","size","style","opacity","renderVisual","ref","setDragState","useState","pointerIdRef","useRef","centerRef","rootRef","applyDragState","useCallback","nextState","updateDragState","clientX","clientY","capture","x","y","offsetX","offsetY","distance","direction","releasePointerCapture","pointerId","element","resetState","releasePointer","handlePointerDown","event","left","top","width","height","handlePointerMove","handlePointerUp","useImperativeHandle","clampedOpacity","sizeScale","normalized","pullOffset","visualRenderer","visualProps","rootStyle","twMerge","minmax","value","min","max","capturePointerMove","onMove","onEnd","isTouchEvent","startPosition","moveEvent","movePosition","TAP_SCROLL_CANCEL_EVENT","MIN_THUMB_SIZE","ARROW_HOLD_DELAY","ARROW_HOLD_INTERVAL","MIN_ARROW_STEP","ARROW_STEP_DIVISOR","TAP_SCROLL_MAX_DISTANCE","TAP_SCROLL_INITIAL_STATE","TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER","TAP_SCROLL_AUTO_SPEED_PER_ORDER","TAP_SCROLL_AUTO_SPEED_MAX_MULTIPLIER","DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS","computeAutoTapScrollMaxSpeedMultiplier","itemCount","clampedCount","ordersOfMagnitude","multiplier","ScrollBar","contentSize","viewportSize","scrollPosition","onScroll","enableThumbDrag","enableTrackClick","enableArrowButtons","horizontal","scrollBarWidth","ariaControls","tapScrollCircleOptions","isDragging","setIsDragging","isThumbHovered","setIsThumbHovered","isTapActive","setIsTapActive","thumbRef","latestScrollPositionRef","arrowHoldIntervalRef","arrowHoldTimeoutRef","tapDragStateRef","tapCircleHandleRef","autoScrollFrameRef","lastAutoScrollTimestampRef","resolvedTapScrollOptions","useMemo","manualMaxSpeedMultiplier","maxSpeedMultiplier","tapCircleEnabled","tapCircleSize","tapCircleOffsetX","tapCircleOffsetY","tapCircleClassName","tapCircleMaxDistance","tapCircleMaxSpeedMultiplier","tapCircleOpacity","tapCircleRenderVisual","mainSizeKey","crossSizeKey","positionKey","clientCoordinateKey","selectDelta","deltaX","deltaY","getPointerCoordinate","point","arrowLabels","arrowIcons","directionClass","effectiveTapMaxDistance","scrollRatio","arrowButtonLength","trackLength","rawThumbSize","thumbSize","maxScrollPosition","effectiveTrackLength","thumbPosition","scrollBarVisible","canUseArrowButtons","useEffect","hoverScale","dragScale","clearArrowTimers","stopAutoScroll","resetTapScroll","stepAutoScroll","timestamp","state","lastTimestamp","deltaSeconds","eased","minSpeed","maxSpeed","speed","prevPosition","nextPosition","startAutoScroll","handleTapCircleDragChange","handleTapScrollCancel","targetPaneId","targetNode","translateToScrollPosition","thumbPositionValue","clampedThumbPosition","scrollByStep","step","prev","next","handleArrowPointerUp","handleArrowPointerDown","handleArrowKeyDown","handlePointerDownOnThumb","startThumbPosition","delta","handlePointerDownOnTrack","position","startMousePosition","rect","clickPositionInTrack","tapCircleOpacityValue","tapCircleStyle","baseTop","renderArrowButton","label","icon","Logger","message","args","DEFAULT_INERTIA_OPTIONS","toggleListeners","target","entries","action","type","listener","options","ScrollPane","children","enablePointerDrag","background","inertiaOptions","scrollPositionRef","_","_forceUpdate","useReducer","scrollContainerRef","contentAreaRef","inertiaStateRef","resolvedInertiaOptions","sizeRef","isScrollable","scrollTo","newPosition","currentContentSize","currentViewportSize","currentIsScrollable","newScrollPosition","stopInertia","startInertia","initialVelocity","maxVelocity","minVelocity","deceleration","startVelocityThreshold","limitedVelocity","deltaTime","previousVelocity","nextVelocity","decelerationAmount","previousPosition","prevPositionInternal","reachedBoundary","useLayoutEffect","handleWheel","scrollContainer","id","useId","DRAG_ACTIVATION_THRESHOLD","dragPointerId","dragStartClientY","dragStartScroll","shouldCancelNextClick","clickResetTimer","velocitySamples","pushVelocitySample","now","sample","shouldIgnoreTarget","handleClickCapture","startDragging","endDrag","inertiaVelocity","lastSample","firstSample","deltaClientY","handlePointerCancel","elementEntries","windowEntries","clamp","tapScrollCircleSampleVisual","radius","stretchY","stretchX","tail","pupilScale","tailBase","baseHeight","coreSize","rodHeight","rodTranslate","rodWidth","limitedX","limitedY","pupilRange","pupilX","pupilY","highlightX","highlightY","highlightSize","highlightOpacity","active","FenwickMapTree","valueOrFn","range","mode","materializedValues","i","index","change","from","to","values","a","b","mid","frequencies","maxFreq","count","modes","sum","updates","deltaUpdates","currentDelta","treeIndex","oldValue","updateTree","oldDelta","newDelta","changeForTree","option","forceIndex","ranges","first","last","chooseLowerBound","low","high","ans","result","finalTotal","safeIndex","materializeOption","treeNodeValue","currentValue","total","lastPrefix","valueFn","newTree","newTotal","theoreticalTotal","newSize","oldSize","useFenwickMapTree","validSize","prevTreeRef","tree","DoublyLinkedListNode","key","DoublyLinkedList","node","head","useLruCache","capacity","cache","list","lruNode","get","set","has","clear","handler","setHandler","HEIGHT_CACHE_CAPACITY","useHeightCache","sanitizeIndex","computeRenderingRanges","overscanCount","getItemHeight","fenwickTree","rawStartIndex","cumulative","baseIndex","adjustedStart","visibleStartIndex","renderingStartIndex","visibleHeight","cursor","visibleEndIndex","renderingEndIndex","VirtualScrollInner","getItem","onRangeChange","initialScrollIndex","initialScrollOffset","scrollPaneRef","isMounted","fenwickTreeInitArgs","initialValues","safeIndexFrom","safeIndexTo","materializedTotal","setScrollPosition","setContentSize","shouldPaneScrollTo","setShouldPaneScrollTo","fenwickSize","setFenwickSize","totalHeight","scrollToIndex","offset","safePosition","handleScroll","_prevPosition","renderingRanges","scrollPaneScrollPosition","renderVisibleItems","currentScrollPosition","safeRenderingStartIndex","oldHeight","visibleItems","toUpdateHeights","newHeight","containerTop","item","actualIndex","safeActualIndex","currentHeight","actualOffset","VirtualScroll"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/TapScrollCircle.tsx","../src/utils.ts","../src/ScrollBar.tsx","../src/logger.ts","../src/ScrollPane.tsx","../src/tapScrollCircleSampleVisual.tsx","../src/useFenwickMapTree.ts","../src/useLruCache.ts","../src/useHeightCache.ts","../src/VirtualScroll.tsx"],"sourcesContent":["/**\n * Provides a touch-friendly tap circle for continuous scrolling interactions.\n * タッチ操作向けのタップサークルを提供し、連続スクロール操作を実現するモジュール。\n */\n\nimport type { CSSProperties, ReactNode, PointerEvent as ReactPointerEvent } from \"react\"\nimport { forwardRef, useCallback, useImperativeHandle, useRef, useState } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport type TapScrollCircleDragState = {\n /** Whether the pointer is actively dragging. / ポインターがドラッグ中かどうか。 */\n active: boolean\n /** Signed horizontal offset from the circle center. / サークル中心からの符号付き水平方向オフセット。 */\n offsetX: number\n /** Signed vertical offset from the circle center. / サークル中心からの符号付き垂直オフセット。 */\n offsetY: number\n /** Absolute distance between pointer and center. / ポインターと中心の距離。 */\n distance: number\n /** Drag direction relative to the circle. / サークルに対するドラッグ方向。 */\n direction: -1 | 0 | 1\n}\n\nexport type TapScrollCircleProps = {\n /** Called whenever the drag state updates. / ドラッグ状態が更新された際に呼び出されるコールバック。 */\n onDragChange: (state: TapScrollCircleDragState) => void\n /** Additional class names for styling. / 追加のスタイル用クラス名。 */\n className?: string\n /** Maximum distance used for visual stretching. / 視覚的な伸縮に使用する最大距離。 */\n maxVisualDistance?: number\n /** Diameter of the circle in pixels. / サークルの直径 (ピクセル)。 */\n size?: number\n /** Additional inline styles. / 追加のインラインスタイル。 */\n style?: CSSProperties\n /** Base opacity applied to the circle. / サークル全体に適用する基準透明度。 */\n opacity: number\n /** Custom rendering logic for the visual contents. / ビジュアル内容を描画するカスタムロジック。 */\n renderVisual?: (props: TapScrollCircleRenderProps) => ReactNode\n}\n\nexport type TapScrollCircleHandle = {\n /**\n * Resets the drag state and releases pointer capture if active.\n *\n * ドラッグ状態をリセットし、必要に応じてポインタキャプチャを解除する。\n */\n reset: () => void\n /**\n * Returns the underlying DOM element of the tap circle.\n *\n * タップサークルの DOM 要素を返す。\n */\n getElement: () => HTMLDivElement | null\n}\n\nconst INITIAL_STATE: TapScrollCircleDragState = {\n active: false,\n offsetX: 0,\n offsetY: 0,\n distance: 0,\n direction: 0,\n}\n\nconst DEAD_ZONE = 6\n\nexport type TapScrollCircleRenderProps = {\n /** Current drag state snapshot. / 現在のドラッグ状態のスナップショット。 */\n dragState: TapScrollCircleDragState\n /** Normalized distance within [0, 1]. / 正規化距離 (0 から 1 の範囲)。 */\n normalizedDistance: number\n /** Relative scale based on size. / サイズに基づく相対スケール。 */\n sizeScale: number\n /** Circle diameter in pixels. / サークル直径 (ピクセル)。 */\n size: number\n /** Applied opacity value. / 適用中の不透明度値。 */\n opacity: number\n}\n\nconst defaultRenderVisual = ({ dragState, normalizedDistance }: TapScrollCircleRenderProps) => {\n const scale = 1 + normalizedDistance * 0.18\n const glow = 0.16 + normalizedDistance * 0.24\n const innerOpacity = 0.38 + normalizedDistance * 0.28\n const baseTransition = dragState.active ? \"80ms ease-out\" : \"220ms ease\"\n\n return (\n <>\n <div\n className=\"absolute inset-0 rounded-full\"\n style={{\n background: \"linear-gradient(140deg, rgba(255,255,255,0.62), rgba(72,72,72,0.48))\",\n boxShadow: `0 0 0 1px rgba(255,255,255,0.28), 0 10px 22px rgba(0,0,0,${glow})`,\n transform: `scale(${scale})`,\n transition: `${baseTransition}, ${dragState.active ? \"80ms\" : \"260ms\"} box-shadow ease`,\n }}\n />\n <div\n className=\"absolute inset-[18%] rounded-full\"\n style={{\n background: \"linear-gradient(140deg, rgba(255,255,255,0.72), rgba(28,28,28,0.58))\",\n boxShadow: \"inset 0 4px 10px rgba(0,0,0,0.24), inset 0 0 2px rgba(255,255,255,0.55)\",\n opacity: innerOpacity,\n transition: dragState.active ? \"120ms opacity ease-out\" : \"220ms opacity ease\",\n }}\n />\n </>\n )\n}\n\n/**\n * A circular touch handle that stretches toward the drag direction.\n * タップした方向へ伸縮するタッチ操作用サークル。\n */\nexport const TapScrollCircle = forwardRef<TapScrollCircleHandle, TapScrollCircleProps>(({ onDragChange, className, maxVisualDistance = 160, size = 40, style, opacity = 1, renderVisual }, ref) => {\n const [dragState, setDragState] = useState<TapScrollCircleDragState>(INITIAL_STATE)\n const pointerIdRef = useRef<number | null>(null)\n const centerRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 })\n const rootRef = useRef<HTMLDivElement>(null)\n\n /**\n * Updates drag state and notifies listeners.\n *\n * ドラッグ状態を更新してリスナーに通知。\n */\n const applyDragState = useCallback((nextState: TapScrollCircleDragState) => {\n setDragState(nextState)\n onDragChange(nextState)\n }, [onDragChange])\n\n const updateDragState = useCallback(\n (clientX: number, clientY: number, capture: boolean = false) => {\n const { x, y } = centerRef.current\n const offsetX = clientX - x\n const offsetY = clientY - y\n const distance = Math.abs(offsetY)\n const direction: -1 | 0 | 1 = distance < DEAD_ZONE ? 0 : offsetY < 0 ? -1 : 1\n applyDragState({\n active: capture || distance >= DEAD_ZONE,\n offsetX,\n offsetY,\n distance,\n direction,\n })\n },\n [applyDragState],\n )\n\n const releasePointerCapture = useCallback((pointerId: number | null) => {\n if (pointerId === null) {\n return\n }\n const element = rootRef.current\n if (element?.hasPointerCapture(pointerId)) {\n element.releasePointerCapture(pointerId)\n }\n }, [])\n\n const resetState = useCallback(\n (releasePointer: boolean = false) => {\n if (releasePointer) {\n releasePointerCapture(pointerIdRef.current)\n }\n pointerIdRef.current = null\n applyDragState(INITIAL_STATE)\n },\n [applyDragState, releasePointerCapture],\n )\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n event.preventDefault()\n event.stopPropagation()\n const element = rootRef.current ?? event.currentTarget\n const { left, top, width, height } = element.getBoundingClientRect()\n centerRef.current = { x: left + width / 2, y: top + height / 2 }\n pointerIdRef.current = event.pointerId\n element.setPointerCapture(event.pointerId)\n updateDragState(event.clientX, event.clientY, true)\n },\n [updateDragState],\n )\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n if (pointerIdRef.current !== event.pointerId) {\n return\n }\n event.preventDefault()\n updateDragState(event.clientX, event.clientY)\n },\n [updateDragState],\n )\n\n const handlePointerUp = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n if (pointerIdRef.current !== event.pointerId) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n resetState(true)\n },\n [resetState],\n )\n\n useImperativeHandle(\n ref,\n () => ({\n reset: () => {\n resetState(true)\n },\n getElement: () => rootRef.current,\n }),\n [resetState],\n )\n\n const clampedOpacity = Math.min(Math.max(opacity, 0), 1)\n const sizeScale = size / 64\n const normalized = Math.min(dragState.distance, maxVisualDistance) / maxVisualDistance\n const pullOffset = dragState.direction * normalized * 10 * sizeScale\n const visualRenderer = renderVisual ?? defaultRenderVisual\n const visualProps: TapScrollCircleRenderProps = {\n dragState,\n normalizedDistance: normalized,\n sizeScale,\n size,\n opacity: clampedOpacity,\n }\n const rootStyle: CSSProperties = {\n ...style,\n width: size,\n height: size,\n transform: `translateY(${pullOffset}px)`\n }\n rootStyle.opacity = clampedOpacity\n return (\n <div\n ref={rootRef}\n className={twMerge(\n \"relative flex touch-none select-none items-center justify-center\",\n \"transition-transform duration-100 ease-out\",\n className,\n )}\n style={rootStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n role=\"presentation\">\n {visualRenderer(visualProps)}\n </div>\n )\n})\n\nTapScrollCircle.displayName = \"TapScrollCircle\"\n","/**\n * Clamps a value between a minimum and maximum value.\n *\n * 指定された値が最小値と最大値の範囲内に収まるように調整。\n *\n * @param value The value to clamp. / クランプする値。\n * @param min The minimum value. / 最小値。\n * @param max The maximum value. / 最大値。\n * @returns The clamped value. / クランプされた値。\n */\nexport const minmax = (value: number, min: number, max: number): number => {\n return Math.min(max, Math.max(min, value))\n}\n","/**\n * Provides a customizable virtual scrollbar component with auxiliary tap scrolling features.\n *\n * カスタマイズ可能な仮想スクロールバーと補助的なタップスクロール機能を提供。\n */\nimport type { CSSProperties, ReactNode } from \"react\"\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\nimport { TapScrollCircle, type TapScrollCircleDragState, type TapScrollCircleHandle, type TapScrollCircleRenderProps } from \"./TapScrollCircle.tsx\"\nimport { minmax } from \"./utils.ts\"\n\ntype OrientationConfig = {\n mainSizeKey: \"width\" | \"height\"\n crossSizeKey: \"width\" | \"height\"\n positionKey: \"left\" | \"top\"\n selectDelta: (deltaX: number, deltaY: number) => number\n getPointerCoordinate: (point: { clientX: number; clientY: number }) => number\n arrowLabels: [string, string]\n arrowIcons: [string, string]\n directionClass: string\n orientation: \"vertical\" | \"horizontal\"\n}\n\ntype ArrowAutoRepeatOptions = {\n canUseArrowButtons: boolean\n enableArrowButtons: boolean\n resetTapScroll: () => void\n scrollByStep: (direction: 1 | -1) => void\n}\n\ntype ArrowAutoRepeatHandlers = {\n handleArrowPointerDown: (direction: 1 | -1) => (event: React.MouseEvent<HTMLButtonElement> | React.TouchEvent<HTMLButtonElement>) => void\n handleArrowPointerUp: () => void\n handleArrowKeyDown: (direction: 1 | -1) => (event: React.KeyboardEvent<HTMLButtonElement>) => void\n}\n\ntype ThumbVisualFeedbackOptions = {\n thumbRef: React.RefObject<HTMLDivElement | null>\n isDragging: boolean\n isThumbHovered: boolean\n enableThumbDrag: boolean\n horizontal: boolean\n}\n\n/**\n * Captures mouse and touch move events globally to track dragging.\n *\n * ドラッグ操作を追跡するために、マウスとタッチの移動イベントをグローバルにキャプチャ。\n *\n * @param event The initial mouse or touch event. / 初期のマウスまたはタッチイベント。\n * @param onMove A callback function that is called when the pointer moves. / ポインターが移動したときに呼び出されるコールバック関数。\n * @param onEnd A callback function that is called when the pointer is released. / ポインターが離されたときに呼び出されるコールバック関数。\n */\nconst capturePointerMove = (event: React.MouseEvent | React.TouchEvent, onMove: (event: { deltaX: number; deltaY: number }) => void, onEnd?: () => void) => {\n const isTouchEvent = \"touches\" in event.nativeEvent\n const startPosition = isTouchEvent ? (event as React.TouchEvent).nativeEvent.touches[0] : (event as React.MouseEvent).nativeEvent\n\n const handlePointerMove = (moveEvent: MouseEvent | TouchEvent) => {\n // ドラッグ中のデフォルトのブラウザ動作(スクロールなど)を防止\n if (isTouchEvent && moveEvent.cancelable) {\n moveEvent.preventDefault()\n }\n const movePosition = \"touches\" in moveEvent ? moveEvent.touches[0] : moveEvent\n onMove({\n deltaX: movePosition.clientX - startPosition.clientX,\n deltaY: movePosition.clientY - startPosition.clientY,\n })\n }\n\n const handlePointerUp = () => {\n if (isTouchEvent) {\n document.removeEventListener(\"touchmove\", handlePointerMove as (e: TouchEvent) => void)\n document.removeEventListener(\"touchend\", handlePointerUp)\n } else {\n document.removeEventListener(\"mousemove\", handlePointerMove as (e: MouseEvent) => void)\n document.removeEventListener(\"mouseup\", handlePointerUp)\n }\n onEnd?.()\n }\n\n if (isTouchEvent) {\n document.addEventListener(\"touchmove\", handlePointerMove as (e: TouchEvent) => void, { passive: false })\n document.addEventListener(\"touchend\", handlePointerUp)\n } else {\n document.addEventListener(\"mousemove\", handlePointerMove as (e: MouseEvent) => void)\n document.addEventListener(\"mouseup\", handlePointerUp)\n }\n}\n\n/**\n * Options to customize the auxiliary tap scroll circle.\n *\n * タップスクロール用サークルをカスタマイズするためのオプション。\n */\nexport type ScrollBarTapCircleOptions = {\n /** Enable or disable the tap scroll circle. / タップサークルを有効化または無効化。 */\n enabled?: boolean\n /** Circle diameter in pixels. / サークルの直径 (ピクセル)。 */\n size?: number\n /** Horizontal offset in pixels. / 水平方向オフセット (ピクセル)。 */\n offsetX?: number\n /** Vertical offset in pixels. / 垂直方向オフセット (ピクセル)。 */\n offsetY?: number\n /** Additional class names for the circle. / サークルの追加クラス名。 */\n className?: string\n /** Maximum drag distance used for visual feedback. / ビジュアルフィードバックに利用する最大ドラッグ距離。 */\n maxVisualDistance?: number\n /** Maximum speed multiplier relative to viewport size. / ビューポートサイズに対する最大速度倍率。 */\n maxSpeedMultiplier?: number\n /** Minimum speed multiplier relative to viewport size. / ビューポートサイズに対する最小速度倍率。 */\n minSpeedMultiplier?: number\n /** Base opacity multiplier for the circle visuals. / サークル表示の基準透明度倍率。 */\n opacity?: number\n /** Custom visual renderer for the tap circle. / タップサークルのカスタムビジュアルのレンダラー。 */\n renderVisual?: (props: TapScrollCircleRenderProps) => ReactNode\n /** Optional exponential cap configuration for max speed. / 最大速度に指数関数的な上限を設定するためのオプション設定。 */\n maxSpeedCurve?: {\n // Steepness factor for the exponential curve. / 指数関数の急峻さを決定する要素。\n exponentialSteepness: number\n // Scale factor for the exponential curve. / 指数関数のスケールファクター。\n exponentialScale?: number\n // Additional eased offset to apply to the curve. / 曲線に適用する追加のイーズドオフセット。\n easedOffset?: number\n }\n}\n\ntype ResolvedTapScrollCircleOptions = Required<Omit<ScrollBarTapCircleOptions, \"className\" | \"maxVisualDistance\" | \"renderVisual\" | \"maxSpeedCurve\">> & {\n className?: string\n maxVisualDistance: number\n renderVisual?: ScrollBarTapCircleOptions[\"renderVisual\"]\n maxSpeedCurve?: ScrollBarTapCircleOptions[\"maxSpeedCurve\"]\n}\n\ntype TapScrollCancelEventDetail = {\n paneId?: string\n}\n\n/** Custom event name emitted when external interactions should cancel tap scrolling. */\nexport const TAP_SCROLL_CANCEL_EVENT = \"virtualscroll:tap-scroll-cancel\"\n\n/**\n * Props for the ScrollBar component.\n *\n * ScrollBar コンポーネントの Props。\n */\nexport type ScrollBarThumbOverlayRenderProps = {\n orientation: \"vertical\" | \"horizontal\"\n scrollPosition: number\n maxScrollPosition: number\n contentSize: number\n viewportSize: number\n thumbSize: number\n thumbPosition: number\n thumbCenter: number\n trackSize: number\n isDragging: boolean\n isTapScrollActive: boolean\n}\n\nexport type ScrollBarProps = {\n /** The total size of the content. / コンテンツの総サイズ。 */\n contentSize: number\n /** The size of the visible area. / 表示領域のサイズ。 */\n viewportSize: number\n /** The current scroll position. / 現在のスクロール位置。 */\n scrollPosition: number\n /** A callback function that is called when the scroll position changes. / スクロール位置が変更されたときに呼び出されるコールバック関数。 */\n onScroll?: (scrollPosition: number, prevPosition: number) => void\n /** Whether grabbing the scrollbar thumb is allowed. / スクロールバーのつまみ操作を許可するかどうか。 */\n enableThumbDrag?: boolean\n /** Whether clicking on the track moves the scrollbar. / スクロールバーのトラッククリック操作を許可するかどうか。 */\n enableTrackClick?: boolean\n /** Whether arrow buttons control the scroll position. / 矢印ボタンによるスクロール操作を許可するかどうか。 */\n enableArrowButtons?: boolean\n /** Whether the scrollbar is horizontal. / スクロールバーが水平かどうか。 */\n horizontal?: boolean\n /** The width of the scrollbar. / スクロールバーの幅。 */\n scrollBarWidth?: number\n /** Additional class names for the component. / コンポーネントの追加のクラス名。 */\n className?: string\n /** The ID of the element that the scrollbar controls. / スクロールバーが制御する要素の ID。 */\n ariaControls?: string\n /** Configuration for the tap scroll circle. / タップサークルの設定。 */\n tapScrollCircleOptions?: ScrollBarTapCircleOptions\n /** Total number of scrollable items (optional). / スクロール対象アイテムの総数(任意)。 */\n itemCount?: number\n /** Optional renderer for thumb-adjacent overlays. / サム付近に重ねるオーバーレイのレンダラー。 */\n renderThumbOverlay?: (props: ScrollBarThumbOverlayRenderProps) => ReactNode\n}\n\n/** The minimum size of the scrollbar thumb. / スクロールバーのつまみの最小サイズ。 */\nconst MIN_THUMB_SIZE = 20\nconst ARROW_HOLD_DELAY = 250\nconst ARROW_HOLD_INTERVAL = 60\nconst MIN_ARROW_STEP = 20\nconst ARROW_STEP_DIVISOR = 20\nconst TAP_SCROLL_MAX_DISTANCE = 220\nconst TAP_SCROLL_INITIAL_STATE: TapScrollCircleDragState = { active: false, offsetX: 0, offsetY: 0, distance: 0, direction: 0 }\n\nconst TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER = 2.2\nconst TAP_SCROLL_AUTO_SPEED_PER_ORDER = 8\nconst TAP_SCROLL_AUTO_SPEED_MAX_MULTIPLIER = 120\n\nconst DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS: ResolvedTapScrollCircleOptions = {\n enabled: true,\n size: 40,\n offsetX: -80,\n offsetY: 0,\n className: undefined,\n maxVisualDistance: TAP_SCROLL_MAX_DISTANCE,\n maxSpeedMultiplier: TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER,\n minSpeedMultiplier: 0.2,\n opacity: 1,\n renderVisual: undefined,\n maxSpeedCurve: undefined,\n}\n\n/**\n * Creates the orientation dependent configuration for the scrollbar.\n *\n * スクロールバーの向きに応じた設定を生成。\n */\nconst createOrientationConfig = (horizontal: boolean): OrientationConfig => {\n if (horizontal) {\n return {\n mainSizeKey: \"width\",\n crossSizeKey: \"height\",\n positionKey: \"left\",\n selectDelta: (deltaX: number, _deltaY: number) => deltaX,\n getPointerCoordinate: ({ clientX }) => clientX,\n arrowLabels: [\"Scroll left\", \"Scroll right\"],\n arrowIcons: [\"◀\", \"▶\"],\n directionClass: \"flex flex-row items-stretch\",\n orientation: \"horizontal\",\n }\n }\n\n return {\n mainSizeKey: \"height\",\n crossSizeKey: \"width\",\n positionKey: \"top\",\n selectDelta: (_deltaX: number, deltaY: number) => deltaY,\n getPointerCoordinate: ({ clientY }) => clientY,\n arrowLabels: [\"Scroll up\", \"Scroll down\"],\n arrowIcons: [\"▲\", \"▼\"],\n directionClass: \"flex flex-col items-stretch\",\n orientation: \"vertical\",\n }\n}\n\n/**\n * Resolves user supplied tap scroll circle options with internal defaults.\n *\n * ユーザー指定のタップスクロールサークル設定を内部デフォルトで補完。\n */\nconst resolveTapScrollCircleOptions = (options: ScrollBarTapCircleOptions | undefined, itemCount?: number): ResolvedTapScrollCircleOptions => {\n const manualMaxSpeedMultiplier = options?.maxSpeedMultiplier\n const maxSpeedMultiplier = typeof manualMaxSpeedMultiplier === \"number\" ? manualMaxSpeedMultiplier : computeAutoTapScrollMaxSpeedMultiplier(itemCount)\n\n return {\n enabled: options?.enabled ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.enabled,\n size: options?.size ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.size,\n offsetX: options?.offsetX ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.offsetX,\n offsetY: options?.offsetY ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.offsetY,\n className: options?.className ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.className,\n maxVisualDistance: options?.maxVisualDistance ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.maxVisualDistance,\n maxSpeedMultiplier,\n minSpeedMultiplier: Math.max(options?.minSpeedMultiplier ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.minSpeedMultiplier, 0),\n opacity: minmax(options?.opacity ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.opacity, 0, 1),\n renderVisual: options?.renderVisual ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.renderVisual,\n maxSpeedCurve: options?.maxSpeedCurve ?? DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS.maxSpeedCurve,\n }\n}\n\n/**\n * Applies hover and drag visual feedback to the scrollbar thumb.\n *\n * スクロールバーつまみのホバーとドラッグ時の見た目を適用。\n */\nconst useThumbVisualFeedback = ({ thumbRef, isDragging, isThumbHovered, enableThumbDrag, horizontal }: ThumbVisualFeedbackOptions) => {\n useEffect(() => {\n const element = thumbRef.current\n if (!element) {\n return\n }\n\n const hoverScale = horizontal ? \"scaleY(1.06)\" : \"scaleX(1.06)\"\n const dragScale = horizontal ? \"scaleY(1.12)\" : \"scaleX(1.12)\"\n\n if (!enableThumbDrag) {\n element.style.removeProperty(\"transform\")\n element.style.backgroundColor = \"#7F7F7F\"\n element.style.removeProperty(\"transition\")\n return\n }\n\n if (isDragging) {\n element.style.transform = dragScale\n element.style.backgroundColor = \"#4F4F4F\"\n element.style.transition = \"transform 60ms ease-out\"\n return\n }\n\n element.style.transition = \"transform 80ms ease-out\"\n if (isThumbHovered) {\n element.style.transform = hoverScale\n element.style.backgroundColor = \"#5F5F5F\"\n } else {\n element.style.removeProperty(\"transform\")\n element.style.backgroundColor = \"#7F7F7F\"\n }\n }, [enableThumbDrag, horizontal, isDragging, isThumbHovered, thumbRef])\n}\n\n/**\n * Provides handlers for scrollbar arrow auto-repeat interactions.\n *\n * スクロールバー矢印の自動リピート操作向けハンドラーを提供。\n */\nconst useArrowAutoRepeat = ({ canUseArrowButtons, enableArrowButtons, resetTapScroll, scrollByStep }: ArrowAutoRepeatOptions): ArrowAutoRepeatHandlers => {\n const arrowHoldIntervalRef = useRef<number | null>(null)\n const arrowHoldTimeoutRef = useRef<number | null>(null)\n\n const clearArrowTimers = useCallback(() => {\n if (arrowHoldIntervalRef.current !== null) {\n window.clearInterval(arrowHoldIntervalRef.current)\n arrowHoldIntervalRef.current = null\n }\n if (arrowHoldTimeoutRef.current !== null) {\n window.clearTimeout(arrowHoldTimeoutRef.current)\n arrowHoldTimeoutRef.current = null\n }\n }, [])\n\n const handleArrowPointerUp = useCallback(() => {\n clearArrowTimers()\n }, [clearArrowTimers])\n\n const handleArrowPointerDown = useCallback(\n (direction: 1 | -1) => (event: React.MouseEvent<HTMLButtonElement> | React.TouchEvent<HTMLButtonElement>) => {\n if (!canUseArrowButtons) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n resetTapScroll()\n clearArrowTimers()\n scrollByStep(direction)\n arrowHoldTimeoutRef.current = window.setTimeout(() => {\n arrowHoldIntervalRef.current = window.setInterval(() => {\n scrollByStep(direction)\n }, ARROW_HOLD_INTERVAL)\n }, ARROW_HOLD_DELAY)\n },\n [canUseArrowButtons, clearArrowTimers, resetTapScroll, scrollByStep],\n )\n\n const handleArrowKeyDown = useCallback(\n (direction: 1 | -1) => (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (!enableArrowButtons) {\n return\n }\n if (event.key === \"Enter\" || event.key === \" \" || event.key === \"Spacebar\") {\n event.preventDefault()\n scrollByStep(direction)\n }\n },\n [enableArrowButtons, scrollByStep],\n )\n\n useEffect(() => {\n return () => {\n clearArrowTimers()\n }\n }, [clearArrowTimers])\n\n return { handleArrowPointerDown, handleArrowPointerUp, handleArrowKeyDown }\n}\n\n/**\n * Computes the auto-scroll speed multiplier based on item count.\n *\n * アイテム数に応じた自動スクロール速度倍率を算出。\n */\nconst computeAutoTapScrollMaxSpeedMultiplier = (itemCount?: number) => {\n if (!itemCount || itemCount <= 0) {\n return TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER\n }\n\n const clampedCount = Math.max(1, itemCount)\n const ordersOfMagnitude = Math.log10(clampedCount)\n const multiplier = TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER + ordersOfMagnitude * TAP_SCROLL_AUTO_SPEED_PER_ORDER\n return minmax(multiplier, TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER, TAP_SCROLL_AUTO_SPEED_MAX_MULTIPLIER)\n}\n\n/**\n * A custom scrollbar component.\n *\n * カスタムスクロールバーコンポーネント。\n */\nexport const ScrollBar = ({\n contentSize,\n viewportSize,\n scrollPosition,\n onScroll,\n enableThumbDrag = true,\n enableTrackClick = true,\n enableArrowButtons = true,\n horizontal = false,\n scrollBarWidth = 12,\n className,\n ariaControls,\n tapScrollCircleOptions,\n itemCount,\n renderThumbOverlay,\n}: ScrollBarProps) => {\n const [isDragging, setIsDragging] = useState(false)\n const [isThumbHovered, setIsThumbHovered] = useState(false)\n const [isTapActive, setIsTapActive] = useState(false)\n const thumbRef = useRef<HTMLDivElement>(null)\n const latestScrollPositionRef = useRef(scrollPosition)\n const tapDragStateRef = useRef<TapScrollCircleDragState>(TAP_SCROLL_INITIAL_STATE)\n const tapCircleHandleRef = useRef<TapScrollCircleHandle | null>(null)\n const autoScrollFrameRef = useRef<number | null>(null)\n const lastAutoScrollTimestampRef = useRef<number | null>(null)\n const resolvedTapScrollOptions = useMemo<ResolvedTapScrollCircleOptions>(() => resolveTapScrollCircleOptions(tapScrollCircleOptions, itemCount), [itemCount, tapScrollCircleOptions])\n const orientationConfig = useMemo(() => createOrientationConfig(horizontal), [horizontal])\n const {\n enabled: tapCircleEnabled,\n size: tapCircleSize,\n offsetX: tapCircleOffsetX,\n offsetY: tapCircleOffsetY,\n className: tapCircleClassName,\n maxVisualDistance: tapCircleMaxDistance,\n maxSpeedMultiplier: tapCircleMaxSpeedMultiplier,\n minSpeedMultiplier: tapCircleMinSpeedMultiplier,\n opacity: tapCircleOpacity,\n renderVisual: tapCircleRenderVisual,\n maxSpeedCurve: tapCircleMaxSpeedCurve,\n } = resolvedTapScrollOptions\n const { mainSizeKey, crossSizeKey, positionKey, selectDelta, getPointerCoordinate, arrowLabels, arrowIcons, directionClass, orientation } = orientationConfig\n const effectiveTapMaxDistance = Math.max(tapCircleMaxDistance, 1)\n // 表示領域に対するコンテンツの比率\n const scrollRatio = viewportSize / contentSize\n const arrowButtonLength = scrollBarWidth\n const trackLength = Math.max(viewportSize - arrowButtonLength * 2, 0)\n const rawThumbSize = scrollRatio * trackLength\n const thumbSize = Math.min(Math.max(MIN_THUMB_SIZE, rawThumbSize || 0), trackLength || MIN_THUMB_SIZE)\n // 最大スクロール位置\n const maxScrollPosition = contentSize - viewportSize\n const effectiveTrackLength = Math.max(trackLength - thumbSize, 0)\n const thumbPosition = maxScrollPosition <= 0 || effectiveTrackLength <= 0 ? 0 : (scrollPosition / maxScrollPosition) * effectiveTrackLength\n const thumbCenter = thumbPosition + thumbSize / 2\n\n // スクロールバーが表示されるかどうか\n const scrollBarVisible = contentSize > viewportSize\n const canUseArrowButtons = scrollBarVisible && enableArrowButtons\n\n useEffect(() => {\n latestScrollPositionRef.current = scrollPosition\n }, [scrollPosition])\n\n useEffect(() => {\n if (!enableThumbDrag) {\n setIsThumbHovered(false)\n }\n }, [enableThumbDrag])\n\n useThumbVisualFeedback({ thumbRef, isDragging, isThumbHovered, enableThumbDrag, horizontal })\n\n /**\n * Stops the tap circle auto-scroll animation.\n *\n * タップサークルによる自動スクロールを停止。\n */\n const stopAutoScroll = useCallback(() => {\n if (autoScrollFrameRef.current !== null) {\n window.cancelAnimationFrame(autoScrollFrameRef.current)\n autoScrollFrameRef.current = null\n }\n lastAutoScrollTimestampRef.current = null\n }, [])\n\n /**\n * Resets tap circle state and related motion.\n *\n * タップサークルの状態と動作を初期化。\n */\n const resetTapScroll = useCallback(() => {\n tapDragStateRef.current = { ...TAP_SCROLL_INITIAL_STATE }\n setIsTapActive(false)\n tapCircleHandleRef.current?.reset()\n stopAutoScroll()\n }, [stopAutoScroll])\n\n /**\n * Advances tap circle auto-scroll by animation frame.\n *\n * タップサークルの自動スクロールをフレームごとに進行。\n */\n const stepAutoScroll = useCallback(\n (timestamp: number) => {\n const state = tapDragStateRef.current\n if (!state.active || state.direction === 0) {\n stopAutoScroll()\n return\n }\n if (!scrollBarVisible || maxScrollPosition <= 0) {\n stopAutoScroll()\n return\n }\n\n const lastTimestamp = lastAutoScrollTimestampRef.current ?? timestamp\n const deltaSeconds = Math.max((timestamp - lastTimestamp) / 1000, 0)\n lastAutoScrollTimestampRef.current = timestamp\n\n if (deltaSeconds <= 0) {\n autoScrollFrameRef.current = window.requestAnimationFrame(stepAutoScroll)\n return\n }\n\n const normalized = Math.min(state.distance, effectiveTapMaxDistance) / effectiveTapMaxDistance\n const eased = normalized ** 1.1\n const hasCustomMaxSpeedMultiplier = typeof tapScrollCircleOptions?.maxSpeedMultiplier === \"number\"\n const minSpeed = Math.max(viewportSize * tapCircleMinSpeedMultiplier, 40)\n const maxSpeedFloor = hasCustomMaxSpeedMultiplier ? minSpeed : 1200\n const linearMaxSpeed = Math.max(viewportSize * tapCircleMaxSpeedMultiplier, maxSpeedFloor)\n\n let cappedMaxSpeed = linearMaxSpeed\n if (tapCircleMaxSpeedCurve) {\n const steepness = Math.max(tapCircleMaxSpeedCurve.exponentialSteepness, 0)\n const scale = Math.max(tapCircleMaxSpeedCurve.exponentialScale ?? tapCircleMaxSpeedMultiplier, 0)\n const expNumerator = steepness === 0 ? normalized : Math.expm1(steepness * normalized)\n const expDenominator = steepness === 0 ? 1 : Math.expm1(steepness) || 1\n const exponentialRatio = expDenominator === 0 ? normalized : Math.min(Math.max(expNumerator / expDenominator, 0), 1)\n const exponentialMaxSpeed = viewportSize * scale * exponentialRatio\n cappedMaxSpeed = Math.min(cappedMaxSpeed, Math.max(exponentialMaxSpeed, minSpeed))\n }\n\n const maxSpeed = Math.max(cappedMaxSpeed, minSpeed)\n const easedOffset = Math.max(tapCircleMaxSpeedCurve?.easedOffset ?? 0, 0)\n const effectiveEased = Math.min(1, eased + easedOffset)\n const speed = minSpeed + (maxSpeed - minSpeed) * effectiveEased\n\n const prevPosition = latestScrollPositionRef.current\n const nextPosition = minmax(prevPosition + state.direction * speed * deltaSeconds, 0, maxScrollPosition)\n\n if (nextPosition === prevPosition) {\n stopAutoScroll()\n return\n }\n\n latestScrollPositionRef.current = nextPosition\n onScroll?.(nextPosition, prevPosition)\n\n autoScrollFrameRef.current = window.requestAnimationFrame(stepAutoScroll)\n },\n [effectiveTapMaxDistance, maxScrollPosition, onScroll, scrollBarVisible, stopAutoScroll, tapCircleMaxSpeedCurve, tapCircleMaxSpeedMultiplier, tapCircleMinSpeedMultiplier, tapScrollCircleOptions, viewportSize],\n )\n\n /**\n * Starts tap circle auto-scroll loop.\n *\n * タップサークルによる自動スクロールを開始。\n */\n const startAutoScroll = useCallback(() => {\n if (autoScrollFrameRef.current === null) {\n lastAutoScrollTimestampRef.current = null\n autoScrollFrameRef.current = window.requestAnimationFrame(stepAutoScroll)\n }\n }, [stepAutoScroll])\n\n useEffect(() => {\n return () => {\n stopAutoScroll()\n }\n }, [stopAutoScroll])\n\n /**\n * Handles tap circle drag state changes.\n *\n * タップサークルのドラッグ状態変化を処理。\n */\n const handleTapCircleDragChange = useCallback(\n (state: TapScrollCircleDragState) => {\n tapDragStateRef.current = state\n setIsTapActive(state.active)\n if (state.active && state.direction !== 0) {\n startAutoScroll()\n } else {\n stopAutoScroll()\n }\n },\n [startAutoScroll, stopAutoScroll],\n )\n\n useEffect(() => {\n if (!tapCircleEnabled) {\n resetTapScroll()\n }\n }, [resetTapScroll, tapCircleEnabled])\n\n useEffect(() => {\n const handleTapScrollCancel = (event: Event) => {\n const customEvent = event as CustomEvent<TapScrollCancelEventDetail>\n const targetPaneId = customEvent.detail?.paneId\n if (targetPaneId && ariaControls && targetPaneId !== ariaControls) {\n return\n }\n resetTapScroll()\n }\n\n window.addEventListener(TAP_SCROLL_CANCEL_EVENT, handleTapScrollCancel as EventListener)\n return () => {\n window.removeEventListener(TAP_SCROLL_CANCEL_EVENT, handleTapScrollCancel as EventListener)\n }\n }, [ariaControls, resetTapScroll])\n\n useEffect(() => {\n if (!tapCircleEnabled) {\n return\n }\n const handlePointerDown = (event: PointerEvent) => {\n if (!tapDragStateRef.current.active) {\n return\n }\n const targetNode = event.target\n if (!(targetNode instanceof Node)) {\n resetTapScroll()\n return\n }\n const element = tapCircleHandleRef.current?.getElement()\n if (element?.contains(targetNode)) {\n return\n }\n resetTapScroll()\n }\n document.addEventListener(\"pointerdown\", handlePointerDown, true)\n return () => {\n document.removeEventListener(\"pointerdown\", handlePointerDown, true)\n }\n }, [resetTapScroll, tapCircleEnabled])\n\n /**\n * Translates the thumb position to a scroll position.\n *\n * つまみの位置をスクロール位置に変換。\n *\n * @param thumbPosition The position of the thumb. / つまみの位置。\n * @returns The scroll position. / スクロール位置。\n */\n const translateToScrollPosition = (thumbPositionValue: number) => {\n if (!scrollBarVisible || effectiveTrackLength <= 0 || maxScrollPosition <= 0) {\n return 0\n }\n const clampedThumbPosition = minmax(thumbPositionValue, 0, effectiveTrackLength)\n return minmax((clampedThumbPosition / effectiveTrackLength) * maxScrollPosition, 0, maxScrollPosition)\n }\n\n /**\n * Moves scroll position by a fixed step using arrow controls.\n *\n * 矢印操作で一定ステップ分スクロール。\n */\n const scrollByStep = (direction: 1 | -1) => {\n if (!scrollBarVisible || maxScrollPosition <= 0) {\n return\n }\n const step = Math.max(Math.round(viewportSize / ARROW_STEP_DIVISOR), MIN_ARROW_STEP)\n const prev = latestScrollPositionRef.current\n const next = minmax(prev + direction * step, 0, maxScrollPosition)\n if (next === prev) {\n return\n }\n latestScrollPositionRef.current = next\n onScroll?.(next, prev)\n }\n\n const { handleArrowPointerDown, handleArrowPointerUp, handleArrowKeyDown } = useArrowAutoRepeat({\n canUseArrowButtons,\n enableArrowButtons,\n resetTapScroll,\n scrollByStep,\n })\n\n // スクロールバーのつまみをマウスで押したときのハンドラ\n /**\n * Handles pointer down interaction on the thumb.\n *\n * つまみ押下時のインタラクションを処理。\n */\n const handlePointerDownOnThumb = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n if (!enableThumbDrag) {\n event.preventDefault()\n event.stopPropagation()\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if ((\"button\" in event && event.button !== 0) || event.ctrlKey) {\n return\n }\n // event.preventDefault() // ここでは preventDefault しない\n event.stopPropagation()\n resetTapScroll()\n\n // ドラッグ開始時のつまみの位置\n const startThumbPosition = thumbPosition\n setIsDragging(true)\n setIsThumbHovered(true)\n\n // マウスの移動をキャプチャ\n capturePointerMove(\n event,\n ({ deltaX, deltaY }) => {\n const delta = selectDelta(deltaX, deltaY)\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n },\n () => {\n setIsDragging(false)\n if (thumbRef.current && !thumbRef.current.matches(\":hover\")) {\n setIsThumbHovered(false)\n }\n },\n )\n }\n\n // スクロールバーのトラックをマウスで押したときのハンドラ\n /**\n * Handles pointer down interaction on the track.\n *\n * トラック押下時のインタラクションを処理。\n */\n const handlePointerDownOnTrack = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n if (!enableTrackClick) {\n event.preventDefault()\n event.stopPropagation()\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if ((\"button\" in event && event.button !== 0) || event.ctrlKey) {\n return\n }\n\n const isTouchEvent = \"touches\" in event.nativeEvent\n const position = isTouchEvent ? (event as React.TouchEvent).nativeEvent.touches[0] : (event as React.MouseEvent).nativeEvent\n\n // マウスの初期位置を取得\n const startMousePosition = getPointerCoordinate(position)\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n const clickPositionInTrack = startMousePosition - (horizontal ? rect.left : rect.top)\n resetTapScroll()\n\n // クリックした位置にスクロール\n // つまみはクリック位置の中央に配置\n const startThumbPosition = clickPositionInTrack - thumbSize / 2\n onScroll?.(translateToScrollPosition(startThumbPosition), thumbPosition)\n\n // マウスの移動をキャプチャしてドラッグ操作を処理\n capturePointerMove(event, ({ deltaX, deltaY }) => {\n const delta = selectDelta(deltaX, deltaY)\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n })\n }\n\n const tapCircleOpacityValue = useMemo(() => {\n const baseOpacity = isTapActive ? 1 : 0.8\n return minmax(baseOpacity * tapCircleOpacity, 0, 1)\n }, [isTapActive, tapCircleOpacity])\n\n const tapCircleStyle = useMemo<CSSProperties>(() => {\n const diameter = tapCircleSize\n const baseTop = `calc(50% - ${diameter / 2}px + ${tapCircleOffsetY}px)`\n return {\n left: tapCircleOffsetX,\n top: baseTop,\n }\n }, [tapCircleOffsetX, tapCircleOffsetY, tapCircleSize])\n\n /**\n * Renders an arrow button for scrollbar controls.\n *\n * スクロールバー制御用矢印ボタンを描画。\n */\n const renderArrowButton = (direction: 1 | -1, label: string, icon: string) => (\n <button\n type=\"button\"\n className=\"flex items-center justify-center text-[#313131] text-xs transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-[#60a5fa] focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50\"\n style={{\n [mainSizeKey]: arrowButtonLength,\n [crossSizeKey]: scrollBarWidth,\n backgroundColor: \"#E0E0E0\",\n }}\n aria-label={label}\n onMouseDown={handleArrowPointerDown(direction)}\n onTouchStart={handleArrowPointerDown(direction)}\n onMouseUp={handleArrowPointerUp}\n onMouseLeave={handleArrowPointerUp}\n onTouchEnd={handleArrowPointerUp}\n onTouchCancel={handleArrowPointerUp}\n onKeyDown={handleArrowKeyDown(direction)}\n aria-disabled={!enableArrowButtons}\n disabled={!canUseArrowButtons}>\n <span aria-hidden=\"true\">{icon}</span>\n </button>\n )\n\n const overlayProps: ScrollBarThumbOverlayRenderProps | null =\n renderThumbOverlay && scrollBarVisible\n ? {\n orientation,\n scrollPosition,\n maxScrollPosition,\n contentSize,\n viewportSize,\n thumbSize,\n thumbPosition,\n thumbCenter,\n trackSize: trackLength,\n isDragging,\n isTapScrollActive: isTapActive,\n }\n : null\n\n return (\n <div\n className={twMerge(\"group relative cursor-default select-none\", directionClass, className)}\n style={{\n [mainSizeKey]: viewportSize,\n [crossSizeKey]: scrollBarWidth,\n backgroundColor: \"white\",\n userSelect: \"none\",\n position: \"relative\",\n }}\n role=\"scrollbar\"\n tabIndex={-1}\n aria-controls={ariaControls}\n aria-valuenow={scrollPosition}\n aria-valuemin={0}\n aria-valuemax={maxScrollPosition}\n aria-orientation={horizontal ? \"horizontal\" : \"vertical\"}>\n {!horizontal && scrollBarVisible && tapCircleEnabled && (\n <TapScrollCircle\n ref={tapCircleHandleRef}\n className={twMerge(\"pointer-events-auto absolute transition-opacity duration-150\", tapCircleClassName)}\n size={tapCircleSize}\n maxVisualDistance={effectiveTapMaxDistance}\n style={tapCircleStyle}\n opacity={tapCircleOpacityValue}\n renderVisual={tapCircleRenderVisual}\n onDragChange={handleTapCircleDragChange}\n />\n )}\n {renderArrowButton(-1, arrowLabels[0], arrowIcons[0])}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: スクロールトラックのクリックとドラッグを有効にするため */}\n <div\n className=\"relative flex-1\"\n style={{\n backgroundColor: \"#F5F5F5\",\n borderRadius: scrollBarWidth / 2,\n }}\n onMouseDown={handlePointerDownOnTrack}\n onTouchStart={handlePointerDownOnTrack}\n aria-disabled={!enableTrackClick}>\n {overlayProps && (\n <div className=\"pointer-events-none absolute inset-0\" aria-hidden>\n {renderThumbOverlay?.(overlayProps)}\n </div>\n )}\n {/* コンテンツがビューポートより大きい場合にのみつまみを表示 */}\n {scrollBarVisible && (\n // スクロールバーのつまみの当たり判定を広げるためのラッパー\n <div\n className=\"group absolute\"\n style={{\n [mainSizeKey]: thumbSize,\n [positionKey]: thumbPosition,\n ...(horizontal ? { top: 0, bottom: 0 } : { left: 0, right: 0 }),\n }}\n onMouseDown={handlePointerDownOnThumb}\n onTouchStart={handlePointerDownOnThumb}\n role=\"slider\"\n aria-orientation={horizontal ? \"horizontal\" : \"vertical\"}\n aria-valuenow={scrollPosition}\n aria-valuemin={0}\n aria-valuemax={maxScrollPosition}\n aria-disabled={!enableThumbDrag}\n tabIndex={enableThumbDrag ? 0 : -1}>\n {/* スクロールバーのつまみ(可視部分) */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: スクロールバーのつまみは必要なインタラクションです */}\n <div\n ref={thumbRef}\n className={twMerge(\n \"absolute\",\n horizontal\n ? `inset-x-0 inset-y-[1.5px] group-hover:inset-y-[-0.5px] ${isDragging ? \"-inset-y-0.5\" : \"group-active:-inset-y-0.5\"}`\n : `inset-x-[1.5px] inset-y-0 group-hover:inset-x-[-0.5px] ${isDragging ? \"-inset-x-0.5\" : \"group-active:-inset-x-0.5\"}`,\n )}\n style={{\n backgroundColor: \"#7F7F7F\",\n borderRadius: scrollBarWidth - 1,\n cursor: enableThumbDrag ? \"pointer\" : \"default\",\n ...(horizontal\n ? {\n left: 0,\n right: 0,\n top: 1.5,\n bottom: 1.5,\n }\n : {\n top: 0,\n bottom: 0,\n left: 1.5,\n right: 1.5,\n }),\n }}\n onMouseEnter={() => {\n if (enableThumbDrag) {\n setIsThumbHovered(true)\n }\n }}\n onMouseLeave={() => {\n if (enableThumbDrag) {\n setIsThumbHovered(false)\n }\n }}\n />\n </div>\n )}\n </div>\n {renderArrowButton(1, arrowLabels[1], arrowIcons[1])}\n </div>\n )\n}\n","// Simple logger utility for debugging\nexport const Logger = {\n debug(message: string, ...args: unknown[]): void {\n if (typeof window !== \"undefined\" && window.localStorage?.getItem(\"debug\") === \"true\") {\n console.debug(`[VirtualScroll] ${message}`, ...args);\n }\n },\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(`[VirtualScroll] ${message}`, ...args);\n },\n\n error(message: string, ...args: unknown[]): void {\n console.error(`[VirtualScroll] ${message}`, ...args);\n },\n};\n","import { forwardRef, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useReducer, useRef } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\nimport { Logger } from \"./logger.ts\"\nimport { ScrollBar, type ScrollBarTapCircleOptions, type ScrollBarThumbOverlayRenderProps, TAP_SCROLL_CANCEL_EVENT } from \"./ScrollBar.tsx\"\nimport { minmax } from \"./utils.ts\"\n\n/**\n * Props for the ScrollPane component.\n *\n * ScrollPane コンポーネントの Props。\n */\nexport type ScrollPaneProps = {\n /**\n * A function that renders the content of the scroll pane.\n * It receives the current scroll position as an argument.\n *\n * スクロールペインのコンテンツをレンダリングする関数です。\n * 現在のスクロール位置を引数として受け取ります。\n */\n children: (scrollPosition: number) => React.ReactNode\n /** The total size of the content. / コンテンツの総サイズ。 */\n contentSize: number\n /** The size of the visible area. / 表示領域のサイズ。 */\n viewportSize: number\n /** The width of the scrollbar. / スクロールバーの幅。 */\n scrollBarWidth?: number\n /** Whether grabbing the scrollbar thumb is allowed. / スクロールバーのつまみ操作を許可するかどうか。 */\n enableThumbDrag?: boolean\n /** A callback function that is called when the scroll position changes. / スクロール位置が変更されたときに呼び出されるコールバック関数。 */\n onScroll?: (scrollPosition: number, prevPosition: number) => void\n /** Additional class names for the component. / コンポーネントの追加のクラス名。 */\n className?: string\n /** Custom styles for the component. / コンポーネントのカスタムスタイル。 */\n style?: React.CSSProperties\n /** A background element to be rendered behind the content. / コンテンツの背後にレンダリングされる背景要素。 */\n background?: React.ReactNode\n /** Configuration for the tap scroll circle. / タップサークルの設定。 */\n tapScrollCircleOptions?: ScrollBarTapCircleOptions\n /** Configuration for inertia scroll behavior. / 慣性スクロールの設定。 */\n inertiaOptions?: ScrollPaneInertiaOptions\n /** Total number of scrollable items (optional). / スクロール対象アイテムの総数(任意)。 */\n itemCount?: number\n /** Whether clicking the scrollbar track moves the thumb. / スクロールバートラックのクリック操作を許可するかどうか。 */\n enableTrackClick?: boolean\n /** Whether arrow buttons control the scroll position. / 矢印ボタンのスクロール操作を許可するかどうか。 */\n enableArrowButtons?: boolean\n /** Whether dragging the content area scrolls the pane. / コンテンツ領域のドラッグでスクロールさせるかどうか。 */\n enablePointerDrag?: boolean\n /** Optional renderer for thumb overlays. / サム付近に表示するオーバーレイのレンダラー。 */\n renderThumbOverlay?: (props: ScrollBarThumbOverlayRenderProps) => React.ReactNode\n /** Multiplier applied to wheel delta for faster or slower scrolling. / スクロール速度を調整するためのホイールデルタの倍率。 */\n wheelSpeedMultiplier?: number\n}\n\nexport type ScrollPaneInertiaOptions = {\n /** Maximum velocity applied when inertia starts. / 慣性開始時に適用する最大速度。 */\n maxVelocity?: number\n /** Minimum velocity threshold to continue inertia. / 慣性を継続するための最小速度しきい値。 */\n minVelocity?: number\n /** Deceleration applied on every frame. / 各フレームで適用される減速度。 */\n deceleration?: number\n /** Sampling window in milliseconds for pointer velocity calculation. / ポインタの速度計算に用いるミリ秒単位のサンプリング期間。 */\n velocitySampleWindow?: number\n /** Minimum velocity required to start inertia. / 慣性を開始するために必要な最小速度。 */\n startVelocityThreshold?: number\n}\n\ntype ResolvedScrollPaneInertiaOptions = Required<ScrollPaneInertiaOptions>\n\nconst DEFAULT_INERTIA_OPTIONS: ResolvedScrollPaneInertiaOptions = {\n maxVelocity: 6,\n minVelocity: 0.02,\n deceleration: 0.0025,\n velocitySampleWindow: 90,\n startVelocityThreshold: 0.04,\n}\n\ntype ListenerEntry = [string, EventListenerOrEventListenerObject, AddEventListenerOptions | boolean | undefined]\n\n/**\n * Toggles event listeners on a given target.\n *\n * 指定ターゲットにイベントリスナーを追加または削除。\n */\nconst toggleListeners = (target: HTMLElement | Window, entries: ListenerEntry[], action: \"add\" | \"remove\") => {\n for (const [type, listener, options] of entries) {\n if (action === \"add\") {\n target.addEventListener(type, listener, options)\n } else {\n target.removeEventListener(type, listener, options)\n }\n }\n}\n\nexport type ScrollPaneHandle = {\n scrollTo: (newPosition: number) => void\n getScrollPosition: () => number\n getContentSize: () => number\n getViewportSize: () => number\n}\n\n/**\n * A component that provides a scrollable view with a custom scrollbar.\n *\n * カスタムスクロールバーを備えたスクロール可能なビューを提供するコンポーネントです。\n */\nexport const ScrollPane = forwardRef<ScrollPaneHandle, ScrollPaneProps>(({ children, contentSize, viewportSize, scrollBarWidth = 12, enableThumbDrag = true, enableTrackClick = true, enableArrowButtons = true, enablePointerDrag = true, onScroll, className, style, background, tapScrollCircleOptions, inertiaOptions, itemCount, renderThumbOverlay, wheelSpeedMultiplier = 1 }, ref) => {\n const scrollPositionRef = useRef(0)\n const [_, _forceUpdate] = useReducer((x) => x + 1, 0)\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n const contentAreaRef = useRef<HTMLDivElement>(null)\n const inertiaStateRef = useRef<{ frame: number | null; velocity: number; lastTimestamp: number | null }>({\n frame: null,\n velocity: 0,\n lastTimestamp: null,\n })\n\n const resolvedInertiaOptions = useMemo<ResolvedScrollPaneInertiaOptions>(\n () => ({\n maxVelocity: inertiaOptions?.maxVelocity ?? DEFAULT_INERTIA_OPTIONS.maxVelocity,\n minVelocity: inertiaOptions?.minVelocity ?? DEFAULT_INERTIA_OPTIONS.minVelocity,\n deceleration: inertiaOptions?.deceleration ?? DEFAULT_INERTIA_OPTIONS.deceleration,\n velocitySampleWindow: inertiaOptions?.velocitySampleWindow ?? DEFAULT_INERTIA_OPTIONS.velocitySampleWindow,\n startVelocityThreshold: inertiaOptions?.startVelocityThreshold ?? DEFAULT_INERTIA_OPTIONS.startVelocityThreshold,\n }),\n [inertiaOptions],\n )\n\n Logger.debug(\"[ScrollPane] ScrollPane rendered\", { contentSize, viewportSize, scrollBarWidth, className, style, tapScrollCircleOptions, inertiaOptions, enablePointerDrag })\n\n // const size = useMemo(() => ({ contentSize, viewportSize }), [contentSize, viewportSize])\n\n // contentSize と viewportSize を ref として保持\n // const sizeRef = useRef({ contentSize, viewportSize })\n\n const sizeRef = useRef({ contentSize, viewportSize })\n\n const isScrollable = useMemo(() => contentSize > viewportSize, [contentSize, viewportSize])\n\n // useEffect(() => { // useEffect では contentSize や viewportSize の変更が反映される前にレンダリングされて位置がズレる可能性があるため、useLayoutEffect を使用\n // Logger.debug(\"[ScrollPane] ScrollPane size updated\", { contentSize, viewportSize })\n // // サイズが変更されたときに ref を更新\n // sizeRef.current = { contentSize, viewportSize }\n // forceUpdate() // サイズが変更されたときに強制的に再レンダリング\n // }, [contentSize, viewportSize])\n\n // const scrollTo = useCallback(\n // (newPosition: number | ((prev: number) => number)) => {\n // const { contentSize: currentContentSize, viewportSize: currentViewportSize } = sizeRef.current\n // const currentIsScrollable = currentContentSize > currentViewportSize\n // const prevPosition = scrollPositionRef.current\n\n // Logger.debug(\"[ScrollPane] scrollTo called\", { newPosition, currentContentSize, currentViewportSize, currentIsScrollable, prevPosition })\n\n // if (!currentIsScrollable) {\n // // スクロール不可の場合は常に0に\n // if (scrollPositionRef.current !== 0) {\n // scrollPositionRef.current = 0\n // onScroll?.(0, prevPosition)\n // }\n // return\n // }\n // const nextPosition = typeof newPosition === \"function\" ? newPosition(scrollPositionRef.current) : newPosition\n // const newScrollPosition = minmax(nextPosition, 0, currentContentSize - currentViewportSize)\n // if (scrollPositionRef.current !== newScrollPosition) {\n // scrollPositionRef.current = newScrollPosition\n // onScroll?.(newScrollPosition, prevPosition)\n // }\n // },\n // [onScroll]\n // )\n\n const scrollTo = useCallback(\n (newPosition: number | ((prev: number) => number)) => {\n const { contentSize: currentContentSize, viewportSize: currentViewportSize } = sizeRef.current\n const currentIsScrollable = currentContentSize > currentViewportSize\n const prevPosition = scrollPositionRef.current\n\n Logger.debug(\"[ScrollPane] scrollTo called\", { newPosition, contentSize: currentContentSize, viewportSize: currentViewportSize, currentIsScrollable, prevPosition })\n\n if (!currentIsScrollable) {\n // スクロール不可の場合は常に0に\n if (scrollPositionRef.current !== 0) {\n scrollPositionRef.current = 0\n onScroll?.(0, prevPosition)\n }\n return\n }\n const nextPosition = typeof newPosition === \"function\" ? newPosition(scrollPositionRef.current) : newPosition\n const newScrollPosition = minmax(nextPosition, 0, currentContentSize - currentViewportSize)\n if (scrollPositionRef.current !== newScrollPosition) {\n scrollPositionRef.current = newScrollPosition\n onScroll?.(newScrollPosition, prevPosition)\n }\n },\n [onScroll],\n )\n\n const stopInertia = useCallback(() => {\n const state = inertiaStateRef.current\n if (state.frame !== null) {\n cancelAnimationFrame(state.frame)\n }\n state.frame = null\n state.velocity = 0\n state.lastTimestamp = null\n }, [])\n\n const startInertia = useCallback(\n (initialVelocity: number) => {\n if (!isScrollable) {\n return\n }\n\n const { maxVelocity, minVelocity, deceleration, startVelocityThreshold } = resolvedInertiaOptions\n\n const limitedVelocity = minmax(initialVelocity, -maxVelocity, maxVelocity)\n if (Math.abs(limitedVelocity) < startVelocityThreshold) {\n return\n }\n\n stopInertia()\n\n inertiaStateRef.current.velocity = limitedVelocity\n inertiaStateRef.current.lastTimestamp = null\n\n const step = (timestamp: number) => {\n const state = inertiaStateRef.current\n if (state.lastTimestamp === null) {\n state.lastTimestamp = timestamp\n state.frame = requestAnimationFrame(step)\n return\n }\n\n const deltaTime = timestamp - state.lastTimestamp\n state.lastTimestamp = timestamp\n\n if (deltaTime <= 0) {\n state.frame = requestAnimationFrame(step)\n return\n }\n\n const previousVelocity = state.velocity\n let nextVelocity = previousVelocity\n const decelerationAmount = deceleration * deltaTime\n if (previousVelocity > 0) {\n nextVelocity = Math.max(0, previousVelocity - decelerationAmount)\n } else if (previousVelocity < 0) {\n nextVelocity = Math.min(0, previousVelocity + decelerationAmount)\n }\n\n const averageVelocity = (previousVelocity + nextVelocity) / 2\n const distance = averageVelocity * deltaTime\n const previousPosition = scrollPositionRef.current\n\n if (distance !== 0) {\n scrollTo((prevPositionInternal) => prevPositionInternal + distance)\n }\n\n const nextPosition = scrollPositionRef.current\n const { contentSize: currentContentSize, viewportSize: currentViewportSize } = sizeRef.current\n const maxScrollPosition = Math.max(currentContentSize - currentViewportSize, 0)\n\n state.velocity = nextVelocity\n\n const reachedBoundary = nextPosition === previousPosition || (nextPosition <= 0 && nextVelocity <= 0) || (nextPosition >= maxScrollPosition && nextVelocity >= 0)\n\n if (Math.abs(nextVelocity) < minVelocity || reachedBoundary) {\n stopInertia()\n return\n }\n\n state.frame = requestAnimationFrame(step)\n }\n\n inertiaStateRef.current.frame = requestAnimationFrame(step)\n },\n [isScrollable, resolvedInertiaOptions, scrollTo, stopInertia],\n )\n\n useLayoutEffect(() => {\n // contentSize と viewportSize の最新値を保持して scrollTo の参照を安定させる\n sizeRef.current = { contentSize, viewportSize }\n }, [contentSize, viewportSize])\n\n // contentSize または viewportSize が変更されたときにスクロール位置を調整します。\n useLayoutEffect(() => {\n // useEffect では contentSize や viewportSize の変更が反映される前にレンダリングされて位置がズレる可能性があるため、useLayoutEffect を使用。フリッカー防止も。\n if (isScrollable) {\n Logger.debug(\"[ScrollPane] Adjusting scroll position due to content or viewport size change\", { contentSize, viewportSize, scrollPosition: scrollPositionRef.current })\n const maxScrollPosition = minmax(contentSize - viewportSize, 0, contentSize)\n if (scrollPositionRef.current > maxScrollPosition) {\n scrollTo(maxScrollPosition)\n }\n } else {\n scrollTo(0)\n }\n }, [isScrollable, scrollTo, contentSize, viewportSize])\n\n // useEffect(() => {\n // // ホイールイベントのハンドラ\n // const handleWheel = (event: WheelEvent) => {\n // if (!isScrollable) {\n // return\n // }\n\n // event.preventDefault()\n\n // let deltaY = event.deltaY\n\n // // deltaMode に応じてスクロール量を調整\n // if (event.deltaMode === 1) {\n // // DOM_DELTA_LINE: 行単位のスクロール\n // const lineHeight = 16 // 1行のおおよその高さ (ピクセル)\n // deltaY *= lineHeight\n // } else if (event.deltaMode === 2) {\n // // DOM_DELTA_PAGE: ページ単位のスクロール\n // deltaY *= sizeRef.current.viewportSize // ビューポートの高さを基準にスクロール\n // }\n\n // Logger.debug(\"[ScrollPane] wheel event\", { deltaY, scrollPosition: scrollPositionRef.current })\n\n // // スクロール位置を更新\n // scrollTo((prev) => prev + deltaY)\n // }\n\n // const scrollContainer = scrollContainerRef.current\n // if (scrollContainer) {\n // // wheel イベントリスナーを passive: false で登録し、preventDefault を可能にする\n // scrollContainer.addEventListener(\"wheel\", handleWheel, { passive: false })\n // }\n\n // // クリーンアップ関数\n // return () => {\n // if (scrollContainer) {\n // scrollContainer.removeEventListener(\"wheel\", handleWheel)\n // }\n // }\n // }, [isScrollable, scrollTo])\n\n useEffect(() => {\n // ホイールイベントのハンドラ\n const handleWheel = (event: WheelEvent) => {\n if (!isScrollable) {\n return\n }\n\n event.preventDefault()\n\n stopInertia()\n\n let deltaY = event.deltaY\n\n // deltaMode に応じてスクロール量を調整\n if (event.deltaMode === 1) {\n // DOM_DELTA_LINE: 行単位のスクロール\n const lineHeight = 16 // 1行のおおよその高さ (ピクセル)\n deltaY *= lineHeight\n } else if (event.deltaMode === 2) {\n // DOM_DELTA_PAGE: ページ単位のスクロール\n deltaY *= viewportSize // ビューポートの高さを基準にスクロール\n }\n\n if (wheelSpeedMultiplier !== 1) {\n deltaY *= wheelSpeedMultiplier\n }\n\n Logger.debug(\"[ScrollPane] wheel event\", { deltaY, scrollPosition: scrollPositionRef.current, wheelSpeedMultiplier })\n\n // スクロール位置を更新\n scrollTo((prev) => prev + deltaY)\n }\n\n const scrollContainer = scrollContainerRef.current\n if (scrollContainer) {\n // wheel イベントリスナーを passive: false で登録し、preventDefault を可能にする\n scrollContainer.addEventListener(\"wheel\", handleWheel, { passive: false })\n }\n\n // クリーンアップ関数\n return () => {\n if (scrollContainer) {\n scrollContainer.removeEventListener(\"wheel\", handleWheel)\n }\n }\n }, [isScrollable, scrollTo, stopInertia, viewportSize, wheelSpeedMultiplier])\n\n useImperativeHandle(\n ref,\n () => ({\n scrollTo,\n getScrollPosition: () => scrollPositionRef.current,\n getContentSize: () => contentSize,\n getViewportSize: () => viewportSize,\n }),\n [scrollTo, contentSize, viewportSize],\n )\n\n const id = useId()\n\n useEffect(() => {\n const element = contentAreaRef.current\n if (!element) {\n return\n }\n\n if (!enablePointerDrag) {\n stopInertia()\n return\n }\n\n const DRAG_ACTIVATION_THRESHOLD = 6\n let dragPointerId: number | null = null\n let dragStartClientY = 0\n let dragStartScroll = 0\n let isDragging = false\n let shouldCancelNextClick = false\n let clickResetTimer: number | null = null\n let velocitySamples: { clientY: number; time: number }[] = []\n\n const resetState = () => {\n dragPointerId = null\n dragStartClientY = 0\n dragStartScroll = 0\n isDragging = false\n velocitySamples = []\n }\n\n const pushVelocitySample = (clientY: number) => {\n const now = performance.now()\n velocitySamples.push({ clientY, time: now })\n velocitySamples = velocitySamples.filter((sample) => now - sample.time <= resolvedInertiaOptions.velocitySampleWindow)\n }\n\n const shouldIgnoreTarget = (target: EventTarget | null) => target instanceof HTMLElement && target.closest(\"[data-scrollpane-ignore-drag='true']\") !== null\n\n const handleClickCapture = (event: MouseEvent) => {\n if (!shouldCancelNextClick) {\n return\n }\n event.preventDefault()\n event.stopPropagation()\n shouldCancelNextClick = false\n }\n\n const startDragging = (event: PointerEvent) => {\n if (isDragging) {\n return\n }\n isDragging = true\n shouldCancelNextClick = true\n if (!element.hasPointerCapture(event.pointerId)) {\n element.setPointerCapture(event.pointerId)\n }\n pushVelocitySample(event.clientY)\n }\n\n const handlePointerMove = (event: PointerEvent) => {\n if (dragPointerId !== event.pointerId) {\n return\n }\n\n if (!isDragging) {\n const distanceY = Math.abs(event.clientY - dragStartClientY)\n if (distanceY < DRAG_ACTIVATION_THRESHOLD) {\n return\n }\n startDragging(event)\n if (!isDragging) {\n return\n }\n }\n\n pushVelocitySample(event.clientY)\n\n const deltaY = event.clientY - dragStartClientY\n const nextPosition = dragStartScroll - deltaY\n scrollTo(nextPosition)\n\n if (event.cancelable) {\n event.preventDefault()\n }\n }\n\n const endDrag = (event: PointerEvent) => {\n if (dragPointerId !== event.pointerId) {\n return\n }\n\n if (isDragging && shouldCancelNextClick && event.cancelable) {\n event.preventDefault()\n event.stopPropagation()\n }\n\n if (element.hasPointerCapture(event.pointerId)) {\n element.releasePointerCapture(event.pointerId)\n }\n\n let inertiaVelocity = 0\n if (isDragging && velocitySamples.length >= 2) {\n const lastSample = velocitySamples[velocitySamples.length - 1]\n const firstSample = velocitySamples.find((sample) => lastSample.time - sample.time <= resolvedInertiaOptions.velocitySampleWindow) ?? velocitySamples[0]\n if (lastSample && firstSample && lastSample.time !== firstSample.time) {\n const deltaClientY = lastSample.clientY - firstSample.clientY\n const deltaTime = lastSample.time - firstSample.time\n inertiaVelocity = -(deltaClientY / deltaTime)\n }\n }\n\n resetState()\n\n if (clickResetTimer !== null) {\n window.clearTimeout(clickResetTimer)\n }\n if (shouldCancelNextClick) {\n clickResetTimer = window.setTimeout(() => {\n shouldCancelNextClick = false\n clickResetTimer = null\n }, 0)\n }\n\n if (Math.abs(inertiaVelocity) >= resolvedInertiaOptions.startVelocityThreshold) {\n startInertia(inertiaVelocity)\n }\n }\n\n const handlePointerDown = (event: PointerEvent) => {\n if (!isScrollable) {\n return\n }\n if (event.button !== 0 && event.pointerType === \"mouse\") {\n return\n }\n if (event.ctrlKey || event.metaKey || event.altKey) {\n return\n }\n if (shouldIgnoreTarget(event.target)) {\n return\n }\n\n window.dispatchEvent(new CustomEvent(TAP_SCROLL_CANCEL_EVENT, { detail: { paneId: id } }))\n\n stopInertia()\n\n dragPointerId = event.pointerId\n dragStartClientY = event.clientY\n dragStartScroll = scrollPositionRef.current\n isDragging = false\n shouldCancelNextClick = false\n velocitySamples = []\n }\n\n const handlePointerCancel = (event: PointerEvent) => {\n if (dragPointerId !== event.pointerId) {\n return\n }\n shouldCancelNextClick = false\n if (element.hasPointerCapture(event.pointerId)) {\n element.releasePointerCapture(event.pointerId)\n }\n if (clickResetTimer !== null) {\n window.clearTimeout(clickResetTimer)\n clickResetTimer = null\n }\n resetState()\n }\n\n const elementEntries: ListenerEntry[] = [\n [\"click\", handleClickCapture as EventListenerOrEventListenerObject, true],\n [\"pointerdown\", handlePointerDown as EventListenerOrEventListenerObject, { passive: false }],\n [\"pointermove\", handlePointerMove as EventListenerOrEventListenerObject, { passive: false }],\n [\"pointerup\", endDrag as EventListenerOrEventListenerObject, undefined],\n [\"pointercancel\", handlePointerCancel as EventListenerOrEventListenerObject, undefined],\n ]\n const windowEntries: ListenerEntry[] = [\n [\"pointermove\", handlePointerMove as EventListenerOrEventListenerObject, { passive: false }],\n [\"pointerup\", endDrag as EventListenerOrEventListenerObject, undefined],\n [\"pointercancel\", handlePointerCancel as EventListenerOrEventListenerObject, undefined],\n ]\n\n toggleListeners(element, elementEntries, \"add\")\n toggleListeners(window, windowEntries, \"add\")\n\n return () => {\n toggleListeners(element, elementEntries, \"remove\")\n toggleListeners(window, windowEntries, \"remove\")\n if (dragPointerId !== null && element.hasPointerCapture(dragPointerId)) {\n element.releasePointerCapture(dragPointerId)\n }\n if (clickResetTimer !== null) {\n window.clearTimeout(clickResetTimer)\n }\n stopInertia()\n }\n }, [enablePointerDrag, id, isScrollable, resolvedInertiaOptions, scrollTo, startInertia, stopInertia])\n\n return (\n <div ref={scrollContainerRef} className={twMerge(\"flex\", className)} style={style}>\n <div\n ref={contentAreaRef}\n className=\"relative h-full flex-1 overflow-hidden\"\n style={{ height: viewportSize, ...(enablePointerDrag ? { touchAction: \"none\" } : {}) }}\n id={id}>\n {background}\n {children(scrollPositionRef.current)}\n </div>\n {isScrollable && (\n <ScrollBar\n contentSize={contentSize}\n viewportSize={viewportSize}\n scrollPosition={scrollPositionRef.current}\n onScroll={scrollTo}\n enableThumbDrag={enableThumbDrag}\n enableTrackClick={enableTrackClick}\n enableArrowButtons={enableArrowButtons}\n scrollBarWidth={scrollBarWidth}\n ariaControls={id}\n tapScrollCircleOptions={tapScrollCircleOptions}\n itemCount={itemCount}\n renderThumbOverlay={renderThumbOverlay}\n />\n )}\n </div>\n )\n\n // return (\n // <div ref={scrollContainerRef} className={twMerge(\"flex\", className)} style={style}>\n // <div className=\"relative h-full flex-1 overflow-hidden\" style={{ height: viewportSize }} id={id}>\n // {children(scrollPositionRef.current)}\n // </div>\n // {isScrollable && <ScrollBar contentSize={contentSize} viewportSize={sizeRef.current.viewportSize} scrollPosition={scrollPositionRef.current} onScroll={scrollTo} scrollBarWidth={scrollBarWidth} ariaControls={id} />}\n // </div>\n // )\n})\n","/**\n * Provides the sample tap scroll circle visual used for demos.\n * デモ用に使用されるサンプルのタップスクロールビジュアルを提供するモジュール。\n */\n\nimport type { TapScrollCircleProps, TapScrollCircleRenderProps } from \"./TapScrollCircle.tsx\"\n\nconst clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max)\n\nexport const tapScrollCircleSampleVisual: NonNullable<TapScrollCircleProps[\"renderVisual\"]> = ({ dragState, normalizedDistance, sizeScale, size }: TapScrollCircleRenderProps) => {\n const radius = Math.max(size / 2, 1)\n const stretchY = 1 + normalizedDistance * 0.65\n const stretchX = Math.max(0.65, 1 - normalizedDistance * 0.25)\n const tail = dragState.direction * normalizedDistance * 26 * sizeScale\n const pupilScale = 0.8 + normalizedDistance * 0.18\n const tailBase = 3 * sizeScale\n const baseHeight = 6 * sizeScale\n const coreSize = 22 * sizeScale\n const rodHeight = Math.abs(tail) + baseHeight\n const rodTranslate = tail > 0 ? tailBase : -Math.abs(tail) - tailBase\n const rodWidth = Math.max(2.5, 3 * sizeScale)\n const limitedX = clamp(dragState.offsetX, -radius, radius)\n const limitedY = clamp(dragState.offsetY, -radius, radius)\n const pupilRange = radius * 0.35\n const pupilX = (limitedX / radius) * pupilRange\n const pupilY = (limitedY / radius) * pupilRange\n const highlightX = pupilX * 0.45\n const highlightY = pupilY * 0.45\n const highlightSize = Math.max(coreSize * 0.38, 6)\n const highlightOpacity = 0.65 + normalizedDistance * 0.2\n const active = dragState.active\n\n return (\n <>\n <div\n className=\"absolute inset-0 rounded-full border border-white/40 bg-linear-to-br from-[#1d4ed8]/60 via-[#60a5fa]/55 to-[#bfdbfe]/40 shadow-md\"\n style={{\n transform: `scale(${stretchX}, ${stretchY})`,\n transition: active ? \"40ms transform ease-out\" : \"200ms ease transform\",\n }}\n />\n <div\n className=\"absolute top-1/2 left-1/2 rounded-full border border-white/50 bg-white/85\"\n style={{\n width: coreSize,\n height: coreSize,\n transform: `translate(calc(-50% + ${pupilX}px), calc(-50% + ${pupilY}px)) scale(${stretchX}, ${pupilScale * stretchY})`,\n transition: active ? \"70ms transform ease-out\" : \"200ms ease transform\",\n }}\n />\n <div\n className=\"absolute top-1/2 left-1/2 rounded-full bg-white/80\"\n style={{\n width: highlightSize,\n height: highlightSize,\n transform: `translate(calc(-50% + ${highlightX}px), calc(-50% + ${highlightY}px)) scale(${stretchX}, ${stretchY})`,\n opacity: highlightOpacity,\n boxShadow: \"0 0 8px rgba(255,255,255,0.45)\",\n transition: active ? \"120ms opacity 150ms, 120ms transform ease-out ease-out\" : \"220ms ease transform, 240ms opacity ease\",\n }}\n />\n <div\n className=\"absolute top-1/2 left-1/2 rounded-full bg-white/50\"\n style={{\n width: rodWidth,\n height: rodHeight,\n transform: `translate(-50%, ${rodTranslate}px)`,\n opacity: normalizedDistance,\n transition: active ? \"40ms height, 60ms opacity ease-out ease-out\" : \"200ms ease height, 120ms ease opacity\",\n }}\n />\n </>\n )\n}\n","/**\n * @file Fenwick Tree (Binary Indexed Tree) implementation and React hook.\n * @file Fenwick Tree (Binary Indexed Tree) の実装と React フック。\n *\n * @module useFenwickMapTree\n * @description This module provides a FenwickTree (Binary Indexed Tree) data structure\n * and a React hook `useFenwickMapTree` to manage it.\n * This is optimized for virtual scrolling scenarios with dynamically sized items.\n *\n * @description このモジュールは、FenwickTree (バイナリインデックスツリー) データ構造と、\n * それを管理するための React フック `useFenwickMapTree` の提供。\n * 動的なアイテムサイズを持つ仮想スクロールのシナリオに最適化されている。\n */\nimport { useMemo, useRef } from \"react\"\nimport { minmax } from \"./utils.ts\"\n\ntype MaterializeRange = { from: number; to: number }\ntype MaterializeOption = { materialize: boolean; ranges?: MaterializeRange[] }\ntype MaterializeConfig = { materializeOption?: MaterializeOption }\ntype DeltaUpdate = { index: number; change: number }\ntype ValueUpdate = { index: number; value: number }\n\n/**\n * @class FenwickTree\n * @classdesc Implements a Fenwick Tree (or Binary Indexed Tree).\n * This data structure efficiently calculates prefix sums and performs updates in logarithmic time.\n * It is particularly useful for virtual scrolling, where it can manage the offsets of variably sized items.\n *\n * @classdesc Fenwick Tree (バイナリインデックスツリー) の実装。\n * このデータ構造は、接頭辞和の計算と更新を対数時間で効率的に実行。\n * 可変サイズのアイテムのオフセットを管理できるため、特に仮想スクロールで有用。\n */\nexport class FenwickMapTree {\n /**\n * @private\n * @property {Map<number, number>} tree - The Map storing the Fenwick tree structure, specifically the sums of deltas. It is 1-indexed.\n * @property {Map<number, number>} tree - Fenwick Tree 構造を格納する Map。特に差分の合計を保持する。1-indexed。\n */\n private tree!: Map<number, number>\n\n /**\n * @private\n * @property {Map<number, number>} deltas - The Map storing the differences (deltas) from the base value at each index.\n * @property {Map<number, number>} deltas - 各インデックスにおける基準値との差分 (delta) を格納する Map。\n */\n private deltas!: Map<number, number>\n\n /**\n * @private\n * @property {number} size - The number of elements the tree manages.\n * @property {number} size - ツリーが管理する要素数。\n */\n private size!: number\n\n /**\n * @private\n * @property {number} baseValue - The uniform base value for all elements, used to optimize memory.\n * @property {number} baseValue - 全要素の均一な基準値。メモリ最適化のために使用。\n */\n private baseValue!: number\n\n /**\n * @private\n * @property {((index: number) => number) | undefined} valueFn - A function to generate values, stored for lazy initialization.\n * @property {((index: number) => number) | undefined} valueFn - 値を生成するための関数。遅延初期化のために保存される。\n */\n private valueFn?: (index: number) => number\n private total?: number\n\n /**\n * @constructor\n * @description Initializes the Fenwick Tree.\n * @description Fenwick Tree の初期化。\n * @param {number} size - The total number of items.\n * @param {number | ((index: number) => number)} valueOrFn - The value for all elements, or a function to generate values.\n * @param {{ sampleRange?: { from: number; to: number }, materialize?: boolean }} [options] - Optional settings for initialization.\n */\n constructor(size: number, valueOrFn: number | ((index: number) => number), options?: { sampleRange?: { from: number; to: number }; materialize?: boolean }) {\n this.reset(size, valueOrFn, options)\n }\n\n /**\n * @method reset\n * @description Resets the Fenwick Tree with a new size and initial values.\n * @description Fenwick Tree を新しいサイズと初期値でリセット。\n * @param {number} size - The total number of items.\n * @param {number | ((index: number) => number)} valueOrFn - The value for all elements, or a function to generate values.\n * @param {{ sampleRange?: { from: number; to: number }, materialize?: boolean }} [options] - Optional settings for initialization.\n */\n reset(size: number, valueOrFn: number | ((index: number) => number), options?: { sampleRange?: { from: number; to: number }; materialize?: boolean }) {\n this.size = size\n this.tree = new Map()\n this.deltas = new Map()\n this.total = undefined\n\n const isFn = typeof valueOrFn === \"function\"\n if (isFn) {\n this.valueFn = valueOrFn\n if (this.size > 0) {\n // サンプリング範囲を決定する\n const range = options?.sampleRange ?? {\n from: 0,\n to: Math.min(99, this.size - 1),\n }\n // 最頻値と生成された値を取得する\n const { mode, materializedValues } = this._calculateMode(range.from, range.to)\n this.baseValue = mode\n\n // サンプリング範囲の値を具現化する\n if (options?.materialize) {\n for (let i = 0; i < materializedValues.length; i++) {\n const value = materializedValues[i]\n const index = range.from + i\n if (index >= this.size) {\n break\n }\n // _materialize を直接呼ぶ代わりに、計算済みの値を使って更新する\n const change = value - this.baseValue\n this.deltas.set(index, change)\n this._updateTree(index, change)\n }\n }\n } else {\n this.baseValue = 0\n }\n // 具現化が完了した後に total を計算する\n this.total = this.getTotal()\n } else {\n this.valueFn = undefined\n this.baseValue = valueOrFn\n this.total = this.baseValue * this.size\n }\n }\n\n /**\n * @method setValueFn\n * @description Updates the value function and re-initializes the tree.\n * @description 値関数を更新し、ツリーを再初期化する。\n * @param {number | ((index: number) => number)} valueOrFn - The new value for all elements, or a function to generate values.\n */\n setValueFn(valueOrFn: number | ((index: number) => number)) {\n if (typeof valueOrFn === \"function\") {\n this.valueFn = valueOrFn\n } else {\n // If a number is provided, it's treated as a new baseValue,\n // and valueFn is cleared. This case effectively turns the tree\n // into a uniform-value tree, but existing deltas are preserved.\n this.valueFn = undefined\n this.baseValue = valueOrFn\n }\n }\n\n /**\n * @private\n * @method _calculateMode\n * @description Calculates the mode (most frequent value) within a given range of values generated by `valueFn`. If multiple modes exist, it returns their average. If no value appears more than once, it returns the median of the range. This approach helps determine a representative `baseValue` for the Fenwick tree, especially for data with high variance. It also returns the array of values generated within the range for reuse.\n * @description `valueFn` によって生成される値の指定された範囲内の最頻値を計算する。最頻値が複数存在する場合は、それらの平均値を返す。どの値も複数回出現しない場合は、範囲の中央値を返す。このアプローチは、特に分散の大きいデータに対して、Fenwick Tree の代表的な `baseValue` を決定するのに役立つ。また、再利用のために範囲内で生成された値の配列も返す。\n * @param {number} from - The starting index of the range (inclusive).\n * @param {number} to - The ending index of the range (inclusive).\n * @returns {{ mode: number; materializedValues: number[] }} An object containing the calculated mode and the array of generated values.\n */\n private _calculateMode(from: number, to: number): { mode: number; materializedValues: number[] } {\n if (!this.valueFn) {\n return { mode: 0, materializedValues: [] }\n }\n\n const values: number[] = []\n for (let i = from; i <= to; i++) {\n if (i >= this.size) {\n break\n }\n values.push(this.valueFn(i))\n }\n // valueFn で生成した値を再利用するためにコピーを保持する\n const materializedValues = [...values]\n\n if (values.length === 0) {\n return { mode: 0, materializedValues: [] }\n }\n\n // 中央値を計算してデフォルトの最頻値として設定\n values.sort((a, b) => a - b)\n const mid = Math.floor(values.length / 2)\n let mode: number\n if (values.length % 2 === 0) {\n // 偶数個の場合は中央2つの値の平均\n mode = Math.floor((values[mid - 1] + values[mid]) / 2)\n } else {\n // 奇数個の場合は中央の値\n mode = values[mid]\n }\n\n const frequencies = new Map<number, number>()\n let maxFreq = 0\n\n for (const value of values) {\n const count = (frequencies.get(value) ?? 0) + 1\n frequencies.set(value, count)\n if (count > maxFreq) {\n maxFreq = count\n }\n }\n\n if (maxFreq > 1) {\n const modes: number[] = []\n for (const [value, count] of frequencies.entries()) {\n if (count === maxFreq) {\n modes.push(value)\n }\n }\n const sum = modes.reduce((a, b) => a + b, 0)\n mode = Math.floor(sum / modes.length)\n }\n return { mode, materializedValues }\n }\n\n /**\n * @method update\n * @description Updates the value at a given index.\n * @description 指定されたインデックスの値を更新。\n * @param {number} index - The 0-based index to update.\n * @param {number} value - The new value.\n */\n update(index: number, value: number): number | undefined {\n return this.updates([{ index, value }])\n }\n\n /**\n * @method updates\n * @description Updates the values at given indices.\n * @description 指定されたインデックスの値を更新。\n * @param {ValueUpdate[]} updates - An array of updates, each with an index and the new value.\n */\n updates(updates: ValueUpdate[]): number | undefined {\n const deltaUpdates = this._buildDeltaUpdates(updates)\n if (deltaUpdates.length > 0) {\n return this.updateDeltas(deltaUpdates)\n }\n return this.total\n }\n\n /**\n * @method updateDelta\n * @description Updates the delta at a given index and propagates the change through the tree.\n * @description 指定されたインデックスのデルタを更新し、変更をツリーに伝播させる。\n * @param {number} index - The 0-based index to update.\n * @param {number} change - The value to add to the delta at the given index.\n */\n updateDelta(index: number, change: number): number | undefined {\n return this.updateDeltas([{ index, change }])\n }\n\n /**\n * @method updateDeltas\n * @description Updates the deltas at given indices and propagates the changes through the tree.\n * @description 指定されたインデックスのデルタを更新し、変更をツリーに伝播させる。\n * @param {DeltaUpdate[]} updates - An array of updates, each with an index and the change to apply.\n */\n updateDeltas(updates: DeltaUpdate[]): number | undefined {\n for (const { index, change } of updates) {\n if (index < 0 || index >= this.size) {\n throw new Error(`Index ${index} out of bounds`)\n }\n\n // deltas Map を更新\n const currentDelta = this.deltas.get(index) ?? 0\n this.deltas.set(index, currentDelta + change)\n\n // ツリーを更新\n this._updateTree(index, change)\n }\n\n return this.total\n }\n\n /**\n * @private\n * @method _updateTree\n * @description Updates the Fenwick tree and the total sum with a given change.\n * @description Fenwick Tree と合計値を指定された変更で更新する。\n * @param {number} index - The 0-based index that changed.\n * @param {number} change - The change in value.\n */\n private _updateTree(index: number, change: number) {\n if (change === 0) {\n return\n }\n // tree Map を更新\n let treeIndex = index + 1 // Fenwick Tree のアルゴリズムは 1 始まりで設計される\n while (treeIndex <= this.size) {\n this.tree.set(treeIndex, (this.tree.get(treeIndex) ?? 0) + change)\n treeIndex += treeIndex & -treeIndex\n }\n\n // 合計値を更新 (totalが計算済みの場合のみ)\n if (this.total !== undefined) {\n this.total += change\n }\n }\n\n /**\n * @private\n * @method _buildDeltaUpdates\n * @description Converts value updates into delta updates while preserving validation logic.\n * @description 値更新入力を検証しつつデルタ更新へ変換する。\n * @param {ValueUpdate[]} updates - Requested value updates.\n * @returns {DeltaUpdate[]} Sanitized delta updates ready to apply.\n */\n private _buildDeltaUpdates(updates: ValueUpdate[]): DeltaUpdate[] {\n const deltaUpdates: DeltaUpdate[] = []\n for (const { index, value } of updates) {\n if (index < 0 || index >= this.size) {\n throw new Error(`Index ${index} out of bounds`)\n }\n if (value < 0) {\n throw new Error(\"Value cannot be negative.\")\n }\n\n // 現在値を取得して差分を算出\n const oldValue = this.deltas.has(index) ? (this.deltas.get(index) ?? 0) + this.baseValue : this.baseValue\n const change = value - oldValue\n if (change !== 0) {\n deltaUpdates.push({ index, change })\n }\n }\n return deltaUpdates\n }\n\n /**\n * @private\n * @method _materialize\n * @description Materializes the value at a specific index if it hasn't been already.\n * @description 特定のインデックスの値がまだ具現化されていない場合に具現化する。\n * @param {number} index - The 0-based index to materialize.\n * @param {boolean} [updateTree=true] - Whether to update the Fenwick tree after materialization.\n */\n private _materialize(index: number, updateTree = true) {\n if (this.valueFn) {\n // 1. 現在の差分を取得する (存在しなければ 0)\n const oldDelta = this.deltas.get(index) ?? 0\n\n // 2. valueFn から本来の値を計算し、新しい差分を求める\n const value = this.valueFn(index)\n const newDelta = value - this.baseValue\n\n // 3. 差分が実際に変わった場合のみ、ツリーを更新する\n if (newDelta !== oldDelta) {\n this.deltas.set(index, newDelta)\n if (updateTree) {\n // ツリーに反映すべき差分は「新しい差分」と「古い差分」の間の差\n const changeForTree = newDelta - oldDelta\n this._updateTree(index, changeForTree)\n }\n }\n }\n }\n\n /**\n * @private\n * @method _materializeRanges\n * @description Materializes values for provided ranges and optionally a target index, keeping existing semantics for each caller.\n * @description 指定された範囲とターゲットインデックスを既存仕様通りに具現化する。\n * @param {MaterializeOption | undefined} option - Materialization option wrapper.\n * @param {number | undefined} index - Target index for materialization.\n * @param {boolean} [forceIndex=false] - When true, materializes the index even if it is outside the provided ranges.\n */\n private _materializeRanges(option?: MaterializeOption, index?: number, forceIndex = false) {\n if (!(option?.materialize && this.valueFn)) {\n return\n }\n\n const ranges = option.ranges\n if (ranges && ranges.length > 0) {\n for (const range of ranges) {\n const from = range.from\n const to = Math.min(range.to, this.size - 1)\n for (let i = from; i <= to; i++) {\n this._materialize(i)\n }\n }\n\n if (index === undefined) {\n return\n }\n\n if (forceIndex) {\n this._materialize(index)\n return\n }\n\n const first = ranges[0].from\n const last = ranges[ranges.length - 1].to\n if (index >= first && index <= last) {\n this._materialize(index)\n }\n return\n }\n\n if (index !== undefined) {\n this._materialize(index)\n }\n }\n\n /**\n * @private\n * @method _findIndex\n * @description Executes a binary search over prefix sums to find the first index satisfying a boundary condition.\n * @description 累積和に対する二分探索を行い、境界条件を満たす最初のインデックスを求める。\n * @param {number} target - Target cumulative value.\n * @param {MaterializeConfig} options - Materialization setting wrapper.\n * @param {boolean} chooseLowerBound - When true, finds the smallest index meeting or exceeding the target; otherwise finds the largest index not exceeding it.\n * @returns {{ index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined }} Binary search result.\n */\n private _findIndex(\n target: number,\n options: MaterializeConfig = {},\n chooseLowerBound: boolean,\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n if (this.size === 0) {\n return { index: -1, total: this.total ?? 0, cumulative: undefined, currentValue: undefined, safeIndex: undefined }\n }\n\n let low = 0\n let high = this.size - 1\n let ans = -1\n let result:\n | {\n cumulative: number\n total: number | undefined\n currentValue: number\n safeIndex: number\n }\n | undefined\n let finalTotal = this.total\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2)\n result = this.prefixSum(mid, options)\n finalTotal = result.total\n const meetsCondition = chooseLowerBound ? result.cumulative >= target : result.cumulative <= target\n if (meetsCondition) {\n ans = mid\n if (chooseLowerBound) {\n high = mid - 1\n } else {\n low = mid + 1\n }\n } else if (chooseLowerBound) {\n low = mid + 1\n } else {\n high = mid - 1\n }\n }\n\n return { index: ans, total: finalTotal, cumulative: result?.cumulative, currentValue: result?.currentValue, safeIndex: result?.safeIndex }\n }\n\n /**\n * @method prefixSum\n * @description Calculates the cumulative sum up to a given index (inclusive) in O(log n) time.\n * @description 指定されたインデックスまでの累積和を O(log n) で計算。\n * @param {number} index - The 0-based index to prefixSum up to.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @returns {{ cumulative: number; total: number | undefined; currentValue: number; safeIndex: number }} The cumulative sum of values from index 0 to the given index, the total sum, and the value at the given index.\n */\n prefixSum(index: number, options?: MaterializeConfig): { cumulative: number; total: number | undefined; currentValue: number; safeIndex: number } {\n if (index < 0) {\n return { cumulative: 0, total: this.total, currentValue: 0, safeIndex: 0 }\n }\n const safeIndex = minmax(index, 0, this.size - 1)\n\n const materializeOption = options?.materializeOption\n this._materializeRanges(materializeOption, safeIndex, true)\n\n let sum = 0\n let treeIndex = safeIndex + 1 // Fenwick Tree のアルゴリズムは 1 始まりで設計される\n while (treeIndex > 0) {\n const treeNodeValue = this.tree.get(treeIndex) ?? 0\n sum += treeNodeValue\n treeIndex -= treeIndex & -treeIndex\n }\n\n const currentValue = materializeOption?.materialize ? this.get(safeIndex) : (this.deltas.get(safeIndex) || 0) + this.baseValue\n\n // ベース値に基づく合計を加算\n return { cumulative: sum + this.baseValue * (safeIndex + 1), total: this.total, currentValue, safeIndex }\n }\n\n /**\n * @method get\n * @description Gets the value at a specific index.\n * @description 特定のインデックスの値を取得。\n * @param {number} index - The 0-based index to get.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @returns {number} The value at the given index.\n */\n get(index: number, options?: MaterializeConfig): number {\n if (index < 0 || index >= this.size) {\n throw new Error(\"Index out of bounds\")\n }\n\n const materializeOption = options?.materializeOption\n this._materializeRanges(materializeOption, index)\n\n return (this.deltas.get(index) ?? 0) + this.baseValue\n }\n\n /**\n * @method getTotal\n * @description Gets the total sum of all values in the tree.\n * @description ツリー内のすべての値の合計を取得。\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @returns {number} The total sum of all values.\n */\n getTotal(options?: MaterializeConfig): number {\n const materializeOption = options?.materializeOption\n this._materializeRanges(materializeOption)\n\n if (this.total === undefined) {\n if (this.size === 0) {\n this.total = 0\n } else {\n // 具現化は冒頭の処理に任せて高さを計算する\n let total = this.baseValue * this.size\n for (const delta of this.deltas.values()) {\n total += delta\n }\n this.total = total\n const lastPrefix = this.prefixSum(this.getSize() - 1)\n console.assert(lastPrefix.cumulative === lastPrefix.total, \"Inconsistent Fenwick Tree state\")\n }\n }\n\n return this.total\n }\n\n /**\n * @method rebuildTree\n * @description Rebuilds the Fenwick Tree from the existing `baseValue` and `deltas`. This corrects any discrepancies in the tree's internal state, such as those caused by floating-point errors, by recalculating the tree structure and the total sum from the source `deltas`. This method does not re-materialize values from `valueFn`.\n * @description 既存の `baseValue` と `deltas` から Fenwick Tree を再構築します。これにより、`deltas` からツリー構造と合計値を再計算することで、浮動小数点誤差などによって生じた内部状態の不一致を修正します。このメソッドは `valueFn` から値を再具現化しません。\n * @param {object} [options] - Optional settings for rebuilding.\n * @param {boolean} [options.materialize=false] - If true and `valueFn` is provided, re-materializes all values, recalculating `deltas` and `baseValue`.\n */\n rebuildTree(options?: { materialize?: boolean }) {\n if (options?.materialize && this.valueFn) {\n // すべての値を具現化する\n const valueFn = this.valueFn\n this.reset(this.size, (i) => valueFn(i), { materialize: true })\n return\n }\n\n const newTree = new Map<number, number>()\n let newTotal = this.baseValue * this.size\n\n // 既存の deltas を使って新しいツリーを構築し、合計値も同時に再計算する\n for (const [index, delta] of this.deltas.entries()) {\n newTotal += delta\n\n if (delta === 0) {\n continue\n }\n // Fenwick Tree のアルゴリズムは 1 始まりで設計されるため、インデックスを 1 加算する\n let treeIndex = index + 1\n while (treeIndex <= this.size) {\n newTree.set(treeIndex, (newTree.get(treeIndex) ?? 0) + delta)\n treeIndex += treeIndex & -treeIndex\n }\n }\n\n // 最後に状態をアトミックに更新\n this.tree = newTree\n this.total = newTotal\n }\n\n /**\n * @method calculateAccumulatedError\n * @description Compares the cached total sum with a theoretical total calculated directly from the source values (`deltas` and `baseValue`, or `valueFn`). This helps detect any discrepancy in the tree's cached state, which might be caused by floating-point errors or other inconsistencies.\n * @description キャッシュされている合計値と、元の値 (`deltas` と `baseValue`、または `valueFn`) から直接計算した理論上の合計値とを比較します。これにより、浮動小数点数の累積誤差やその他の不整合によって生じる可能性のある、ツリーのキャッシュ状態の不一致を検出できます。\n * @returns {number} The difference between the cached total and the theoretical total.\n */\n calculateAccumulatedError(): number {\n if (this.total === undefined) {\n // total がまだ計算されていない場合は、誤差は 0 とする\n return 0\n }\n\n // 理論上の合計値を計算\n let theoreticalTotal = this.baseValue * this.size\n for (const delta of this.deltas.values()) {\n theoreticalTotal += delta\n }\n\n // キャッシュされている合計値との差を返す\n return this.total - theoreticalTotal\n }\n\n /**\n * @method changeSize\n * @description Changes the size of the Fenwick Tree.\n * @description Fenwick Tree のサイズを変更する。\n * @param {number} newSize - The new size of the tree.\n */\n changeSize(newSize: number) {\n const oldSize = this.size\n if (newSize === oldSize) {\n // サイズが変わらない場合は何もしない\n return\n }\n\n // サイズが小さくなる場合、範囲外の delta を削除する\n if (newSize < oldSize) {\n for (const index of this.deltas.keys()) {\n if (index >= newSize) {\n this.deltas.delete(index)\n }\n }\n }\n\n this.size = newSize\n // サイズ変更後、deltas に基づいてツリー全体を再構築します。\n this.rebuildTree()\n\n const lastPrefix = this.prefixSum(this.getSize() - 1)\n console.assert(lastPrefix.cumulative === lastPrefix.total, \"Inconsistent Fenwick Tree state\")\n }\n\n /**\n * @method getSize\n * @description Gets the size of the tree.\n * @description ツリーのサイズを取得。\n * @returns {number} The total number of items.\n */\n getSize(): number {\n return this.size\n }\n\n /**\n * @method findIndexAtOrAfter\n * @description Finds the first index where the cumulative sum is greater than or equal to a target value.\n * @description 累積和がターゲット値以上になる最初のインデックスを検索。\n * @param {number} target - The target cumulative sum.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @param {MaterializeOption} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {MaterializeRange[]} [options.materializeOption.ranges] - Optional ranges for eager materialization.\n * @returns {{ index: number, total: number | undefined, cumulative: number | undefined, currentValue: number | undefined, safeIndex: number | undefined }} The 0-based index and the total sum, or -1 if not found.\n */\n findIndexAtOrAfter(\n target: number,\n options?: MaterializeConfig,\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n return this._findIndex(target, options ?? {}, true)\n }\n\n /**\n * @method findIndexAtOrBefore\n * @description Finds the last index where the cumulative sum is less than or equal to a target value.\n * @description 累積和がターゲット値以下になる最後のインデックスを検索。\n * @param {number} target - The target cumulative sum.\n * @param {MaterializeConfig} [options] - Optional settings for materializing values.\n * @param {MaterializeOption} [options.materializeOption] - Options to control materialization。\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values。\n * @param {MaterializeRange[]} [options.materializeOption.ranges] - Optional ranges for eager materialization。\n * @returns {{ index: number, total: number | undefined, cumulative: number | undefined, currentValue: number | undefined, safeIndex: number | undefined }} The 0-based index and the total sum, or -1 if not found.\n */\n findIndexAtOrBefore(\n target: number,\n options?: MaterializeConfig,\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n return this._findIndex(target, options ?? {}, false)\n }\n}\n\n/**\n * @hook useFenwickMapTree\n * @description A React hook that creates and manages a `FenwickMapTree` instance.\n * The tree instance is stable across re-renders. A new tree instance is created\n * if `size` or `valueOrFn` changes.\n * @description `FenwickMapTree` インスタンスを作成・管理する React フック。\n * ツリーインスタンスは再レンダリングされても同一性を維持する。`size` または `valueOrFn` が\n * 変更された場合に新しいインスタンスが作成される。\n * @param {number} size - The total number of items.\n * @param {number | ((index: number) => number)} valueOrFn - The value for all elements, or a function to generate values.\n * @param {number | ((index: number) => number)} valueOrFn - 全要素の均一な値、または値を生成する関数。不要なツリーの再作成を防ぐため、この関数は `useCallback` でメモ化すること。\n * @param {{ sampleRange?: { from: number; to: number } }} [options] - Optional settings for initialization. To prevent unnecessary re-creations of the tree, memoize this object with `useMemo`.\n * @param {{ sampleRange?: { from: number; to: number } }} [options] - 初期化時のオプション設定。不要なツリーの再作成を防ぐため、このオブジェクトは `useMemo` でメモ化すること。\n * @returns {FenwickMapTree} The FenwickMapTree instance.\n * @returns {FenwickMapTree} FenwickMapTree インスタンス。\n */\nexport const useFenwickMapTree = (size: number, valueOrFn: number | ((index: number) => number), options?: { sampleRange?: { from: number; to: number } }): FenwickMapTree => {\n const validSize = Math.max(0, size)\n const prevTreeRef = useRef<FenwickMapTree | null>(null)\n\n const tree = useMemo(() => {\n const newTree = new FenwickMapTree(validSize, valueOrFn, options)\n return newTree\n }, [validSize, valueOrFn, options])\n\n // インスタンスが更新された場合にログを出力\n if (!Object.is(prevTreeRef.current, tree)) {\n console.warn(\"[useFenwickMapTree] instance changed\")\n }\n prevTreeRef.current = tree\n\n return tree\n}\n","/**\n * @module useLruCache\n * @description This module provides a `useLruCache` hook, which implements a Least Recently Used (LRU) cache.\n * It uses a Map for O(1) key-based lookups and a doubly linked list to maintain the order of usage, ensuring that get, set, and eviction operations are all efficient.\n *\n * @description このモジュールは、Least Recently Used (LRU) キャッシュを実装した `useLruCache` フックを提供します。\n * Map を使用した O(1) のキー検索と、使用順序を維持するための双方向連結リストを組み合わせることで、get, set, および削除操作のすべてを効率的に行います。\n */\nimport { useCallback, useEffect, useRef, useState } from \"react\"\n\n/**\n * @class DoublyLinkedListNode\n * @description Represents a node in the doubly linked list. It holds a key-value pair and references to the previous and next nodes.\n * @description 双方向連結リスト内のノードを表します。キーと値のペア、および前後のノードへの参照を保持します。\n */\nclass DoublyLinkedListNode<K, V> {\n key: K\n value: V\n prev: DoublyLinkedListNode<K, V> | null = null\n next: DoublyLinkedListNode<K, V> | null = null\n\n constructor(key: K, value: V) {\n // キーを初期化\n this.key = key\n // 値を初期化\n this.value = value\n }\n}\n\n/**\n * @class DoublyLinkedList\n * @description Implements a doubly linked list to maintain the usage order of cache items.\n * The tail of the list represents the most recently used item, and the head represents the least recently used item.\n * @description キャッシュアイテムの使用順序を維持するための双方向連結リストを実装します。\n * リストの末尾が最も最近使用されたアイテムを、先頭が最も最近使用されていないアイテムを示します。\n */\nclass DoublyLinkedList<K, V> {\n private head: DoublyLinkedListNode<K, V> | null = null\n private tail: DoublyLinkedListNode<K, V> | null = null\n\n /**\n * @method addToTail\n * @description Adds a node to the tail of the list, marking it as the most recently used.\n * @description ノードをリストの末尾に追加し、最も最近使用されたものとしてマークします。\n * @param {DoublyLinkedListNode<K, V>} node - The node to add.\n */\n addToTail(node: DoublyLinkedListNode<K, V>) {\n // リストが既に末尾ノードを持っているかチェック\n if (this.tail) {\n // 既存の末尾ノードの次に新しいノードをリンク\n this.tail.next = node\n // 新しいノードの前に既存の末尾ノードをリンク\n node.prev = this.tail\n // リストの末尾を新しいノードに更新\n this.tail = node\n } else {\n // リストが空の場合、新しいノードが先頭かつ末尾となる\n this.head = this.tail = node\n }\n }\n\n /**\n * @method remove\n * @description Removes a given node from the list.\n * @description 指定されたノードをリストから削除します。\n * @param {DoublyLinkedListNode<K, V>} node - The node to remove.\n */\n remove(node: DoublyLinkedListNode<K, V>) {\n // ノードに前のノードが存在する場合\n if (node.prev) {\n // 前のノードの `next` を、現在のノードの `next` につなぎ直す\n node.prev.next = node.next\n } else {\n // ノードが先頭の場合、リストの先頭を次のノードに更新\n this.head = node.next\n }\n\n // ノードに次のノードが存在する場合\n if (node.next) {\n // 次のノードの `prev` を、現在のノードの `prev` につなぎ直す\n node.next.prev = node.prev\n } else {\n // ノードが末尾の場合、リストの末尾を前のノードに更新\n this.tail = node.prev\n }\n\n // 削除されたノードの参照をクリア\n node.prev = null\n node.next = null\n }\n\n /**\n * @method removeHead\n * @description Removes and returns the head of the list, which is the least recently used item.\n * @description リストの先頭(最も最近使用されていないアイテム)を削除して返します。\n * @returns {DoublyLinkedListNode<K, V> | null} The removed head node, or null if the list is empty.\n */\n removeHead(): DoublyLinkedListNode<K, V> | null {\n // 現在の先頭ノードを保持\n const head = this.head\n // 先頭ノードが存在する場合のみ処理\n if (head) {\n // 先頭ノードをリストから削除\n this.remove(head)\n }\n // 削除したノード(または null)を返す\n return head\n }\n\n /**\n * @method moveToTail\n * @description Moves an existing node to the tail of the list to mark it as most recently used.\n * @description 既存のノードをリストの末尾に移動し、最も最近使用されたものとしてマークします。\n * @param {DoublyLinkedListNode<K, V>} node - The node to move.\n */\n moveToTail(node: DoublyLinkedListNode<K, V>) {\n // ノードを現在の位置から一旦削除\n this.remove(node)\n // ノードをリストの末尾に再追加\n this.addToTail(node)\n }\n}\n\n/**\n * @hook useLruCache\n * @description A custom hook that provides a Least Recently Used (LRU) cache of a specified capacity.\n * It returns an object with methods to interact with the cache (`get`, `set`, `has`, `clear`).\n * @description 指定された容量の LRU (Least Recently Used) キャッシュを提供するカスタムフック。\n * キャッシュを操作するためのメソッド (`get`, `set`, `has`, `clear`) を持つオブジェクトを返します。\n * @param {number} capacity - The maximum capacity of the cache.\n * @returns {{ get: (key: K) => V | undefined, set: (key: K, value: V) => void, has: (key: K) => boolean, clear: () => void }} An object with methods to interact with the cache.\n */\nexport function useLruCache<K, V>(capacity: number) {\n // キャッシュストレージ。キーと双方向連結リストのノードをマッピングする (O(1) アクセス用)\n const cache = useRef(new Map<K, DoublyLinkedListNode<K, V>>())\n // 使用順序を管理する双方向連結リスト (先頭が最も古く、末尾が最も新しい)\n const list = useRef(new DoublyLinkedList<K, V>())\n\n useEffect(() => {\n while (cache.current.size > capacity) {\n const lruNode = list.current.removeHead()\n if (lruNode) {\n cache.current.delete(lruNode.key)\n } else {\n // This should not happen if cache.current.size > 0\n break\n }\n }\n }, [capacity])\n\n /**\n * @function get\n * @description Retrieves a value from the cache for a given key. If found, the item is marked as most recently used.\n * @description 指定されたキーの値を取得します。アイテムが見つかった場合、それは最も最近使用されたものとしてマークされます。\n * @param {K} key - The key of the item to retrieve.\n * @returns {V | undefined} The cached value, or undefined if the key does not exist.\n */\n const get = useCallback((key: K): V | undefined => {\n // Map からノードを効率的に検索\n const node = cache.current.get(key)\n // ノードが存在する場合\n if (node) {\n // アクセスされたノードを使用順序リストの末尾に移動\n list.current.moveToTail(node)\n // ノードの値を返す\n return node.value\n }\n // ノードが存在しない場合は undefined を返す\n return undefined\n }, [])\n\n /**\n * @function set\n * @description Adds or updates a key-value pair in the cache. If the cache is full, it evicts the least recently used item.\n * @description キーと値のペアをキャッシュに追加または更新します。キャッシュが満杯の場合、最も最近使用されていないアイテムが削除されます。\n * @param {K} key - The key of the item to set.\n * @param {V} value - The value of the item to set.\n */\n const set = useCallback(\n (key: K, value: V) => {\n if (capacity <= 0) {\n return\n }\n // キャッシュ内にキーが既に存在するかチェック\n let node = cache.current.get(key)\n\n if (node) {\n // キーが存在する場合、値を更新\n node.value = value\n // アクセスされたので、使用順序リストの末尾に移動\n list.current.moveToTail(node)\n } else {\n // 新しいノードを追加する場合\n // キャッシュが容量上限に達しているかチェック\n if (cache.current.size >= capacity) {\n // 容量オーバーの場合、最も最近使用されていないノード (リストの先頭) を取得して削除\n const lruNode = list.current.removeHead()\n if (lruNode) {\n // Map からも対応するエントリを削除\n cache.current.delete(lruNode.key)\n }\n }\n // 新しいノードを作成\n node = new DoublyLinkedListNode(key, value)\n // 新しいノードを Map に登録\n cache.current.set(key, node)\n // 新しいノードを使用順序リストの末尾に追加\n list.current.addToTail(node)\n }\n },\n [capacity],\n )\n\n /**\n * @function has\n * @description Checks if a key exists in the cache.\n * @description 指定されたキーがキャッシュ内に存在するかどうかを確認します。\n * @param {K} key - The key to check.\n * @returns {boolean} True if the key exists, false otherwise.\n */\n const has = useCallback((key: K): boolean => {\n // Map にキーが存在するかどうかを O(1) でチェック\n return cache.current.has(key)\n }, [])\n\n /**\n * @function clear\n * @description Clears the entire cache, removing all entries.\n * @description キャッシュを完全にクリアし、すべてのエントリを削除します。\n */\n const clear = useCallback(() => {\n // Map をクリア\n cache.current.clear()\n // 双方向連結リストを新しく作成してリセット\n list.current = new DoublyLinkedList<K, V>()\n }, [])\n\n const [handler, setHandler] = useState(() => ({ get, set, has, clear }))\n\n useEffect(() => setHandler({ get, set, has, clear }), [get, set, has, clear])\n\n // キャッシュ操作用の API を返す\n return handler\n}\n","/**\n * @module useHeightCache\n * @description This module provides a hook for caching item heights using an LRU (Least Recently Used) cache.\n * It is designed to be used in virtual scrolling components to optimize performance by storing and retrieving the heights of rendered items.\n *\n * @description このモジュールは、LRU (Least Recently Used) キャッシュを使用してアイテムの高さをキャッシュするためのフックを提供します。\n * 仮想スクロールコンポーネントで使用されることを想定しており、レンダリングされたアイテムの高さを保存および取得することでパフォーマンスを最適化します。\n */\nimport { useLruCache } from \"./useLruCache.ts\"\n\n// LRU キャッシュに保存する高さの測定値の最大数\nconst HEIGHT_CACHE_CAPACITY = 10000\n\n/**\n * A custom hook that provides a cache for storing the heights of items, backed by an LRU cache.\n * This helps in optimizing virtual scrolling by avoiding re-computation of item heights.\n * The key is the item's index (number), and the value is its height (number).\n *\n * LRU キャッシュを利用して、アイテムの高さを保存するためのキャッシュを提供するカスタムフック。\n * これにより、アイテムの高さの再計算を回避し、仮想スクロールを最適化します。\n * キーはアイテムのインデックス (number)、値はその高さ (number) です。\n */\nexport const useHeightCache = () => {\n // useLruCache フックを初期化し、指定された容量でキャッシュインスタンスを作成\n const { get, set, has, clear } = useLruCache<number, number>(HEIGHT_CACHE_CAPACITY)\n\n // キャッシュを操作するための関数 (get, set, has, clear) を返す\n return { get, set, has, clear }\n}\n","import { forwardRef, type ReactNode, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from \"react\"\nimport { Logger } from \"./logger.ts\"\nimport { ScrollPane, type ScrollPaneHandle, type ScrollPaneProps } from \"./ScrollPane.tsx\"\nimport { useFenwickMapTree } from \"./useFenwickMapTree.ts\"\nimport { minmax } from \"./utils.ts\"\n\nexport type VirtualScrollHandle = ScrollPaneHandle & {\n scrollToIndex: (index: number) => void\n getFenwickTreeTotalHeight: () => number\n getFenwickSize: () => number\n}\n\ntype VirtualScrollProps<T> = {\n itemCount: number\n getItem: (index: number) => T\n getItemHeight: (index: number) => number\n viewportSize: number\n overscanCount?: number\n className?: string\n onScroll?: (scrollPosition: number, totalHeight: number) => void\n onRangeChange?: (renderingStartIndex: number, renderingEndIndex: number, visibleStartIndex: number, visibleEndIndex: number, scrollPosition: number, totalHeight: number) => void\n background?: ReactNode\n children: (item: T, index: number) => ReactNode\n initialScrollIndex?: number\n initialScrollOffset?: number\n tapScrollCircleOptions?: ScrollPaneProps[\"tapScrollCircleOptions\"]\n scrollBarWidth?: number\n enableThumbDrag?: ScrollPaneProps[\"enableThumbDrag\"]\n enableTrackClick?: ScrollPaneProps[\"enableTrackClick\"]\n enableArrowButtons?: ScrollPaneProps[\"enableArrowButtons\"]\n enablePointerDrag?: ScrollPaneProps[\"enablePointerDrag\"]\n inertiaOptions?: ScrollPaneProps[\"inertiaOptions\"]\n renderThumbOverlay?: ScrollPaneProps[\"renderThumbOverlay\"]\n wheelSpeedMultiplier?: ScrollPaneProps[\"wheelSpeedMultiplier\"]\n}\n\nconst sanitizeIndex = (value: number, size: number) => (size <= 0 ? 0 : minmax(value, 0, size - 1))\n\n/**\n * Calculates rendering boundaries from current scroll metrics.\n *\n * 現在のスクロール情報から描画範囲を算出。\n */\nconst computeRenderingRanges = (\n scrollPosition: number,\n viewportSize: number,\n overscanCount: number,\n size: number,\n getItemHeight: (index: number) => number,\n fenwickTree: ReturnType<typeof useFenwickMapTree>,\n) => {\n if (size === 0) {\n return { renderingStartIndex: 0, renderingEndIndex: 0, visibleStartIndex: 0, visibleEndIndex: 0 }\n }\n const { index: rawStartIndex, cumulative, currentValue } = fenwickTree.findIndexAtOrAfter(scrollPosition, { materializeOption: { materialize: false } })\n const baseIndex = rawStartIndex === -1 ? 0 : rawStartIndex\n const adjustedStart = rawStartIndex !== -1 && (cumulative ?? 0) < scrollPosition + (currentValue ?? 0) ? baseIndex + 1 : baseIndex\n const visibleStartIndex = sanitizeIndex(adjustedStart, size)\n const renderingStartIndex = sanitizeIndex(visibleStartIndex - overscanCount, size)\n\n let visibleHeight = 0\n let cursor = visibleStartIndex\n while (cursor < size && visibleHeight < viewportSize) {\n visibleHeight += getItemHeight(cursor)\n cursor++\n }\n const visibleEndIndex = sanitizeIndex(cursor - 1, size)\n const renderingEndIndex = sanitizeIndex(visibleEndIndex + overscanCount, size)\n\n return { renderingStartIndex, renderingEndIndex, visibleStartIndex, visibleEndIndex }\n}\n\nfunction VirtualScrollInner<T>({ itemCount, getItem, getItemHeight, viewportSize, overscanCount = 5, className, onScroll, onRangeChange, children, background, initialScrollIndex, initialScrollOffset, tapScrollCircleOptions, scrollBarWidth, enableThumbDrag, enableTrackClick, enableArrowButtons, enablePointerDrag, inertiaOptions, renderThumbOverlay, wheelSpeedMultiplier }: VirtualScrollProps<T>, ref: React.Ref<VirtualScrollHandle>) {\n const scrollPaneRef = useRef<VirtualScrollHandle>(null)\n const isMounted = useRef(false)\n\n useEffect(() => {\n isMounted.current = true\n return () => {\n isMounted.current = false\n }\n }, [])\n\n const fenwickTreeInitArgs = useRef({ size: itemCount, valueOrFn: getItemHeight, options: { sampleRange: { from: 0, to: 100 } } })\n const fenwickTree = useFenwickMapTree(fenwickTreeInitArgs.current.size, fenwickTreeInitArgs.current.valueOrFn, fenwickTreeInitArgs.current.options)\n\n const [initialValues] = useState(() => {\n let position = 0\n let total = 0\n if (typeof initialScrollIndex === \"number\") {\n const safeIndex = minmax(initialScrollIndex, 0, itemCount - 1)\n const safeIndexFrom = minmax(safeIndex - overscanCount * 2, 0, itemCount - 1)\n const safeIndexTo = minmax(safeIndex + overscanCount * 2, 0, itemCount - 1)\n const options = initialScrollIndex > 0 ? { materializeOption: { materialize: true, ranges: [{ from: safeIndexFrom, to: safeIndexTo }] } } : undefined\n const { cumulative, total: materializedTotal, currentValue } = fenwickTree.prefixSum(initialScrollIndex, options)\n position = cumulative - currentValue\n total = materializedTotal ?? fenwickTree.getTotal()\n } else if (typeof initialScrollOffset === \"number\") {\n position = initialScrollOffset\n total = fenwickTree.getTotal()\n } else {\n total = fenwickTree.getTotal()\n }\n return { position, total }\n })\n\n const [scrollPosition, setScrollPosition] = useState(initialValues.position)\n const [contentSize, setContentSize] = useState<number>(initialValues.total)\n const [shouldPaneScrollTo, setShouldPaneScrollTo] = useState<number | null>(initialValues.position)\n\n const [fenwickSize, setFenwickSize] = useState<number>(itemCount)\n\n useLayoutEffect(() => {\n fenwickTree.setValueFn(getItemHeight)\n if (fenwickSize !== itemCount) {\n fenwickTree.changeSize(itemCount)\n setFenwickSize(itemCount)\n }\n const totalHeight = fenwickTree.getTotal()\n if (contentSize !== totalHeight) {\n setContentSize(totalHeight)\n }\n }, [fenwickTree, fenwickSize, itemCount, contentSize, getItemHeight])\n\n useLayoutEffect(() => {\n // スクロールより前に、コンテンツのサイズを更新する必要があるので、 useLayoutEffect で同期処理\n if (shouldPaneScrollTo !== null && scrollPaneRef.current) {\n Logger.debug(\"[VirtualScroll] Scrolling to position:\", shouldPaneScrollTo)\n scrollPaneRef.current.scrollTo(shouldPaneScrollTo)\n setShouldPaneScrollTo(null)\n }\n }, [shouldPaneScrollTo])\n\n const scrollToIndex = useCallback(\n (index: number) => {\n if (!scrollPaneRef.current) {\n return\n }\n const safeIndex = sanitizeIndex(index, fenwickSize)\n const safeIndexFrom = sanitizeIndex(safeIndex - overscanCount * 2, fenwickSize)\n const safeIndexTo = sanitizeIndex(safeIndex + overscanCount * 2, fenwickSize)\n const { cumulative: offset, total, currentValue } = fenwickTree.prefixSum(safeIndex, { materializeOption: { materialize: true, ranges: [{ from: safeIndexFrom, to: safeIndexTo }] } })\n\n Logger.debug(\"[VirtualScroll] Scrolling to index:\", safeIndex, \"Offset:\", offset, \"Total height:\", total, \"Current value:\", currentValue, \"safeIndexFrom:\", safeIndexFrom, \"safeIndexTo:\", safeIndexTo)\n\n if (!total) {\n return\n }\n setContentSize(total)\n setShouldPaneScrollTo(offset - currentValue)\n Logger.debug(\"[VirtualScroll] Setting scroll position to:\", offset - currentValue)\n },\n [fenwickTree, overscanCount, fenwickSize],\n )\n\n const scrollTo = useCallback(\n (newPosition: number) => {\n if (!scrollPaneRef.current) {\n return\n }\n const total = fenwickTree.getTotal()\n const safePosition = minmax(Math.floor(newPosition), 0, total)\n const index = fenwickTree.findIndexAtOrAfter(safePosition, { materializeOption: { materialize: false } }).index\n scrollToIndex(index)\n },\n [fenwickTree, scrollToIndex],\n )\n\n const handleScroll = useCallback(\n (newPosition: number, _prevPosition: number) => {\n Logger.debug(\"[VirtualScroll] Scroll position changed:\", newPosition)\n\n // スクロール位置を更新\n setScrollPosition(newPosition)\n // 高さを更新\n const totalHeight = fenwickTree.getTotal()\n // if (contentSize !== totalHeight) {\n // setContentSize(totalHeight)\n // }\n // コールバックを呼び出す\n onScroll?.(newPosition, totalHeight)\n },\n [fenwickTree, onScroll],\n )\n\n // レンダリング範囲を計算\n const renderingRanges = useMemo(() => {\n const ranges = computeRenderingRanges(scrollPosition, viewportSize, overscanCount, fenwickSize, getItemHeight, fenwickTree)\n Logger.debug(\"[VirtualScroll] Calculated rendering range:\", {\n ...ranges,\n scrollPosition,\n renderingContentSize: fenwickTree.getTotal(),\n overscanCount,\n viewportSize,\n })\n return ranges\n }, [scrollPosition, viewportSize, overscanCount, fenwickSize, getItemHeight, fenwickTree])\n\n // レンダリング範囲が変更されたらコールバックを呼ぶ\n useEffect(() => {\n const scrollPaneScrollPosition = scrollPaneRef.current?.getScrollPosition() ?? 0\n Logger.debug(\"[VirtualScroll] Range change effect triggered\", {\n renderingStartIndex: renderingRanges.renderingStartIndex,\n renderingEndIndex: renderingRanges.renderingEndIndex,\n visibleStartIndex: renderingRanges.visibleStartIndex,\n visibleEndIndex: renderingRanges.visibleEndIndex,\n scrollPosition,\n contentSize,\n scrollPaneScrollPosition,\n })\n onRangeChange?.(renderingRanges.renderingStartIndex, renderingRanges.renderingEndIndex, renderingRanges.visibleStartIndex, renderingRanges.visibleEndIndex, scrollPosition, contentSize)\n }, [renderingRanges.renderingStartIndex, renderingRanges.renderingEndIndex, renderingRanges.visibleStartIndex, renderingRanges.visibleEndIndex, onRangeChange, scrollPosition, contentSize])\n\n const renderVisibleItems = useCallback(\n (currentScrollPosition: number) => {\n const { renderingStartIndex, renderingEndIndex } = renderingRanges\n Logger.debug(\"[VirtualScroll] Rendering visible items\", { currentScrollPosition, renderingStartIndex, renderingEndIndex, fenwickSize, viewportSize })\n\n if (fenwickSize === 0) {\n return (\n <div className=\"absolute w-full\" style={{ top: 0 }}>\n <div className=\"text-center text-gray-500\">No items</div>\n </div>\n )\n }\n\n const safeRenderingStartIndex = sanitizeIndex(renderingStartIndex, fenwickSize)\n const { cumulative, currentValue: oldHeight } = fenwickTree.prefixSum(safeRenderingStartIndex, { materializeOption: { materialize: false } })\n const startPosition = cumulative - oldHeight // スクロール位置を調整\n\n const visibleItems: Array<{ item: T; height: number; index: number }> = []\n const toUpdateHeights: Array<{ index: number; value: number }> = []\n\n for (let i = renderingStartIndex; i <= renderingEndIndex; i++) {\n const newHeight = getItemHeight(i)\n visibleItems.push({ item: getItem(i), height: newHeight, index: i })\n const oldHeight = fenwickTree.get(i)\n if (oldHeight !== newHeight) {\n toUpdateHeights.push({ index: i, value: newHeight })\n }\n }\n\n if (toUpdateHeights.length > 0) {\n // レンダリング中に状態を更新しないように、更新処理をマイクロタスクにスケジュールする\n Promise.resolve().then(() => {\n const total = fenwickTree.updates(toUpdateHeights)\n if (total) {\n setContentSize(total)\n Logger.debug(\"[VirtualScroll] Updated heights for items\", toUpdateHeights, \"New total height:\", total)\n }\n })\n }\n\n // 全体の高さがビューポートより小さい場合は、topを0に固定\n const containerTop = contentSize < viewportSize ? 0 : startPosition - currentScrollPosition\n\n Logger.debug(\"[VirtualScroll] Rendering items\", { visibleItems, containerTop })\n\n return (\n <div className=\"absolute w-full\" style={{ top: containerTop }}>\n {visibleItems.map(({ item, index: actualIndex }) => {\n const safeActualIndex = sanitizeIndex(actualIndex, fenwickSize)\n const { cumulative, currentValue: currentHeight } = fenwickTree.prefixSum(safeActualIndex, { materializeOption: { materialize: false } })\n const actualOffset = cumulative - currentHeight\n\n return (\n <div\n key={actualIndex}\n data-index={actualIndex}\n style={{\n position: \"absolute\",\n top: actualOffset - startPosition,\n width: \"100%\",\n }}>\n {children(item, actualIndex)}\n </div>\n )\n })}\n </div>\n )\n },\n [getItem, children, contentSize, viewportSize, renderingRanges, fenwickTree, fenwickSize, getItemHeight],\n )\n\n useImperativeHandle(ref, () => ({\n getScrollPosition: () => scrollPaneRef.current?.getScrollPosition() ?? -1,\n getContentSize: () => scrollPaneRef.current?.getContentSize() ?? -1,\n getViewportSize: () => scrollPaneRef.current?.getViewportSize() ?? -1,\n scrollTo,\n scrollToIndex,\n getFenwickTreeTotalHeight: () => fenwickTree.getTotal(),\n getFenwickSize: () => fenwickTree.getSize(),\n }), [scrollTo, scrollToIndex, fenwickTree])\n\n return (\n <ScrollPane\n ref={scrollPaneRef}\n contentSize={contentSize}\n viewportSize={viewportSize}\n className={className}\n onScroll={handleScroll}\n background={background}\n tapScrollCircleOptions={tapScrollCircleOptions}\n inertiaOptions={inertiaOptions}\n itemCount={itemCount}\n scrollBarWidth={scrollBarWidth}\n enableThumbDrag={enableThumbDrag}\n enableTrackClick={enableTrackClick}\n enableArrowButtons={enableArrowButtons}\n enablePointerDrag={enablePointerDrag}\n renderThumbOverlay={renderThumbOverlay}\n wheelSpeedMultiplier={wheelSpeedMultiplier}>\n {renderVisibleItems}\n </ScrollPane>\n )\n}\n\nexport const VirtualScroll = forwardRef(VirtualScrollInner) as <T>(props: VirtualScrollProps<T> & { ref?: React.Ref<VirtualScrollHandle> }) => React.ReactElement\n"],"names":["INITIAL_STATE","DEAD_ZONE","defaultRenderVisual","dragState","normalizedDistance","scale","glow","innerOpacity","baseTransition","jsxs","Fragment","jsx","TapScrollCircle","forwardRef","onDragChange","className","maxVisualDistance","size","style","opacity","renderVisual","ref","setDragState","useState","pointerIdRef","useRef","centerRef","rootRef","applyDragState","useCallback","nextState","updateDragState","clientX","clientY","capture","x","y","offsetX","offsetY","distance","direction","releasePointerCapture","pointerId","element","resetState","releasePointer","handlePointerDown","event","left","top","width","height","handlePointerMove","handlePointerUp","useImperativeHandle","clampedOpacity","sizeScale","normalized","pullOffset","visualRenderer","visualProps","rootStyle","twMerge","minmax","value","min","max","capturePointerMove","onMove","onEnd","isTouchEvent","startPosition","moveEvent","movePosition","TAP_SCROLL_CANCEL_EVENT","MIN_THUMB_SIZE","ARROW_HOLD_DELAY","ARROW_HOLD_INTERVAL","MIN_ARROW_STEP","ARROW_STEP_DIVISOR","TAP_SCROLL_MAX_DISTANCE","TAP_SCROLL_INITIAL_STATE","TAP_SCROLL_AUTO_SPEED_BASE_MULTIPLIER","TAP_SCROLL_AUTO_SPEED_PER_ORDER","TAP_SCROLL_AUTO_SPEED_MAX_MULTIPLIER","DEFAULT_TAP_SCROLL_CIRCLE_OPTIONS","createOrientationConfig","horizontal","deltaX","_deltaY","_deltaX","deltaY","resolveTapScrollCircleOptions","options","itemCount","manualMaxSpeedMultiplier","maxSpeedMultiplier","computeAutoTapScrollMaxSpeedMultiplier","useThumbVisualFeedback","thumbRef","isDragging","isThumbHovered","enableThumbDrag","useEffect","hoverScale","dragScale","useArrowAutoRepeat","canUseArrowButtons","enableArrowButtons","resetTapScroll","scrollByStep","arrowHoldIntervalRef","arrowHoldTimeoutRef","clearArrowTimers","handleArrowPointerUp","handleArrowPointerDown","handleArrowKeyDown","clampedCount","ordersOfMagnitude","multiplier","ScrollBar","contentSize","viewportSize","scrollPosition","onScroll","enableTrackClick","scrollBarWidth","ariaControls","tapScrollCircleOptions","renderThumbOverlay","setIsDragging","setIsThumbHovered","isTapActive","setIsTapActive","latestScrollPositionRef","tapDragStateRef","tapCircleHandleRef","autoScrollFrameRef","lastAutoScrollTimestampRef","resolvedTapScrollOptions","useMemo","orientationConfig","tapCircleEnabled","tapCircleSize","tapCircleOffsetX","tapCircleOffsetY","tapCircleClassName","tapCircleMaxDistance","tapCircleMaxSpeedMultiplier","tapCircleMinSpeedMultiplier","tapCircleOpacity","tapCircleRenderVisual","tapCircleMaxSpeedCurve","mainSizeKey","crossSizeKey","positionKey","selectDelta","getPointerCoordinate","arrowLabels","arrowIcons","directionClass","orientation","effectiveTapMaxDistance","scrollRatio","arrowButtonLength","trackLength","rawThumbSize","thumbSize","maxScrollPosition","effectiveTrackLength","thumbPosition","thumbCenter","scrollBarVisible","stopAutoScroll","stepAutoScroll","timestamp","state","lastTimestamp","deltaSeconds","eased","hasCustomMaxSpeedMultiplier","minSpeed","maxSpeedFloor","cappedMaxSpeed","steepness","expNumerator","expDenominator","exponentialRatio","exponentialMaxSpeed","maxSpeed","easedOffset","effectiveEased","speed","prevPosition","nextPosition","startAutoScroll","handleTapCircleDragChange","handleTapScrollCancel","targetPaneId","targetNode","translateToScrollPosition","thumbPositionValue","clampedThumbPosition","step","prev","next","handlePointerDownOnThumb","startThumbPosition","delta","handlePointerDownOnTrack","position","startMousePosition","rect","clickPositionInTrack","tapCircleOpacityValue","tapCircleStyle","baseTop","renderArrowButton","label","icon","overlayProps","Logger","message","args","DEFAULT_INERTIA_OPTIONS","toggleListeners","target","entries","action","type","listener","ScrollPane","children","enablePointerDrag","background","inertiaOptions","wheelSpeedMultiplier","scrollPositionRef","_","_forceUpdate","useReducer","scrollContainerRef","contentAreaRef","inertiaStateRef","resolvedInertiaOptions","sizeRef","isScrollable","scrollTo","newPosition","currentContentSize","currentViewportSize","currentIsScrollable","newScrollPosition","stopInertia","startInertia","initialVelocity","maxVelocity","minVelocity","deceleration","startVelocityThreshold","limitedVelocity","deltaTime","previousVelocity","nextVelocity","decelerationAmount","previousPosition","prevPositionInternal","reachedBoundary","useLayoutEffect","handleWheel","scrollContainer","id","useId","DRAG_ACTIVATION_THRESHOLD","dragPointerId","dragStartClientY","dragStartScroll","shouldCancelNextClick","clickResetTimer","velocitySamples","pushVelocitySample","now","sample","shouldIgnoreTarget","handleClickCapture","startDragging","endDrag","inertiaVelocity","lastSample","firstSample","deltaClientY","handlePointerCancel","elementEntries","windowEntries","clamp","tapScrollCircleSampleVisual","radius","stretchY","stretchX","tail","pupilScale","tailBase","baseHeight","coreSize","rodHeight","rodTranslate","rodWidth","limitedX","limitedY","pupilRange","pupilX","pupilY","highlightX","highlightY","highlightSize","highlightOpacity","active","FenwickMapTree","valueOrFn","range","mode","materializedValues","i","index","change","from","to","values","a","b","mid","frequencies","maxFreq","count","modes","sum","updates","deltaUpdates","currentDelta","treeIndex","oldValue","updateTree","oldDelta","newDelta","changeForTree","option","forceIndex","ranges","first","last","chooseLowerBound","low","high","ans","result","finalTotal","safeIndex","materializeOption","treeNodeValue","currentValue","total","lastPrefix","valueFn","newTree","newTotal","theoreticalTotal","newSize","oldSize","useFenwickMapTree","validSize","prevTreeRef","tree","DoublyLinkedListNode","key","DoublyLinkedList","node","head","useLruCache","capacity","cache","list","lruNode","get","set","has","clear","handler","setHandler","HEIGHT_CACHE_CAPACITY","useHeightCache","sanitizeIndex","computeRenderingRanges","overscanCount","getItemHeight","fenwickTree","rawStartIndex","cumulative","baseIndex","adjustedStart","visibleStartIndex","renderingStartIndex","visibleHeight","cursor","visibleEndIndex","renderingEndIndex","VirtualScrollInner","getItem","onRangeChange","initialScrollIndex","initialScrollOffset","scrollPaneRef","isMounted","fenwickTreeInitArgs","initialValues","safeIndexFrom","safeIndexTo","materializedTotal","setScrollPosition","setContentSize","shouldPaneScrollTo","setShouldPaneScrollTo","fenwickSize","setFenwickSize","totalHeight","scrollToIndex","offset","safePosition","handleScroll","_prevPosition","renderingRanges","scrollPaneScrollPosition","renderVisibleItems","currentScrollPosition","safeRenderingStartIndex","oldHeight","visibleItems","toUpdateHeights","newHeight","containerTop","item","actualIndex","safeActualIndex","currentHeight","actualOffset","VirtualScroll"],"mappings":"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"}