@aiquants/virtualscroll 0.2.2 → 0.4.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../node_modules/.pnpm/react@19.1.1/node_modules/react/cjs/react-jsx-runtime.production.js","../../../node_modules/.pnpm/react@19.1.1/node_modules/react/cjs/react-jsx-runtime.development.js","../../../node_modules/.pnpm/react@19.1.1/node_modules/react/jsx-runtime.js","../src/logger.ts","../src/utils.ts","../src/ScrollBar.tsx","../src/ScrollPane.tsx","../src/useFenwickMapTree.ts","../src/VirtualScroll.tsx","../src/useLruCache.ts","../src/useHeightCache.ts"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\");\nfunction jsxProd(type, config, maybeKey) {\n var key = null;\n void 0 !== maybeKey && (key = \"\" + maybeKey);\n void 0 !== config.key && (key = \"\" + config.key);\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n config = maybeKey.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== config ? config : null,\n props: maybeKey\n };\n}\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsxProd;\nexports.jsxs = jsxProd;\n","/**\n * @license React\n * react-jsx-runtime.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function getComponentNameFromType(type) {\n if (null == type) return null;\n if (\"function\" === typeof type)\n return type.$$typeof === REACT_CLIENT_REFERENCE\n ? null\n : type.displayName || type.name || null;\n if (\"string\" === typeof type) return type;\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return \"Fragment\";\n case REACT_PROFILER_TYPE:\n return \"Profiler\";\n case REACT_STRICT_MODE_TYPE:\n return \"StrictMode\";\n case REACT_SUSPENSE_TYPE:\n return \"Suspense\";\n case REACT_SUSPENSE_LIST_TYPE:\n return \"SuspenseList\";\n case REACT_ACTIVITY_TYPE:\n return \"Activity\";\n }\n if (\"object\" === typeof type)\n switch (\n (\"number\" === typeof type.tag &&\n console.error(\n \"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.\"\n ),\n type.$$typeof)\n ) {\n case REACT_PORTAL_TYPE:\n return \"Portal\";\n case REACT_CONTEXT_TYPE:\n return (type.displayName || \"Context\") + \".Provider\";\n case REACT_CONSUMER_TYPE:\n return (type._context.displayName || \"Context\") + \".Consumer\";\n case REACT_FORWARD_REF_TYPE:\n var innerType = type.render;\n type = type.displayName;\n type ||\n ((type = innerType.displayName || innerType.name || \"\"),\n (type = \"\" !== type ? \"ForwardRef(\" + type + \")\" : \"ForwardRef\"));\n return type;\n case REACT_MEMO_TYPE:\n return (\n (innerType = type.displayName || null),\n null !== innerType\n ? innerType\n : getComponentNameFromType(type.type) || \"Memo\"\n );\n case REACT_LAZY_TYPE:\n innerType = type._payload;\n type = type._init;\n try {\n return getComponentNameFromType(type(innerType));\n } catch (x) {}\n }\n return null;\n }\n function testStringCoercion(value) {\n return \"\" + value;\n }\n function checkKeyStringCoercion(value) {\n try {\n testStringCoercion(value);\n var JSCompiler_inline_result = !1;\n } catch (e) {\n JSCompiler_inline_result = !0;\n }\n if (JSCompiler_inline_result) {\n JSCompiler_inline_result = console;\n var JSCompiler_temp_const = JSCompiler_inline_result.error;\n var JSCompiler_inline_result$jscomp$0 =\n (\"function\" === typeof Symbol &&\n Symbol.toStringTag &&\n value[Symbol.toStringTag]) ||\n value.constructor.name ||\n \"Object\";\n JSCompiler_temp_const.call(\n JSCompiler_inline_result,\n \"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.\",\n JSCompiler_inline_result$jscomp$0\n );\n return testStringCoercion(value);\n }\n }\n function getTaskName(type) {\n if (type === REACT_FRAGMENT_TYPE) return \"<>\";\n if (\n \"object\" === typeof type &&\n null !== type &&\n type.$$typeof === REACT_LAZY_TYPE\n )\n return \"<...>\";\n try {\n var name = getComponentNameFromType(type);\n return name ? \"<\" + name + \">\" : \"<...>\";\n } catch (x) {\n return \"<...>\";\n }\n }\n function getOwner() {\n var dispatcher = ReactSharedInternals.A;\n return null === dispatcher ? null : dispatcher.getOwner();\n }\n function UnknownOwner() {\n return Error(\"react-stack-top-frame\");\n }\n function hasValidKey(config) {\n if (hasOwnProperty.call(config, \"key\")) {\n var getter = Object.getOwnPropertyDescriptor(config, \"key\").get;\n if (getter && getter.isReactWarning) return !1;\n }\n return void 0 !== config.key;\n }\n function defineKeyPropWarningGetter(props, displayName) {\n function warnAboutAccessingKey() {\n specialPropKeyWarningShown ||\n ((specialPropKeyWarningShown = !0),\n console.error(\n \"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)\",\n displayName\n ));\n }\n warnAboutAccessingKey.isReactWarning = !0;\n Object.defineProperty(props, \"key\", {\n get: warnAboutAccessingKey,\n configurable: !0\n });\n }\n function elementRefGetterWithDeprecationWarning() {\n var componentName = getComponentNameFromType(this.type);\n didWarnAboutElementRef[componentName] ||\n ((didWarnAboutElementRef[componentName] = !0),\n console.error(\n \"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.\"\n ));\n componentName = this.props.ref;\n return void 0 !== componentName ? componentName : null;\n }\n function ReactElement(\n type,\n key,\n self,\n source,\n owner,\n props,\n debugStack,\n debugTask\n ) {\n self = props.ref;\n type = {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n props: props,\n _owner: owner\n };\n null !== (void 0 !== self ? self : null)\n ? Object.defineProperty(type, \"ref\", {\n enumerable: !1,\n get: elementRefGetterWithDeprecationWarning\n })\n : Object.defineProperty(type, \"ref\", { enumerable: !1, value: null });\n type._store = {};\n Object.defineProperty(type._store, \"validated\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: 0\n });\n Object.defineProperty(type, \"_debugInfo\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: null\n });\n Object.defineProperty(type, \"_debugStack\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugStack\n });\n Object.defineProperty(type, \"_debugTask\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugTask\n });\n Object.freeze && (Object.freeze(type.props), Object.freeze(type));\n return type;\n }\n function jsxDEVImpl(\n type,\n config,\n maybeKey,\n isStaticChildren,\n source,\n self,\n debugStack,\n debugTask\n ) {\n var children = config.children;\n if (void 0 !== children)\n if (isStaticChildren)\n if (isArrayImpl(children)) {\n for (\n isStaticChildren = 0;\n isStaticChildren < children.length;\n isStaticChildren++\n )\n validateChildKeys(children[isStaticChildren]);\n Object.freeze && Object.freeze(children);\n } else\n console.error(\n \"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.\"\n );\n else validateChildKeys(children);\n if (hasOwnProperty.call(config, \"key\")) {\n children = getComponentNameFromType(type);\n var keys = Object.keys(config).filter(function (k) {\n return \"key\" !== k;\n });\n isStaticChildren =\n 0 < keys.length\n ? \"{key: someKey, \" + keys.join(\": ..., \") + \": ...}\"\n : \"{key: someKey}\";\n didWarnAboutKeySpread[children + isStaticChildren] ||\n ((keys =\n 0 < keys.length ? \"{\" + keys.join(\": ..., \") + \": ...}\" : \"{}\"),\n console.error(\n 'A props object containing a \"key\" prop is being spread into JSX:\\n let props = %s;\\n <%s {...props} />\\nReact keys must be passed directly to JSX without using spread:\\n let props = %s;\\n <%s key={someKey} {...props} />',\n isStaticChildren,\n children,\n keys,\n children\n ),\n (didWarnAboutKeySpread[children + isStaticChildren] = !0));\n }\n children = null;\n void 0 !== maybeKey &&\n (checkKeyStringCoercion(maybeKey), (children = \"\" + maybeKey));\n hasValidKey(config) &&\n (checkKeyStringCoercion(config.key), (children = \"\" + config.key));\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n children &&\n defineKeyPropWarningGetter(\n maybeKey,\n \"function\" === typeof type\n ? type.displayName || type.name || \"Unknown\"\n : type\n );\n return ReactElement(\n type,\n children,\n self,\n source,\n getOwner(),\n maybeKey,\n debugStack,\n debugTask\n );\n }\n function validateChildKeys(node) {\n \"object\" === typeof node &&\n null !== node &&\n node.$$typeof === REACT_ELEMENT_TYPE &&\n node._store &&\n (node._store.validated = 1);\n }\n var React = require(\"react\"),\n REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\");\n Symbol.for(\"react.provider\");\n var REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\"),\n ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n hasOwnProperty = Object.prototype.hasOwnProperty,\n isArrayImpl = Array.isArray,\n createTask = console.createTask\n ? console.createTask\n : function () {\n return null;\n };\n React = {\n react_stack_bottom_frame: function (callStackForError) {\n return callStackForError();\n }\n };\n var specialPropKeyWarningShown;\n var didWarnAboutElementRef = {};\n var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(\n React,\n UnknownOwner\n )();\n var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));\n var didWarnAboutKeySpread = {};\n exports.Fragment = REACT_FRAGMENT_TYPE;\n exports.jsx = function (type, config, maybeKey, source, self) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !1,\n source,\n self,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n exports.jsxs = function (type, config, maybeKey, source, self) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !0,\n source,\n self,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\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","/**\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 { useState, useRef, useEffect } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\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 * 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 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}\n\n/** The minimum size of the scrollbar thumb. / スクロールバーのつまみの最小サイズ。 */\nconst MIN_THUMB_SIZE = 20\n\n/**\n * A custom scrollbar component.\n *\n * カスタムスクロールバーコンポーネント。\n */\nexport const ScrollBar = ({ contentSize, viewportSize, scrollPosition, onScroll, horizontal = false, scrollBarWidth = 12, className, ariaControls }: ScrollBarProps) => {\n const [isDragging, setIsDragging] = useState(false)\n const thumbRef = useRef<HTMLDivElement>(null)\n // 表示領域に対するコンテンツの比率\n const scrollRatio = viewportSize / contentSize\n // スクロールバーのつまみのサイズ\n const thumbSize = Math.max(MIN_THUMB_SIZE, scrollRatio * viewportSize)\n // 最大スクロール位置\n const maxScrollPosition = contentSize - viewportSize\n // スクロールバーのつまみの位置\n const thumbPosition = (scrollPosition / maxScrollPosition) * (viewportSize - thumbSize)\n\n // スクロールバーが表示されるかどうか\n const scrollBarVisible = contentSize > viewportSize\n\n // ドラッグ状態が変わったときに色を更新\n useEffect(() => {\n if (thumbRef.current) {\n if (isDragging) {\n thumbRef.current.style.backgroundColor = \"#4F4F4F\"; // ドラッグ中はさらに濃い色\n } else {\n thumbRef.current.style.backgroundColor = \"#7F7F7F\"; // 通常色\n }\n }\n }, [isDragging])\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 = (thumbPosition: number) => {\n return minmax((thumbPosition / (viewportSize - thumbSize)) * maxScrollPosition, 0, maxScrollPosition)\n }\n\n // スクロールバーのつまみをマウスで押したときのハンドラ\n const handlePointerDownOnThumb = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if (\"button\" in event && event.button !== 0) {\n return\n }\n if (event.ctrlKey) {\n return\n }\n // event.preventDefault() // ここでは preventDefault しない\n event.stopPropagation()\n\n // ドラッグ開始時のつまみの位置\n const startThumbPosition = thumbPosition\n setIsDragging(true)\n\n // マウスの移動をキャプチャ\n capturePointerMove(\n event,\n ({ deltaX, deltaY }) => {\n const delta = horizontal ? deltaX : deltaY\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n },\n () => {\n setIsDragging(false)\n },\n )\n }\n\n // スクロールバーのトラックをマウスで押したときのハンドラ\n const handlePointerDownOnTrack = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if (\"button\" in event && event.button !== 0) {\n return\n }\n if (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 = horizontal ? position.clientX : position.clientY\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n const clickPositionInTrack = horizontal ? startMousePosition - rect.left : startMousePosition - rect.top\n\n // クリックした位置にスクロール\n // つまみはクリック位置の中央に配置\n const startThumbPosition = clickPositionInTrack - thumbSize / 2\n onScroll?.(translateToScrollPosition(startThumbPosition), thumbPosition)\n\n // マウスの移動をキャプチャしてドラッグ操作を処理\n capturePointerMove(event, ({ deltaX, deltaY }) => {\n const delta = horizontal ? deltaX : deltaY\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n })\n }\n\n return (\n // スクロールバーのコンテナ\n <div\n className={twMerge(\"group relative cursor-default select-none\", className)}\n style={{\n [horizontal ? \"width\" : \"height\"]: viewportSize,\n [horizontal ? \"height\" : \"width\"]: scrollBarWidth,\n backgroundColor: \"white\",\n userSelect: \"none\",\n }}\n onMouseDown={handlePointerDownOnTrack}\n onTouchStart={handlePointerDownOnTrack}\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 {/* コンテンツがビューポートより大きい場合にのみつまみを表示 */}\n {contentSize > viewportSize && (\n // スクロールバーのつまみの当たり判定を広げるためのラッパー\n <div\n className=\"group absolute\"\n style={{\n [horizontal ? \"width\" : \"height\"]: thumbSize,\n [horizontal ? \"left\" : \"top\"]: thumbPosition,\n // 当たり判定を上下または左右に広げる\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 tabIndex={0}>\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-[-2px]\" : \"group-active:inset-y-[-2px]\"}`\n : `inset-x-[1.5px] inset-y-0 group-hover:inset-x-[-0.5px] ${isDragging ? \"inset-x-[-2px]\" : \"group-active:inset-x-[-2px]\"}`,\n )}\n style={{\n backgroundColor: \"#7F7F7F\",\n borderRadius: scrollBarWidth - 1,\n // Tailwind が適用されない場合のフォールバック\n ...(horizontal ? {\n left: 0,\n right: 0,\n top: isDragging ? -2 : 1.5,\n bottom: isDragging ? -2 : 1.5,\n } : {\n top: 0,\n bottom: 0,\n left: isDragging ? -2 : 1.5,\n right: isDragging ? -2 : 1.5,\n }),\n }}\n onMouseEnter={(e) => {\n // ポジション変更\n if (horizontal) {\n e.currentTarget.style.top = \"-0.5px\";\n e.currentTarget.style.bottom = \"-0.5px\";\n } else {\n e.currentTarget.style.left = \"-0.5px\";\n e.currentTarget.style.right = \"-0.5px\";\n }\n // 色を濃くする(ホバー時)- ドラッグ中でない場合のみ\n if (!isDragging) {\n e.currentTarget.style.backgroundColor = \"#5F5F5F\";\n }\n }}\n onMouseLeave={(e) => {\n // ポジション復元\n if (horizontal) {\n e.currentTarget.style.top = isDragging ? \"-2px\" : \"1.5px\";\n e.currentTarget.style.bottom = isDragging ? \"-2px\" : \"1.5px\";\n } else {\n e.currentTarget.style.left = isDragging ? \"-2px\" : \"1.5px\";\n e.currentTarget.style.right = isDragging ? \"-2px\" : \"1.5px\";\n }\n // 色を元に戻す - ドラッグ中でない場合のみ\n if (!isDragging) {\n e.currentTarget.style.backgroundColor = \"#7F7F7F\";\n }\n }}\n />\n </div>\n )}\n </div>\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 } 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 /** 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}\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, onScroll, className, style, background }, ref) => {\n const scrollPositionRef = useRef(0)\n const [_, _forceUpdate] = useReducer((x) => x + 1, 0)\n const scrollContainerRef = useRef<HTMLDivElement>(null)\n\n Logger.debug(\"[ScrollPane] ScrollPane rendered\", { contentSize, viewportSize, scrollBarWidth, className, style })\n\n // const size = useMemo(() => ({ contentSize, viewportSize }), [contentSize, viewportSize])\n\n // contentSize と viewportSize を ref として保持\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 currentIsScrollable = contentSize > viewportSize\n const prevPosition = scrollPositionRef.current\n\n Logger.debug(\"[ScrollPane] scrollTo called\", { newPosition, contentSize, viewportSize, 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, contentSize - viewportSize)\n if (scrollPositionRef.current !== newScrollPosition) {\n scrollPositionRef.current = newScrollPosition\n onScroll?.(newScrollPosition, prevPosition)\n }\n },\n [onScroll, contentSize, viewportSize],\n )\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 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, 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 const ItemComponents = useMemo(() => {\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 {background}\n {children(scrollPositionRef.current)}\n </div>\n {isScrollable && <ScrollBar contentSize={contentSize} viewportSize={viewportSize} scrollPosition={scrollPositionRef.current} onScroll={scrollTo} scrollBarWidth={scrollBarWidth} ariaControls={id} />}\n </div>\n )\n }, [children, contentSize, viewportSize, scrollBarWidth, className, style, isScrollable, scrollTo, id, background])\n return ItemComponents\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 * @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\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 {{ index: number; value: number }[]} updates - An array of updates, each with an index and the new value.\n */\n updates(updates: { index: number; value: number }[]): number | undefined {\n const deltaUpdates = updates\n .map(({ index, value }) => {\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 // 更新前に現在の値を取得する。未具現化の場合は baseValue を使用する\n const oldValue = this.deltas.has(index) ? (this.deltas.get(index) ?? 0) + this.baseValue : this.baseValue\n const delta = value - oldValue\n return { index, change: delta }\n })\n .filter((update) => update.change !== 0)\n\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 {{ index: number; change: number }[]} updates - An array of updates, each with an index and the change to apply.\n */\n updateDeltas(updates: { index: number; change: number }[]): 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 _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 * @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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\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?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } }): { 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 if (materializeOption?.materialize && this.valueFn) {\n if (materializeOption.ranges) {\n for (const range of materializeOption.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 // `ranges` の範囲にかかわらず、`safeIndex` を具現化する\n this._materialize(safeIndex)\n }\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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\n * @returns {number} The value at the given index.\n */\n get(index: number, options?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } }): number {\n if (index < 0 || index >= this.size) {\n throw new Error(\"Index out of bounds\")\n }\n\n const materializeOption = options?.materializeOption\n if (materializeOption?.materialize && this.valueFn) {\n if (materializeOption.ranges) {\n for (const range of materializeOption.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 if (index >= materializeOption.ranges[0].from && index <= materializeOption.ranges[materializeOption.ranges.length - 1].to) {\n this._materialize(index)\n }\n } else {\n this._materialize(index)\n }\n }\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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\n * @returns {number} The total sum of all values.\n */\n getTotal(options?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } }): number {\n const materializeOption = options?.materializeOption\n\n if (materializeOption?.materialize && this.valueFn) {\n if (materializeOption.ranges) {\n for (const range of materializeOption.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 }\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 console.assert(this.prefixSum(this.getSize() - 1).cumulative === this.prefixSum(this.getSize() - 1).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 console.assert(this.prefixSum(this.getSize() - 1).cumulative === this.prefixSum(this.getSize() - 1).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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\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?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } },\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n // サイズが 0 の場合は探索しようがないので -1 を返す\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 if (result.cumulative >= target) {\n ans = mid\n high = mid - 1\n } else {\n low = 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 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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\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?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } },\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n // サイズが 0 の場合は探索しようがないので -1 を返す\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 if (result.cumulative <= target) {\n ans = mid\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/**\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","import { forwardRef, type ReactNode, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from \"react\"\nimport { Logger } from \"./logger.ts\"\nimport { ScrollPane, type ScrollPaneHandle } 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}\n\nfunction VirtualScrollInner<T>({ itemCount, getItem, getItemHeight, viewportSize, overscanCount = 5, className, onScroll, onRangeChange, children, background, initialScrollIndex, initialScrollOffset }: 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 Logger.debug(\"[VirtualScroll] Scrolling to index:\", index)\n\n const safeIndex = minmax(index, 0, fenwickSize - 1)\n const safeIndexFrom = minmax(safeIndex - overscanCount * 2, 0, fenwickSize - 1) // 末尾の場合は最終スクロールの先頭を表示するので、余裕をもってマテリアライズする\n const safeIndexTo = minmax(safeIndex + overscanCount * 2, 0, fenwickSize - 1)\n // スクロール先のインデックスまでの高さをマテリアライズして、正確なオフセットを計算\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:\", index, \"Offset:\", offset, \"Total height:\", total, \"Current value:\", currentValue, \"safeIndex:\", safeIndex, \"safeIndexFrom:\", safeIndexFrom, \"safeIndexTo:\", safeIndexTo)\n\n if (total) {\n // コンテンツ全体のサイズも更新する。更新しないと\n setContentSize(total)\n // 計算された正確なオフセットにスクロール\n setShouldPaneScrollTo(offset - currentValue)\n }\n Logger.debug(\"[VirtualScroll] Setting scroll position to:\", offset - currentValue)\n }\n },\n [fenwickTree, overscanCount, fenwickSize],\n )\n\n const scrollTo = useCallback(\n (newPosition: number) => {\n if (scrollPaneRef.current) {\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 },\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<{ renderingStartIndex: number; renderingEndIndex: number; visibleStartIndex: number; visibleEndIndex: number }>(() => {\n if (fenwickSize === 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 let indexAdjustment = 0\n if (rawStartIndex === -1) {\n indexAdjustment = 0\n } else if ((cumulative ?? 0) < scrollPosition + (currentValue ?? 0)) {\n indexAdjustment = 1\n } else {\n indexAdjustment = 0\n }\n const visibleStartIndex = rawStartIndex === -1 ? 0 : rawStartIndex + indexAdjustment\n const renderingStartIndex = minmax(visibleStartIndex - overscanCount, 0, fenwickSize - 1)\n\n let visibleHeight = 0\n let visibleEndIndex = rawStartIndex === -1 ? 0 : rawStartIndex + indexAdjustment\n while (visibleEndIndex < fenwickSize && visibleHeight < viewportSize) {\n const currentHeight = getItemHeight(visibleEndIndex)\n visibleHeight += currentHeight\n visibleEndIndex++\n }\n visibleEndIndex -= 1 // 最後にインクリメントされた分を戻す\n\n const renderingEndIndex = minmax(visibleEndIndex + overscanCount, 0, fenwickSize - 1)\n\n Logger.debug(\"[VirtualScroll] Calculated rendering range:\", {\n renderingStartIndex,\n renderingEndIndex,\n visibleStartIndex,\n visibleEndIndex,\n scrollPosition,\n renderingContentSize: fenwickTree.getTotal(),\n overscanCount,\n viewportSize,\n })\n\n return { renderingStartIndex, renderingEndIndex, visibleStartIndex, visibleEndIndex }\n }, [scrollPosition, overscanCount, viewportSize, getItemHeight, fenwickTree, fenwickSize])\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 = minmax(renderingStartIndex, 0, fenwickSize - 1)\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 }> = []\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 })\n\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, height: _height }, index) => {\n const actualIndex = renderingStartIndex + index\n const safeActualIndex = minmax(actualIndex, 0, fenwickSize - 1)\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(\n ref,\n () => ({\n getScrollPosition: () => scrollPaneRef.current?.getScrollPosition() ?? -1,\n getContentSize: () => scrollPaneRef.current?.getContentSize() ?? -1,\n getViewportSize: () => scrollPaneRef.current?.getViewportSize() ?? -1,\n scrollTo: (newPosition: number) => scrollTo(newPosition),\n scrollToIndex: (index: number) => scrollToIndex(index),\n getFenwickTreeTotalHeight: () => fenwickTree.getTotal(),\n getFenwickSize: () => fenwickTree.getSize(),\n }),\n [scrollToIndex, fenwickTree, scrollTo],\n )\n\n return (\n <ScrollPane ref={scrollPaneRef} contentSize={contentSize} viewportSize={viewportSize} className={className} onScroll={handleScroll} background={background}>\n {renderVisibleItems}\n </ScrollPane>\n )\n}\n\nexport const VirtualScroll = forwardRef(VirtualScrollInner) as <T>(props: VirtualScrollProps<T> & { ref?: React.Ref<VirtualScrollHandle> }) => React.ReactElement\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"],"names":["REACT_ELEMENT_TYPE","REACT_FRAGMENT_TYPE","jsxProd","type","config","maybeKey","key","propName","reactJsxRuntime_production","getComponentNameFromType","REACT_CLIENT_REFERENCE","REACT_PROFILER_TYPE","REACT_STRICT_MODE_TYPE","REACT_SUSPENSE_TYPE","REACT_SUSPENSE_LIST_TYPE","REACT_ACTIVITY_TYPE","REACT_PORTAL_TYPE","REACT_CONTEXT_TYPE","REACT_CONSUMER_TYPE","REACT_FORWARD_REF_TYPE","innerType","REACT_MEMO_TYPE","REACT_LAZY_TYPE","testStringCoercion","value","checkKeyStringCoercion","JSCompiler_inline_result","JSCompiler_temp_const","JSCompiler_inline_result$jscomp$0","getTaskName","name","getOwner","dispatcher","ReactSharedInternals","UnknownOwner","hasValidKey","hasOwnProperty","getter","defineKeyPropWarningGetter","props","displayName","warnAboutAccessingKey","specialPropKeyWarningShown","elementRefGetterWithDeprecationWarning","componentName","didWarnAboutElementRef","ReactElement","self","source","owner","debugStack","debugTask","jsxDEVImpl","isStaticChildren","children","isArrayImpl","validateChildKeys","keys","k","didWarnAboutKeySpread","node","React","require$$0","createTask","callStackForError","unknownOwnerDebugStack","unknownOwnerDebugTask","reactJsxRuntime_development","trackActualOwner","jsxRuntimeModule","require$$1","Logger","message","args","minmax","min","max","capturePointerMove","event","onMove","onEnd","isTouchEvent","startPosition","handlePointerMove","moveEvent","movePosition","handlePointerUp","MIN_THUMB_SIZE","ScrollBar","contentSize","viewportSize","scrollPosition","onScroll","horizontal","scrollBarWidth","className","ariaControls","isDragging","setIsDragging","useState","thumbRef","useRef","scrollRatio","thumbSize","maxScrollPosition","thumbPosition","scrollBarVisible","useEffect","translateToScrollPosition","handlePointerDownOnThumb","startThumbPosition","deltaX","deltaY","handlePointerDownOnTrack","position","startMousePosition","rect","jsx","twMerge","e","ScrollPane","forwardRef","style","background","ref","scrollPositionRef","_","_forceUpdate","useReducer","x","scrollContainerRef","isScrollable","useMemo","scrollTo","useCallback","newPosition","currentIsScrollable","prevPosition","nextPosition","newScrollPosition","useLayoutEffect","handleWheel","prev","scrollContainer","useImperativeHandle","id","useId","jsxs","FenwickMapTree","size","valueOrFn","options","range","mode","materializedValues","index","change","from","to","values","i","a","b","mid","frequencies","maxFreq","count","modes","sum","updates","deltaUpdates","oldValue","delta","update","currentDelta","treeIndex","updateTree","oldDelta","newDelta","changeForTree","safeIndex","materializeOption","treeNodeValue","currentValue","total","valueFn","newTree","newTotal","theoreticalTotal","newSize","oldSize","target","low","high","ans","result","finalTotal","useFenwickMapTree","validSize","prevTreeRef","tree","VirtualScrollInner","itemCount","getItem","getItemHeight","overscanCount","onRangeChange","initialScrollIndex","initialScrollOffset","scrollPaneRef","isMounted","fenwickTreeInitArgs","fenwickTree","initialValues","safeIndexFrom","safeIndexTo","cumulative","materializedTotal","setScrollPosition","setContentSize","shouldPaneScrollTo","setShouldPaneScrollTo","fenwickSize","setFenwickSize","totalHeight","scrollToIndex","offset","safePosition","handleScroll","_prevPosition","renderingRanges","rawStartIndex","indexAdjustment","visibleStartIndex","renderingStartIndex","visibleHeight","visibleEndIndex","currentHeight","renderingEndIndex","scrollPaneScrollPosition","renderVisibleItems","currentScrollPosition","safeRenderingStartIndex","oldHeight","visibleItems","toUpdateHeights","newHeight","containerTop","item","_height","actualIndex","safeActualIndex","actualOffset","VirtualScroll","DoublyLinkedListNode","DoublyLinkedList","head","useLruCache","capacity","cache","list","lruNode","get","set","has","clear","handler","setHandler","HEIGHT_CACHE_CAPACITY","useHeightCache"],"mappings":"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","x_google_ignoreList":[0,1,2]}
1
+ {"version":3,"file":"index.cjs","sources":["../../../node_modules/.pnpm/react@19.1.1/node_modules/react/cjs/react-jsx-runtime.production.js","../../../node_modules/.pnpm/react@19.1.1/node_modules/react/cjs/react-jsx-runtime.development.js","../../../node_modules/.pnpm/react@19.1.1/node_modules/react/jsx-runtime.js","../src/logger.ts","../src/utils.ts","../src/TapScrollCircle.tsx","../src/ScrollBar.tsx","../src/ScrollPane.tsx","../src/useFenwickMapTree.ts","../src/VirtualScroll.tsx","../src/useLruCache.ts","../src/useHeightCache.ts"],"sourcesContent":["/**\n * @license React\n * react-jsx-runtime.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\");\nfunction jsxProd(type, config, maybeKey) {\n var key = null;\n void 0 !== maybeKey && (key = \"\" + maybeKey);\n void 0 !== config.key && (key = \"\" + config.key);\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n config = maybeKey.ref;\n return {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n ref: void 0 !== config ? config : null,\n props: maybeKey\n };\n}\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.jsx = jsxProd;\nexports.jsxs = jsxProd;\n","/**\n * @license React\n * react-jsx-runtime.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function getComponentNameFromType(type) {\n if (null == type) return null;\n if (\"function\" === typeof type)\n return type.$$typeof === REACT_CLIENT_REFERENCE\n ? null\n : type.displayName || type.name || null;\n if (\"string\" === typeof type) return type;\n switch (type) {\n case REACT_FRAGMENT_TYPE:\n return \"Fragment\";\n case REACT_PROFILER_TYPE:\n return \"Profiler\";\n case REACT_STRICT_MODE_TYPE:\n return \"StrictMode\";\n case REACT_SUSPENSE_TYPE:\n return \"Suspense\";\n case REACT_SUSPENSE_LIST_TYPE:\n return \"SuspenseList\";\n case REACT_ACTIVITY_TYPE:\n return \"Activity\";\n }\n if (\"object\" === typeof type)\n switch (\n (\"number\" === typeof type.tag &&\n console.error(\n \"Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.\"\n ),\n type.$$typeof)\n ) {\n case REACT_PORTAL_TYPE:\n return \"Portal\";\n case REACT_CONTEXT_TYPE:\n return (type.displayName || \"Context\") + \".Provider\";\n case REACT_CONSUMER_TYPE:\n return (type._context.displayName || \"Context\") + \".Consumer\";\n case REACT_FORWARD_REF_TYPE:\n var innerType = type.render;\n type = type.displayName;\n type ||\n ((type = innerType.displayName || innerType.name || \"\"),\n (type = \"\" !== type ? \"ForwardRef(\" + type + \")\" : \"ForwardRef\"));\n return type;\n case REACT_MEMO_TYPE:\n return (\n (innerType = type.displayName || null),\n null !== innerType\n ? innerType\n : getComponentNameFromType(type.type) || \"Memo\"\n );\n case REACT_LAZY_TYPE:\n innerType = type._payload;\n type = type._init;\n try {\n return getComponentNameFromType(type(innerType));\n } catch (x) {}\n }\n return null;\n }\n function testStringCoercion(value) {\n return \"\" + value;\n }\n function checkKeyStringCoercion(value) {\n try {\n testStringCoercion(value);\n var JSCompiler_inline_result = !1;\n } catch (e) {\n JSCompiler_inline_result = !0;\n }\n if (JSCompiler_inline_result) {\n JSCompiler_inline_result = console;\n var JSCompiler_temp_const = JSCompiler_inline_result.error;\n var JSCompiler_inline_result$jscomp$0 =\n (\"function\" === typeof Symbol &&\n Symbol.toStringTag &&\n value[Symbol.toStringTag]) ||\n value.constructor.name ||\n \"Object\";\n JSCompiler_temp_const.call(\n JSCompiler_inline_result,\n \"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.\",\n JSCompiler_inline_result$jscomp$0\n );\n return testStringCoercion(value);\n }\n }\n function getTaskName(type) {\n if (type === REACT_FRAGMENT_TYPE) return \"<>\";\n if (\n \"object\" === typeof type &&\n null !== type &&\n type.$$typeof === REACT_LAZY_TYPE\n )\n return \"<...>\";\n try {\n var name = getComponentNameFromType(type);\n return name ? \"<\" + name + \">\" : \"<...>\";\n } catch (x) {\n return \"<...>\";\n }\n }\n function getOwner() {\n var dispatcher = ReactSharedInternals.A;\n return null === dispatcher ? null : dispatcher.getOwner();\n }\n function UnknownOwner() {\n return Error(\"react-stack-top-frame\");\n }\n function hasValidKey(config) {\n if (hasOwnProperty.call(config, \"key\")) {\n var getter = Object.getOwnPropertyDescriptor(config, \"key\").get;\n if (getter && getter.isReactWarning) return !1;\n }\n return void 0 !== config.key;\n }\n function defineKeyPropWarningGetter(props, displayName) {\n function warnAboutAccessingKey() {\n specialPropKeyWarningShown ||\n ((specialPropKeyWarningShown = !0),\n console.error(\n \"%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)\",\n displayName\n ));\n }\n warnAboutAccessingKey.isReactWarning = !0;\n Object.defineProperty(props, \"key\", {\n get: warnAboutAccessingKey,\n configurable: !0\n });\n }\n function elementRefGetterWithDeprecationWarning() {\n var componentName = getComponentNameFromType(this.type);\n didWarnAboutElementRef[componentName] ||\n ((didWarnAboutElementRef[componentName] = !0),\n console.error(\n \"Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.\"\n ));\n componentName = this.props.ref;\n return void 0 !== componentName ? componentName : null;\n }\n function ReactElement(\n type,\n key,\n self,\n source,\n owner,\n props,\n debugStack,\n debugTask\n ) {\n self = props.ref;\n type = {\n $$typeof: REACT_ELEMENT_TYPE,\n type: type,\n key: key,\n props: props,\n _owner: owner\n };\n null !== (void 0 !== self ? self : null)\n ? Object.defineProperty(type, \"ref\", {\n enumerable: !1,\n get: elementRefGetterWithDeprecationWarning\n })\n : Object.defineProperty(type, \"ref\", { enumerable: !1, value: null });\n type._store = {};\n Object.defineProperty(type._store, \"validated\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: 0\n });\n Object.defineProperty(type, \"_debugInfo\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: null\n });\n Object.defineProperty(type, \"_debugStack\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugStack\n });\n Object.defineProperty(type, \"_debugTask\", {\n configurable: !1,\n enumerable: !1,\n writable: !0,\n value: debugTask\n });\n Object.freeze && (Object.freeze(type.props), Object.freeze(type));\n return type;\n }\n function jsxDEVImpl(\n type,\n config,\n maybeKey,\n isStaticChildren,\n source,\n self,\n debugStack,\n debugTask\n ) {\n var children = config.children;\n if (void 0 !== children)\n if (isStaticChildren)\n if (isArrayImpl(children)) {\n for (\n isStaticChildren = 0;\n isStaticChildren < children.length;\n isStaticChildren++\n )\n validateChildKeys(children[isStaticChildren]);\n Object.freeze && Object.freeze(children);\n } else\n console.error(\n \"React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.\"\n );\n else validateChildKeys(children);\n if (hasOwnProperty.call(config, \"key\")) {\n children = getComponentNameFromType(type);\n var keys = Object.keys(config).filter(function (k) {\n return \"key\" !== k;\n });\n isStaticChildren =\n 0 < keys.length\n ? \"{key: someKey, \" + keys.join(\": ..., \") + \": ...}\"\n : \"{key: someKey}\";\n didWarnAboutKeySpread[children + isStaticChildren] ||\n ((keys =\n 0 < keys.length ? \"{\" + keys.join(\": ..., \") + \": ...}\" : \"{}\"),\n console.error(\n 'A props object containing a \"key\" prop is being spread into JSX:\\n let props = %s;\\n <%s {...props} />\\nReact keys must be passed directly to JSX without using spread:\\n let props = %s;\\n <%s key={someKey} {...props} />',\n isStaticChildren,\n children,\n keys,\n children\n ),\n (didWarnAboutKeySpread[children + isStaticChildren] = !0));\n }\n children = null;\n void 0 !== maybeKey &&\n (checkKeyStringCoercion(maybeKey), (children = \"\" + maybeKey));\n hasValidKey(config) &&\n (checkKeyStringCoercion(config.key), (children = \"\" + config.key));\n if (\"key\" in config) {\n maybeKey = {};\n for (var propName in config)\n \"key\" !== propName && (maybeKey[propName] = config[propName]);\n } else maybeKey = config;\n children &&\n defineKeyPropWarningGetter(\n maybeKey,\n \"function\" === typeof type\n ? type.displayName || type.name || \"Unknown\"\n : type\n );\n return ReactElement(\n type,\n children,\n self,\n source,\n getOwner(),\n maybeKey,\n debugStack,\n debugTask\n );\n }\n function validateChildKeys(node) {\n \"object\" === typeof node &&\n null !== node &&\n node.$$typeof === REACT_ELEMENT_TYPE &&\n node._store &&\n (node._store.validated = 1);\n }\n var React = require(\"react\"),\n REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\");\n Symbol.for(\"react.provider\");\n var REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_ACTIVITY_TYPE = Symbol.for(\"react.activity\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\"),\n ReactSharedInternals =\n React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,\n hasOwnProperty = Object.prototype.hasOwnProperty,\n isArrayImpl = Array.isArray,\n createTask = console.createTask\n ? console.createTask\n : function () {\n return null;\n };\n React = {\n react_stack_bottom_frame: function (callStackForError) {\n return callStackForError();\n }\n };\n var specialPropKeyWarningShown;\n var didWarnAboutElementRef = {};\n var unknownOwnerDebugStack = React.react_stack_bottom_frame.bind(\n React,\n UnknownOwner\n )();\n var unknownOwnerDebugTask = createTask(getTaskName(UnknownOwner));\n var didWarnAboutKeySpread = {};\n exports.Fragment = REACT_FRAGMENT_TYPE;\n exports.jsx = function (type, config, maybeKey, source, self) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !1,\n source,\n self,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n exports.jsxs = function (type, config, maybeKey, source, self) {\n var trackActualOwner =\n 1e4 > ReactSharedInternals.recentlyCreatedOwnerStacks++;\n return jsxDEVImpl(\n type,\n config,\n maybeKey,\n !0,\n source,\n self,\n trackActualOwner\n ? Error(\"react-stack-top-frame\")\n : unknownOwnerDebugStack,\n trackActualOwner ? createTask(getTaskName(type)) : unknownOwnerDebugTask\n );\n };\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-jsx-runtime.production.js');\n} else {\n module.exports = require('./cjs/react-jsx-runtime.development.js');\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","/**\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 touch-friendly tap circle for continuous scrolling interactions.\n * タッチ操作向けのタップサークルを提供し、連続スクロール操作を実現するモジュール。\n */\n\nimport type { CSSProperties, PointerEvent as ReactPointerEvent } from \"react\"\nimport { forwardRef, useCallback, useImperativeHandle, useMemo, 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 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}\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 offsetY: 0,\n distance: 0,\n direction: 0,\n}\n\nconst DEAD_ZONE = 6\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 = 64, style, opacity = 1 }, 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 const updateDragState = useCallback(\n (clientY: number, capture: boolean = false) => {\n const { y } = centerRef.current\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 const nextState: TapScrollCircleDragState = {\n active: capture || distance >= DEAD_ZONE,\n offsetY,\n distance,\n direction,\n }\n setDragState(nextState)\n onDragChange(nextState)\n },\n [onDragChange],\n )\n\n const resetState = useCallback(\n (releasePointer: boolean = false) => {\n if (releasePointer && pointerIdRef.current !== null) {\n const element = rootRef.current\n if (element?.hasPointerCapture(pointerIdRef.current)) {\n element.releasePointerCapture(pointerIdRef.current)\n }\n }\n pointerIdRef.current = null\n setDragState(INITIAL_STATE)\n onDragChange(INITIAL_STATE)\n },\n [onDragChange],\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 rect = element.getBoundingClientRect()\n centerRef.current = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n }\n pointerIdRef.current = event.pointerId\n element.setPointerCapture(event.pointerId)\n updateDragState(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.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 normalized = useMemo(() => Math.min(dragState.distance, maxVisualDistance) / maxVisualDistance, [dragState.distance, maxVisualDistance])\n const sizeScale = useMemo(() => size / 64, [size])\n const stretchScale = useMemo(() => 1 + normalized * 0.4, [normalized])\n const pullOffset = useMemo(() => dragState.direction * normalized * 10 * sizeScale, [dragState.direction, normalized, sizeScale])\n const tailLength = useMemo(() => dragState.direction * normalized * 26 * sizeScale, [dragState.direction, normalized, sizeScale])\n const coreSize = useMemo(() => 22 * sizeScale, [sizeScale])\n const rodWidth = useMemo(() => Math.max(2.5, 3 * sizeScale), [sizeScale])\n const rodBaseHeight = useMemo(() => 6 * sizeScale, [sizeScale])\n const rodOffsetBase = useMemo(() => 3 * sizeScale, [sizeScale])\n const clampedOpacity = useMemo(() => Math.min(Math.max(opacity, 0), 1), [opacity])\n\n const rootStyle = useMemo(() => {\n const composed: CSSProperties = {\n ...style,\n width: size,\n height: size,\n transform: `translateY(${pullOffset}px)`,\n }\n composed.opacity = clampedOpacity\n return composed\n }, [clampedOpacity, pullOffset, size, style])\n const rodHeight = useMemo(() => Math.abs(tailLength) + rodBaseHeight, [rodBaseHeight, tailLength])\n const rodTranslate = useMemo(() => (tailLength > 0 ? rodOffsetBase : -Math.abs(tailLength) - rodOffsetBase), [rodOffsetBase, tailLength])\n\n return (\n <div\n ref={rootRef}\n className={twMerge(\n \"relative flex items-center justify-center touch-none select-none\",\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 <div\n className=\"absolute inset-0 rounded-full border border-white/40 bg-gradient-to-br from-[#1d4ed8]/60 via-[#60a5fa]/55 to-[#bfdbfe]/40 shadow-md\"\n style={{\n transform: `scaleY(${stretchScale})`,\n transition: dragState.active ? \"transform 40ms ease-out\" : \"transform 200ms ease\",\n }}\n />\n <div\n className=\"absolute left-1/2 top-1/2 h-6 w-6 -translate-x-1/2 -translate-y-1/2 rounded-full border border-white/50 bg-white/85\"\n style={{\n width: coreSize,\n height: coreSize,\n transform: `translate(-50%, calc(-50% + ${tailLength * 0.3}px)) scale(${1 + normalized * 0.2})`,\n transition: dragState.active ? \"transform 40ms ease-out\" : \"transform 200ms ease\",\n }}\n />\n <div\n className=\"absolute left-1/2 top-1/2 w-1 rounded-full bg-white/50\"\n style={{\n width: rodWidth,\n height: rodHeight,\n transform: `translate(-50%, ${rodTranslate}px)`,\n opacity: normalized,\n transition: dragState.active ? \"height 40ms ease-out, opacity 60ms\" : \"height 200ms ease, opacity 120ms\",\n }}\n />\n </div>\n )\n})\n\nTapScrollCircle.displayName = \"TapScrollCircle\"\n","import type { CSSProperties } from \"react\"\nimport { useState, useRef, useEffect, useCallback, useMemo } from \"react\"\nimport { twMerge } from \"tailwind-merge\"\nimport { minmax } from \"./utils.ts\"\nimport { TapScrollCircle, type TapScrollCircleDragState, type TapScrollCircleHandle } from \"./TapScrollCircle.tsx\"\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}\n\ntype ResolvedTapScrollCircleOptions = Required<Omit<ScrollBarTapCircleOptions, \"className\" | \"maxVisualDistance\">> & {\n className?: string\n maxVisualDistance: number\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 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, 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: 64,\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}\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, horizontal = false, scrollBarWidth = 12, className, ariaControls, tapScrollCircleOptions, itemCount }: ScrollBarProps) => {\n const [isDragging, setIsDragging] = 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 }\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 } = resolvedTapScrollOptions\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\n useEffect(() => {\n latestScrollPositionRef.current = scrollPosition\n }, [scrollPosition])\n\n // ドラッグ状態が変わったときに色を更新\n useEffect(() => {\n if (thumbRef.current) {\n if (isDragging) {\n thumbRef.current.style.backgroundColor = \"#4F4F4F\"; // ドラッグ中はさらに濃い色\n } else {\n thumbRef.current.style.backgroundColor = \"#7F7F7F\"; // 通常色\n }\n }\n }, [isDragging])\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 stopAutoScroll = useCallback(() => {\n if (autoScrollFrameRef.current !== null) {\n window.cancelAnimationFrame(autoScrollFrameRef.current)\n autoScrollFrameRef.current = null\n }\n lastAutoScrollTimestampRef.current = null\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 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 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 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 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 handleArrowPointerUp = () => {\n clearArrowTimers()\n }\n\n const handleArrowPointerDown = (direction: 1 | -1) => (event: React.MouseEvent<HTMLButtonElement> | React.TouchEvent<HTMLButtonElement>) => {\n if (!scrollBarVisible) {\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 const handleArrowKeyDown = (direction: 1 | -1) => (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (event.key === \"Enter\" || event.key === \" \" || event.key === \"Spacebar\") {\n event.preventDefault()\n scrollByStep(direction)\n }\n }\n\n // スクロールバーのつまみをマウスで押したときのハンドラ\n const handlePointerDownOnThumb = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if (\"button\" in event && event.button !== 0) {\n return\n }\n if (event.ctrlKey) {\n return\n }\n // event.preventDefault() // ここでは preventDefault しない\n event.stopPropagation()\n resetTapScroll()\n\n // ドラッグ開始時のつまみの位置\n const startThumbPosition = thumbPosition\n setIsDragging(true)\n\n // マウスの移動をキャプチャ\n capturePointerMove(\n event,\n ({ deltaX, deltaY }) => {\n const delta = horizontal ? deltaX : deltaY\n onScroll?.(translateToScrollPosition(startThumbPosition + delta), thumbPosition)\n },\n () => {\n setIsDragging(false)\n },\n )\n }\n\n // スクロールバーのトラックをマウスで押したときのハンドラ\n const handlePointerDownOnTrack = (event: React.MouseEvent | React.TouchEvent) => {\n // スクロールバーが表示されていない場合は何もしない\n if (!scrollBarVisible) {\n return\n }\n // マウスの場合、左ボタン以外のクリックや Ctrl キーが押されている場合は何もしない\n if (\"button\" in event && event.button !== 0) {\n return\n }\n if (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 = horizontal ? position.clientX : position.clientY\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n const clickPositionInTrack = horizontal ? startMousePosition - rect.left : startMousePosition - 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 = horizontal ? 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 return (\n <div\n className={twMerge(\n \"group relative cursor-default select-none\",\n horizontal ? \"flex flex-row items-stretch\" : \"flex flex-col items-stretch\",\n className,\n )}\n style={{\n [horizontal ? \"width\" : \"height\"]: viewportSize,\n [horizontal ? \"height\" : \"width\"]: 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 onDragChange={handleTapCircleDragChange}\n />\n )}\n <button\n type=\"button\"\n className=\"flex items-center justify-center text-xs text-[#313131] 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 [horizontal ? \"width\" : \"height\"]: arrowButtonLength,\n [horizontal ? \"height\" : \"width\"]: scrollBarWidth,\n backgroundColor: \"#E0E0E0\",\n }}\n aria-label={horizontal ? \"Scroll left\" : \"Scroll up\"}\n onMouseDown={handleArrowPointerDown(-1)}\n onTouchStart={handleArrowPointerDown(-1)}\n onMouseUp={handleArrowPointerUp}\n onMouseLeave={handleArrowPointerUp}\n onTouchEnd={handleArrowPointerUp}\n onTouchCancel={handleArrowPointerUp}\n onKeyDown={handleArrowKeyDown(-1)}\n disabled={!scrollBarVisible}>\n <span aria-hidden=\"true\">{horizontal ? \"◀\" : \"▲\"}</span>\n </button>\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 {/* コンテンツがビューポートより大きい場合にのみつまみを表示 */}\n {contentSize > viewportSize && (\n // スクロールバーのつまみの当たり判定を広げるためのラッパー\n <div\n className=\"group absolute\"\n style={{\n [horizontal ? \"width\" : \"height\"]: thumbSize,\n [horizontal ? \"left\" : \"top\"]: 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 tabIndex={0}>\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-[-2px]\" : \"group-active:inset-y-[-2px]\"}`\n : `inset-x-[1.5px] inset-y-0 group-hover:inset-x-[-0.5px] ${isDragging ? \"inset-x-[-2px]\" : \"group-active:inset-x-[-2px]\"}`,\n )}\n style={{\n backgroundColor: \"#7F7F7F\",\n borderRadius: scrollBarWidth - 1,\n ...(horizontal ? {\n left: 0,\n right: 0,\n top: isDragging ? -2 : 1.5,\n bottom: isDragging ? -2 : 1.5,\n } : {\n top: 0,\n bottom: 0,\n left: isDragging ? -2 : 1.5,\n right: isDragging ? -2 : 1.5,\n }),\n }}\n onMouseEnter={(e) => {\n if (horizontal) {\n e.currentTarget.style.top = \"-0.5px\";\n e.currentTarget.style.bottom = \"-0.5px\";\n } else {\n e.currentTarget.style.left = \"-0.5px\";\n e.currentTarget.style.right = \"-0.5px\";\n }\n if (!isDragging) {\n e.currentTarget.style.backgroundColor = \"#5F5F5F\";\n }\n }}\n onMouseLeave={(e) => {\n if (horizontal) {\n e.currentTarget.style.top = isDragging ? \"-2px\" : \"1.5px\";\n e.currentTarget.style.bottom = isDragging ? \"-2px\" : \"1.5px\";\n } else {\n e.currentTarget.style.left = isDragging ? \"-2px\" : \"1.5px\";\n e.currentTarget.style.right = isDragging ? \"-2px\" : \"1.5px\";\n }\n if (!isDragging) {\n e.currentTarget.style.backgroundColor = \"#7F7F7F\";\n }\n }}\n />\n </div>\n )}\n </div>\n <button\n type=\"button\"\n className=\"flex items-center justify-center text-xs text-[#313131] 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 [horizontal ? \"width\" : \"height\"]: arrowButtonLength,\n [horizontal ? \"height\" : \"width\"]: scrollBarWidth,\n backgroundColor: \"#E0E0E0\",\n }}\n aria-label={horizontal ? \"Scroll right\" : \"Scroll down\"}\n onMouseDown={handleArrowPointerDown(1)}\n onTouchStart={handleArrowPointerDown(1)}\n onMouseUp={handleArrowPointerUp}\n onMouseLeave={handleArrowPointerUp}\n onTouchEnd={handleArrowPointerUp}\n onTouchCancel={handleArrowPointerUp}\n onKeyDown={handleArrowKeyDown(1)}\n disabled={!scrollBarVisible}>\n <span aria-hidden=\"true\">{horizontal ? \"▶\" : \"▼\"}</span>\n </button>\n </div>\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, TAP_SCROLL_CANCEL_EVENT, type ScrollBarTapCircleOptions } 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 /** 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}\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\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, 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 })\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 const ItemComponents = useMemo(() => {\n return (\n <div ref={scrollContainerRef} className={twMerge(\"flex\", className)} style={style}>\n <div ref={contentAreaRef} className=\"relative h-full flex-1 overflow-hidden\" style={{ height: viewportSize, touchAction: \"none\" }} 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 scrollBarWidth={scrollBarWidth}\n ariaControls={id}\n tapScrollCircleOptions={tapScrollCircleOptions}\n itemCount={itemCount}\n />\n )}\n </div>\n )\n }, [children, contentSize, viewportSize, scrollBarWidth, className, style, isScrollable, scrollTo, id, background, tapScrollCircleOptions, itemCount])\n useEffect(() => {\n const element = contentAreaRef.current\n if (!element) {\n return\n }\n\n const DRAG_ACTIVATION_THRESHOLD = 6\n const interactiveSelector = \"input, textarea, select, button, a[href], [role='button']\"\n\n let dragPointerId: number | null = null\n let dragStartClientY = 0\n let dragStartScroll = 0\n let isDragging = false\n let pendingInteractiveDrag = 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 pendingInteractiveDrag = 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) => {\n if (!(target instanceof HTMLElement)) {\n return false\n }\n return target.closest(\"[data-scrollpane-ignore-drag='true']\") !== null\n }\n\n const isInteractiveTarget = (target: EventTarget | null) => {\n if (!(target instanceof HTMLElement)) {\n return false\n }\n return target.closest(interactiveSelector) !== null\n }\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 pendingInteractiveDrag = false\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 (pendingInteractiveDrag && distanceY < DRAG_ACTIVATION_THRESHOLD) {\n return\n }\n startDragging(event)\n }\n\n if (!isDragging) {\n return\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 pendingInteractiveDrag = isInteractiveTarget(event.target)\n isDragging = false\n shouldCancelNextClick = false\n velocitySamples = []\n\n if (!pendingInteractiveDrag) {\n shouldCancelNextClick = true\n startDragging(event)\n pushVelocitySample(event.clientY)\n if (event.cancelable) {\n event.preventDefault()\n }\n }\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 element.addEventListener(\"click\", handleClickCapture, true)\n element.addEventListener(\"pointerdown\", handlePointerDown, { passive: false })\n element.addEventListener(\"pointermove\", handlePointerMove, { passive: false })\n element.addEventListener(\"pointerup\", endDrag)\n element.addEventListener(\"pointercancel\", handlePointerCancel)\n window.addEventListener(\"pointermove\", handlePointerMove, { passive: false })\n window.addEventListener(\"pointerup\", endDrag)\n window.addEventListener(\"pointercancel\", handlePointerCancel)\n\n return () => {\n element.removeEventListener(\"click\", handleClickCapture, true)\n element.removeEventListener(\"pointerdown\", handlePointerDown)\n element.removeEventListener(\"pointermove\", handlePointerMove)\n element.removeEventListener(\"pointerup\", endDrag)\n element.removeEventListener(\"pointercancel\", handlePointerCancel)\n window.removeEventListener(\"pointermove\", handlePointerMove)\n window.removeEventListener(\"pointerup\", endDrag)\n window.removeEventListener(\"pointercancel\", handlePointerCancel)\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 }, [id, isScrollable, resolvedInertiaOptions, scrollTo, startInertia, stopInertia])\n\n return ItemComponents\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 * @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\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 {{ index: number; value: number }[]} updates - An array of updates, each with an index and the new value.\n */\n updates(updates: { index: number; value: number }[]): number | undefined {\n const deltaUpdates = updates\n .map(({ index, value }) => {\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 // 更新前に現在の値を取得する。未具現化の場合は baseValue を使用する\n const oldValue = this.deltas.has(index) ? (this.deltas.get(index) ?? 0) + this.baseValue : this.baseValue\n const delta = value - oldValue\n return { index, change: delta }\n })\n .filter((update) => update.change !== 0)\n\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 {{ index: number; change: number }[]} updates - An array of updates, each with an index and the change to apply.\n */\n updateDeltas(updates: { index: number; change: number }[]): 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 _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 * @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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\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?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } }): { 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 if (materializeOption?.materialize && this.valueFn) {\n if (materializeOption.ranges) {\n for (const range of materializeOption.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 // `ranges` の範囲にかかわらず、`safeIndex` を具現化する\n this._materialize(safeIndex)\n }\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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\n * @returns {number} The value at the given index.\n */\n get(index: number, options?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } }): number {\n if (index < 0 || index >= this.size) {\n throw new Error(\"Index out of bounds\")\n }\n\n const materializeOption = options?.materializeOption\n if (materializeOption?.materialize && this.valueFn) {\n if (materializeOption.ranges) {\n for (const range of materializeOption.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 if (index >= materializeOption.ranges[0].from && index <= materializeOption.ranges[materializeOption.ranges.length - 1].to) {\n this._materialize(index)\n }\n } else {\n this._materialize(index)\n }\n }\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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\n * @returns {number} The total sum of all values.\n */\n getTotal(options?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } }): number {\n const materializeOption = options?.materializeOption\n\n if (materializeOption?.materialize && this.valueFn) {\n if (materializeOption.ranges) {\n for (const range of materializeOption.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 }\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 console.assert(this.prefixSum(this.getSize() - 1).cumulative === this.prefixSum(this.getSize() - 1).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 console.assert(this.prefixSum(this.getSize() - 1).cumulative === this.prefixSum(this.getSize() - 1).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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\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?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } },\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n // サイズが 0 の場合は探索しようがないので -1 を返す\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 if (result.cumulative >= target) {\n ans = mid\n high = mid - 1\n } else {\n low = 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 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 {object} [options] - Optional settings for materializing values.\n * @param {object} [options.materializeOption] - Options to control materialization.\n * @param {boolean} [options.materializeOption.materialize=false] - Whether to materialize values.\n * @param {object[]} [options.materializeOption.ranges] - An optional array of ranges to materialize values for.\n * @param {number} options.materializeOption.ranges.from - The starting index of the range.\n * @param {number} options.materializeOption.ranges.to - The ending index of the range.\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?: { materializeOption?: { materialize: boolean; ranges?: { from: number; to: number }[] } },\n ): { index: number; total: number | undefined; cumulative: number | undefined; currentValue: number | undefined; safeIndex: number | undefined } {\n // サイズが 0 の場合は探索しようがないので -1 を返す\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 if (result.cumulative <= target) {\n ans = mid\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/**\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","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 inertiaOptions?: ScrollPaneProps[\"inertiaOptions\"]\n}\n\nfunction VirtualScrollInner<T>({ itemCount, getItem, getItemHeight, viewportSize, overscanCount = 5, className, onScroll, onRangeChange, children, background, initialScrollIndex, initialScrollOffset, tapScrollCircleOptions, 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 Logger.debug(\"[VirtualScroll] Scrolling to index:\", index)\n\n const safeIndex = minmax(index, 0, fenwickSize - 1)\n const safeIndexFrom = minmax(safeIndex - overscanCount * 2, 0, fenwickSize - 1) // 末尾の場合は最終スクロールの先頭を表示するので、余裕をもってマテリアライズする\n const safeIndexTo = minmax(safeIndex + overscanCount * 2, 0, fenwickSize - 1)\n // スクロール先のインデックスまでの高さをマテリアライズして、正確なオフセットを計算\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:\", index, \"Offset:\", offset, \"Total height:\", total, \"Current value:\", currentValue, \"safeIndex:\", safeIndex, \"safeIndexFrom:\", safeIndexFrom, \"safeIndexTo:\", safeIndexTo)\n\n if (total) {\n // コンテンツ全体のサイズも更新する。更新しないと\n setContentSize(total)\n // 計算された正確なオフセットにスクロール\n setShouldPaneScrollTo(offset - currentValue)\n }\n Logger.debug(\"[VirtualScroll] Setting scroll position to:\", offset - currentValue)\n }\n },\n [fenwickTree, overscanCount, fenwickSize],\n )\n\n const scrollTo = useCallback(\n (newPosition: number) => {\n if (scrollPaneRef.current) {\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 },\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<{ renderingStartIndex: number; renderingEndIndex: number; visibleStartIndex: number; visibleEndIndex: number }>(() => {\n if (fenwickSize === 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 let indexAdjustment = 0\n if (rawStartIndex === -1) {\n indexAdjustment = 0\n } else if ((cumulative ?? 0) < scrollPosition + (currentValue ?? 0)) {\n indexAdjustment = 1\n } else {\n indexAdjustment = 0\n }\n const visibleStartIndex = rawStartIndex === -1 ? 0 : rawStartIndex + indexAdjustment\n const renderingStartIndex = minmax(visibleStartIndex - overscanCount, 0, fenwickSize - 1)\n\n let visibleHeight = 0\n let visibleEndIndex = rawStartIndex === -1 ? 0 : rawStartIndex + indexAdjustment\n while (visibleEndIndex < fenwickSize && visibleHeight < viewportSize) {\n const currentHeight = getItemHeight(visibleEndIndex)\n visibleHeight += currentHeight\n visibleEndIndex++\n }\n visibleEndIndex -= 1 // 最後にインクリメントされた分を戻す\n\n const renderingEndIndex = minmax(visibleEndIndex + overscanCount, 0, fenwickSize - 1)\n\n Logger.debug(\"[VirtualScroll] Calculated rendering range:\", {\n renderingStartIndex,\n renderingEndIndex,\n visibleStartIndex,\n visibleEndIndex,\n scrollPosition,\n renderingContentSize: fenwickTree.getTotal(),\n overscanCount,\n viewportSize,\n })\n\n return { renderingStartIndex, renderingEndIndex, visibleStartIndex, visibleEndIndex }\n }, [scrollPosition, overscanCount, viewportSize, getItemHeight, fenwickTree, fenwickSize])\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 = minmax(renderingStartIndex, 0, fenwickSize - 1)\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 }> = []\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 })\n\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, height: _height }, index) => {\n const actualIndex = renderingStartIndex + index\n const safeActualIndex = minmax(actualIndex, 0, fenwickSize - 1)\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(\n ref,\n () => ({\n getScrollPosition: () => scrollPaneRef.current?.getScrollPosition() ?? -1,\n getContentSize: () => scrollPaneRef.current?.getContentSize() ?? -1,\n getViewportSize: () => scrollPaneRef.current?.getViewportSize() ?? -1,\n scrollTo: (newPosition: number) => scrollTo(newPosition),\n scrollToIndex: (index: number) => scrollToIndex(index),\n getFenwickTreeTotalHeight: () => fenwickTree.getTotal(),\n getFenwickSize: () => fenwickTree.getSize(),\n }),\n [scrollToIndex, fenwickTree, scrollTo],\n )\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 {renderVisibleItems}\n </ScrollPane>\n )\n}\n\nexport const VirtualScroll = forwardRef(VirtualScrollInner) as <T>(props: VirtualScrollProps<T> & { ref?: React.Ref<VirtualScrollHandle> }) => React.ReactElement\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"],"names":["REACT_ELEMENT_TYPE","REACT_FRAGMENT_TYPE","jsxProd","type","config","maybeKey","key","propName","reactJsxRuntime_production","getComponentNameFromType","REACT_CLIENT_REFERENCE","REACT_PROFILER_TYPE","REACT_STRICT_MODE_TYPE","REACT_SUSPENSE_TYPE","REACT_SUSPENSE_LIST_TYPE","REACT_ACTIVITY_TYPE","REACT_PORTAL_TYPE","REACT_CONTEXT_TYPE","REACT_CONSUMER_TYPE","REACT_FORWARD_REF_TYPE","innerType","REACT_MEMO_TYPE","REACT_LAZY_TYPE","testStringCoercion","value","checkKeyStringCoercion","JSCompiler_inline_result","JSCompiler_temp_const","JSCompiler_inline_result$jscomp$0","getTaskName","name","getOwner","dispatcher","ReactSharedInternals","UnknownOwner","hasValidKey","hasOwnProperty","getter","defineKeyPropWarningGetter","props","displayName","warnAboutAccessingKey","specialPropKeyWarningShown","elementRefGetterWithDeprecationWarning","componentName","didWarnAboutElementRef","ReactElement","self","source","owner","debugStack","debugTask","jsxDEVImpl","isStaticChildren","children","isArrayImpl","validateChildKeys","keys","k","didWarnAboutKeySpread","node","React","require$$0","createTask","callStackForError","unknownOwnerDebugStack","unknownOwnerDebugTask","reactJsxRuntime_development","trackActualOwner","jsxRuntimeModule","require$$1","Logger","message","args","minmax","min","max","INITIAL_STATE","DEAD_ZONE","TapScrollCircle","forwardRef","onDragChange","className","maxVisualDistance","size","style","opacity","ref","dragState","setDragState","useState","pointerIdRef","useRef","centerRef","rootRef","updateDragState","useCallback","clientY","capture","y","offsetY","distance","direction","nextState","resetState","releasePointer","element","handlePointerDown","event","rect","handlePointerMove","handlePointerUp","useImperativeHandle","normalized","useMemo","sizeScale","stretchScale","pullOffset","tailLength","coreSize","rodWidth","rodBaseHeight","rodOffsetBase","clampedOpacity","rootStyle","composed","rodHeight","rodTranslate","jsxs","twMerge","jsx","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","horizontal","scrollBarWidth","ariaControls","tapScrollCircleOptions","isDragging","setIsDragging","isTapActive","setIsTapActive","thumbRef","latestScrollPositionRef","arrowHoldIntervalRef","arrowHoldTimeoutRef","tapDragStateRef","tapCircleHandleRef","autoScrollFrameRef","lastAutoScrollTimestampRef","resolvedTapScrollOptions","manualMaxSpeedMultiplier","maxSpeedMultiplier","tapCircleEnabled","tapCircleSize","tapCircleOffsetX","tapCircleOffsetY","tapCircleClassName","tapCircleMaxDistance","tapCircleMaxSpeedMultiplier","tapCircleOpacity","effectiveTapMaxDistance","scrollRatio","arrowButtonLength","trackLength","rawThumbSize","thumbSize","maxScrollPosition","effectiveTrackLength","thumbPosition","scrollBarVisible","useEffect","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","deltaX","deltaY","handlePointerDownOnTrack","position","startMousePosition","clickPositionInTrack","tapCircleOpacityValue","tapCircleStyle","baseTop","e","DEFAULT_INERTIA_OPTIONS","ScrollPane","background","inertiaOptions","scrollPositionRef","_","_forceUpdate","useReducer","x","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","ItemComponents","DRAG_ACTIVATION_THRESHOLD","interactiveSelector","dragPointerId","dragStartClientY","dragStartScroll","pendingInteractiveDrag","shouldCancelNextClick","clickResetTimer","velocitySamples","pushVelocitySample","now","sample","shouldIgnoreTarget","target","isInteractiveTarget","handleClickCapture","startDragging","distanceY","endDrag","inertiaVelocity","lastSample","firstSample","deltaClientY","handlePointerCancel","FenwickMapTree","valueOrFn","options","range","mode","materializedValues","i","index","change","from","to","values","a","b","mid","frequencies","maxFreq","count","modes","sum","updates","deltaUpdates","oldValue","delta","update","currentDelta","treeIndex","updateTree","oldDelta","newDelta","changeForTree","safeIndex","materializeOption","treeNodeValue","currentValue","total","valueFn","newTree","newTotal","theoreticalTotal","newSize","oldSize","low","high","ans","result","finalTotal","useFenwickMapTree","validSize","prevTreeRef","tree","VirtualScrollInner","getItem","getItemHeight","overscanCount","onRangeChange","initialScrollIndex","initialScrollOffset","scrollPaneRef","isMounted","fenwickTreeInitArgs","fenwickTree","initialValues","safeIndexFrom","safeIndexTo","cumulative","materializedTotal","setScrollPosition","setContentSize","shouldPaneScrollTo","setShouldPaneScrollTo","fenwickSize","setFenwickSize","totalHeight","scrollToIndex","offset","safePosition","handleScroll","_prevPosition","renderingRanges","rawStartIndex","indexAdjustment","visibleStartIndex","renderingStartIndex","visibleHeight","visibleEndIndex","currentHeight","renderingEndIndex","scrollPaneScrollPosition","renderVisibleItems","currentScrollPosition","safeRenderingStartIndex","oldHeight","visibleItems","toUpdateHeights","newHeight","containerTop","item","_height","actualIndex","safeActualIndex","actualOffset","VirtualScroll","DoublyLinkedListNode","DoublyLinkedList","head","useLruCache","capacity","cache","list","lruNode","get","set","has","clear","handler","setHandler","HEIGHT_CACHE_CAPACITY","useHeightCache"],"mappings":"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","x_google_ignoreList":[0,1,2]}