@vielzeug/scroll 2.0.1 → 2.0.2

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":"grouped-virtualizer.cjs","names":[],"sources":["../src/grouped-virtualizer.ts"],"sourcesContent":["import { resolveEstimateFn } from './_utils';\nimport { requireNonNegativeNumber, requirePositiveNumber, validateOverscan } from './_validation';\nimport {\n createVirtualizer,\n DEFAULT_ESTIMATE_SIZE,\n DEFAULT_OVERSCAN,\n type MeasurementCache,\n type Overscan,\n type ScrollTarget,\n type ScrollToIndexOptions,\n type VirtualItem,\n type VirtualizerState,\n type VirtualizerUpdateOptions,\n type VirtualKey,\n} from './virtualizer';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface GroupSection<T> {\n items: T[];\n label: string;\n}\n\nexport interface GroupVirtualItem<T> extends VirtualItem {\n /** Item data. */\n data: T;\n /** Index within the section. */\n itemIndex: number;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualHeader extends VirtualItem {\n label: string;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualizerState<T> {\n readonly headers: GroupVirtualHeader[];\n readonly items: Array<GroupVirtualItem<T>>;\n readonly stickyHeader: GroupVirtualHeader | null;\n readonly totalSize: number;\n}\n\n/**\n * Options accepted by `GroupVirtualizer.update()`. Overrides are applied\n * together with the new sections on the next render cycle.\n *\n * Intentionally excludes `horizontal` (axis cannot change at runtime) and\n * `initialOffset` (one-time bootstrap).\n */\nexport interface GroupVirtualizerUpdateOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n measurementCache?: MeasurementCache;\n onChange?: ((state: GroupVirtualizerState<T>) => void) | undefined;\n onScrollEnd?: ((offset: number) => void) | undefined;\n onScrollingChange?: ((isScrolling: boolean) => void) | undefined;\n overscan?: Overscan;\n scrollEndDelay?: number;\n}\n\nexport interface GroupVirtualizerOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n horizontal?: boolean;\n measurementCache?: MeasurementCache;\n /** Called after every render cycle with the new state. Replace through `update()`. */\n onChange?: (state: GroupVirtualizerState<T>) => void;\n /** Called when scrolling settles. Replace through `update()`. */\n onScrollEnd?: (offset: number) => void;\n /** Called when the scrolling state changes. Replace through `update()`. */\n onScrollingChange?: (isScrolling: boolean) => void;\n overscan?: Overscan;\n /**\n * Debounce delay (ms) for scroll-end detection. Defaults to 150.\n * See `VirtualizerOptions.scrollEndDelay` for details.\n */\n scrollEndDelay?: number;\n sections: Array<GroupSection<T>>;\n}\n\nexport interface GroupVirtualizer<T> {\n readonly count: number;\n readonly disposalSignal: AbortSignal;\n readonly disposed: boolean;\n /** `true` while the user is actively scrolling; `false` once scroll has settled. */\n readonly isScrolling: boolean;\n readonly items: ReadonlyArray<GroupVirtualItem<T>>;\n readonly scrollOffset: number;\n readonly stickyItems: VirtualItem[];\n readonly totalSize: number;\n dispose: () => void;\n invalidate: () => void;\n measure: (index: number, size: number) => void;\n measureBatch: (entries: Array<{ index: number; size: number }>) => void;\n measureEl: (index: number, el: HTMLElement) => () => void;\n refresh: () => void;\n scrollToBottom: (options?: { behavior?: ScrollBehavior }) => void;\n scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;\n scrollToItem: (sectionIndex: number, itemIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToOffset: (offset: number, options?: { behavior?: ScrollBehavior }) => void;\n scrollToSection: (sectionIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToTop: (options?: { behavior?: ScrollBehavior }) => void;\n update: (sections: Array<GroupSection<T>>, opts?: GroupVirtualizerUpdateOptions<T>) => void;\n [Symbol.dispose]: () => void;\n}\n\n// ─── Flat entry map ───────────────────────────────────────────────────────────\n\ntype FlatHeader = { isHeader: true; itemIndex: -1; label: string; sectionIndex: number };\ntype FlatItem<T> = { isHeader: false; item: T; itemIndex: number; sectionIndex: number };\ntype FlatEntry<T> = FlatHeader | FlatItem<T>;\n\nfunction buildFlatEntries<T>(sections: Array<GroupSection<T>>): FlatEntry<T>[] {\n const flat: FlatEntry<T>[] = [];\n\n for (let s = 0; s < sections.length; s++) {\n const section = sections[s]!;\n\n flat.push({ isHeader: true, itemIndex: -1, label: section.label, sectionIndex: s });\n\n for (let i = 0; i < section.items.length; i++) {\n flat.push({ isHeader: false, item: section.items[i]!, itemIndex: i, sectionIndex: s });\n }\n }\n\n return flat;\n}\n\n// ─── Implementation ───────────────────────────────────────────────────────────\n\nexport function createGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: GroupVirtualizerOptions<T>,\n): GroupVirtualizer<T> {\n if (typeof options.estimateHeaderSize === 'number')\n requirePositiveNumber(options.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof options.estimateItemSize === 'number') requirePositiveNumber(options.estimateItemSize, 'estimateItemSize');\n\n if (options.overscan !== undefined) validateOverscan(options.overscan);\n\n if (options.scrollEndDelay !== undefined) requireNonNegativeNumber(options.scrollEndDelay, 'scrollEndDelay');\n\n let sections = options.sections;\n let flat = buildFlatEntries(sections);\n\n function buildEstimateHeader(\n estimateHeaderSize: GroupVirtualizerOptions<T>['estimateHeaderSize'],\n ): (index: number) => number {\n return typeof estimateHeaderSize === 'function'\n ? (index: number) => {\n const entry = flat[index]!;\n\n return (estimateHeaderSize as (section: GroupSection<T>, sectionIndex: number) => number)(\n sections[entry.sectionIndex]!,\n entry.sectionIndex,\n );\n }\n : resolveEstimateFn(\n typeof estimateHeaderSize === 'number' ? estimateHeaderSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n let estimateHeaderFn = buildEstimateHeader(options.estimateHeaderSize);\n let estimateItemUserFn: ((item: T, itemIndex: number, sectionIndex: number) => number) | null =\n typeof options.estimateItemSize === 'function' ? options.estimateItemSize : null;\n let estimateItemFixedFn: ((index: number) => number) | null = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof options.estimateItemSize === 'number' ? options.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n let userGetItemKey = options.getItemKey;\n\n function estimateFn(globalIndex: number): number {\n const entry = flat[globalIndex];\n\n if (!entry) return DEFAULT_ESTIMATE_SIZE;\n\n if (entry.isHeader) return estimateHeaderFn(globalIndex);\n\n if (estimateItemUserFn) return estimateItemUserFn(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return estimateItemFixedFn!(globalIndex);\n }\n\n function getItemKey(globalIndex: number): VirtualKey {\n const entry = flat[globalIndex];\n\n if (!entry) return globalIndex;\n\n if (entry.isHeader) return `__header_${entry.sectionIndex}`;\n\n if (userGetItemKey) return userGetItemKey(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return globalIndex;\n }\n\n let destroyed = false;\n let lastItems: Array<GroupVirtualItem<T>> = [];\n let onChange = options.onChange;\n let onScrollEnd = options.onScrollEnd;\n let onScrollingChange = options.onScrollingChange;\n\n function mapState(state: VirtualizerState): GroupVirtualizerState<T> {\n const items: Array<GroupVirtualItem<T>> = [];\n const headers: GroupVirtualHeader[] = [];\n let stickyHeader: GroupVirtualHeader | null = null;\n\n for (const vi of state.items) {\n const entry = flat[vi.index];\n\n if (!entry) continue;\n\n if (entry.isHeader) {\n headers.push({ ...vi, label: entry.label ?? '', sectionIndex: entry.sectionIndex });\n } else {\n items.push({ ...vi, data: entry.item, itemIndex: entry.itemIndex, sectionIndex: entry.sectionIndex });\n }\n }\n\n if (state.stickyItems.length > 0) {\n const svi = state.stickyItems[0]!;\n const entry = flat[svi.index];\n\n if (entry?.isHeader) {\n stickyHeader = { ...svi, label: entry.label ?? '', sectionIndex: entry.sectionIndex };\n }\n }\n\n lastItems = items;\n\n return { headers, items, stickyHeader, totalSize: state.totalSize };\n }\n\n const virtualizer = createVirtualizer(target, {\n count: flat.length,\n estimateSize: estimateFn,\n getItemKey,\n horizontal: options.horizontal,\n measurementCache: options.measurementCache,\n onChange: (state) => {\n const mapped = mapState(state);\n\n onChange?.(mapped);\n },\n onScrollEnd: (offset) => onScrollEnd?.(offset),\n onScrollingChange: (isScrolling) => onScrollingChange?.(isScrolling),\n overscan: options.overscan ?? DEFAULT_OVERSCAN,\n scrollEndDelay: options.scrollEndDelay,\n sticky: (i) => flat[i]?.isHeader ?? false,\n });\n\n const ac = new AbortController();\n\n function _dispose(): void {\n if (destroyed) return;\n\n destroyed = true;\n ac.abort();\n virtualizer.dispose();\n }\n\n // Build a flat-index lookup: [sectionIndex, itemIndex] → flat index.\n // Returns -1 when sectionIndex is out of range so callers can no-op safely.\n function flatIndexOf(sectionIndex: number, itemIndex?: number): number {\n if (sectionIndex < 0 || sectionIndex >= sections.length) return -1;\n\n let pos = 0;\n\n for (let s = 0; s < sections.length; s++) {\n if (s === sectionIndex) {\n if (itemIndex === undefined) return pos; // header\n\n return pos + 1 + itemIndex;\n }\n\n pos += 1 + sections[s]!.items.length;\n }\n\n return -1; // unreachable\n }\n\n return {\n get count() {\n return virtualizer.count;\n },\n get disposalSignal() {\n return ac.signal;\n },\n dispose: _dispose,\n get disposed() {\n return destroyed;\n },\n invalidate() {\n if (destroyed) return;\n\n virtualizer.invalidate();\n },\n get isScrolling() {\n return virtualizer.isScrolling;\n },\n get items() {\n return lastItems;\n },\n measure(index: number, size: number) {\n if (destroyed) return;\n\n virtualizer.measure(index, size);\n },\n measureBatch(entries: Array<{ index: number; size: number }>) {\n if (destroyed) return;\n\n virtualizer.measureBatch(entries);\n },\n measureEl(index: number, el: HTMLElement) {\n if (destroyed) return () => {};\n\n return virtualizer.measureEl(index, el);\n },\n refresh() {\n if (destroyed) return;\n\n virtualizer.refresh();\n },\n get scrollOffset() {\n return virtualizer.scrollOffset;\n },\n scrollToBottom(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToBottom(opts);\n },\n scrollToIndex(index: number, opts?: ScrollToIndexOptions) {\n if (destroyed) return;\n\n virtualizer.scrollToIndex(index, opts);\n },\n scrollToItem(sectionIndex, itemIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex, itemIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToOffset(offset: number, opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToOffset(offset, opts);\n },\n scrollToSection(sectionIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToTop(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToTop(opts);\n },\n get stickyItems() {\n return virtualizer.stickyItems;\n },\n [Symbol.dispose]: _dispose,\n get totalSize() {\n return virtualizer.totalSize;\n },\n /**\n * Replace all sections. Closures for estimateFn and getItemKey already\n * capture the live `flat`/`sections` references — only count is passed to\n * the underlying virtualizer to avoid discarding measured sizes on every\n * data refresh. `refresh()` rebuilds offsets while preserving the cache.\n */\n update(nextSections, opts?: GroupVirtualizerUpdateOptions<T>) {\n if (destroyed) return;\n\n if (opts) {\n if (typeof opts.estimateHeaderSize === 'number')\n requirePositiveNumber(opts.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof opts.estimateItemSize === 'number') requirePositiveNumber(opts.estimateItemSize, 'estimateItemSize');\n\n if (opts.overscan !== undefined) validateOverscan(opts.overscan);\n\n if (opts.scrollEndDelay !== undefined) requireNonNegativeNumber(opts.scrollEndDelay, 'scrollEndDelay');\n\n if (Object.hasOwn(opts, 'onChange')) onChange = opts.onChange;\n\n if (Object.hasOwn(opts, 'onScrollEnd')) onScrollEnd = opts.onScrollEnd;\n\n if (Object.hasOwn(opts, 'onScrollingChange')) onScrollingChange = opts.onScrollingChange;\n\n // Apply option overrides before rebuilding flat entries.\n if (opts.estimateHeaderSize !== undefined) {\n estimateHeaderFn = buildEstimateHeader(opts.estimateHeaderSize);\n }\n\n if (opts.estimateItemSize !== undefined) {\n estimateItemUserFn = typeof opts.estimateItemSize === 'function' ? opts.estimateItemSize : null;\n estimateItemFixedFn = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof opts.estimateItemSize === 'number' ? opts.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n if (opts.getItemKey !== undefined) userGetItemKey = opts.getItemKey;\n }\n\n sections = nextSections;\n\n const prevCount = flat.length;\n\n flat = buildFlatEntries(sections);\n\n const virtUpdateOpts: VirtualizerUpdateOptions = { count: flat.length };\n\n if (opts?.measurementCache !== undefined) virtUpdateOpts.measurementCache = opts.measurementCache;\n\n if (opts?.overscan !== undefined) virtUpdateOpts.overscan = opts.overscan;\n\n if (opts?.scrollEndDelay !== undefined) virtUpdateOpts.scrollEndDelay = opts.scrollEndDelay;\n\n if (\n flat.length !== prevCount ||\n opts?.measurementCache !== undefined ||\n opts?.overscan !== undefined ||\n opts?.scrollEndDelay !== undefined\n ) {\n virtualizer.update(virtUpdateOpts);\n } else {\n virtualizer.refresh();\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"grouped-virtualizer.cjs","names":[],"sources":["../src/grouped-virtualizer.ts"],"sourcesContent":["import { resolveEstimateFn } from './_utils';\nimport { requireNonNegativeNumber, requirePositiveNumber, validateOverscan } from './_validation';\nimport {\n createVirtualizer,\n DEFAULT_ESTIMATE_SIZE,\n DEFAULT_OVERSCAN,\n type MeasurementCache,\n type Overscan,\n type ScrollTarget,\n type ScrollToIndexOptions,\n type VirtualItem,\n type VirtualizerState,\n type VirtualizerUpdateOptions,\n type VirtualKey,\n} from './virtualizer';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface GroupSection<T> {\n items: T[];\n label: string;\n}\n\nexport interface GroupVirtualItem<T> extends VirtualItem {\n /** Item data. */\n data: T;\n /** Index within the section. */\n itemIndex: number;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualHeader extends VirtualItem {\n label: string;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualizerState<T> {\n readonly headers: GroupVirtualHeader[];\n readonly items: Array<GroupVirtualItem<T>>;\n readonly stickyHeader: GroupVirtualHeader | null;\n readonly totalSize: number;\n}\n\n/**\n * Options accepted by `GroupVirtualizer.update()`. Overrides are applied\n * together with the new sections on the next render cycle.\n *\n * Intentionally excludes `horizontal` (axis cannot change at runtime) and\n * `initialOffset` (one-time bootstrap).\n */\nexport interface GroupVirtualizerUpdateOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n measurementCache?: MeasurementCache;\n onChange?: ((state: GroupVirtualizerState<T>) => void) | undefined;\n onScrollEnd?: ((offset: number) => void) | undefined;\n onScrollingChange?: ((isScrolling: boolean) => void) | undefined;\n overscan?: Overscan;\n scrollEndDelay?: number;\n}\n\nexport interface GroupVirtualizerOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n horizontal?: boolean;\n measurementCache?: MeasurementCache;\n /** Called after every render cycle with the new state. Replace through `update()`. */\n onChange?: (state: GroupVirtualizerState<T>) => void;\n /** Called when scrolling settles. Replace through `update()`. */\n onScrollEnd?: (offset: number) => void;\n /** Called when the scrolling state changes. Replace through `update()`. */\n onScrollingChange?: (isScrolling: boolean) => void;\n overscan?: Overscan;\n /**\n * Debounce delay (ms) for scroll-end detection. Defaults to 150.\n * See `VirtualizerOptions.scrollEndDelay` for details.\n */\n scrollEndDelay?: number;\n sections: Array<GroupSection<T>>;\n}\n\nexport interface GroupVirtualizer<T> {\n readonly count: number;\n readonly disposalSignal: AbortSignal;\n dispose: () => void;\n readonly disposed: boolean;\n invalidate: () => void;\n /** `true` while the user is actively scrolling; `false` once scroll has settled. */\n readonly isScrolling: boolean;\n readonly items: ReadonlyArray<GroupVirtualItem<T>>;\n measure: (index: number, size: number) => void;\n measureBatch: (entries: Array<{ index: number; size: number }>) => void;\n measureEl: (index: number, el: HTMLElement) => () => void;\n refresh: () => void;\n readonly scrollOffset: number;\n scrollToBottom: (options?: { behavior?: ScrollBehavior }) => void;\n scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;\n scrollToItem: (sectionIndex: number, itemIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToOffset: (offset: number, options?: { behavior?: ScrollBehavior }) => void;\n scrollToSection: (sectionIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToTop: (options?: { behavior?: ScrollBehavior }) => void;\n readonly stickyItems: VirtualItem[];\n readonly totalSize: number;\n update: (sections: Array<GroupSection<T>>, opts?: GroupVirtualizerUpdateOptions<T>) => void;\n [Symbol.dispose]: () => void;\n}\n\n// ─── Flat entry map ───────────────────────────────────────────────────────────\n\ntype FlatHeader = { isHeader: true; itemIndex: -1; label: string; sectionIndex: number };\ntype FlatItem<T> = { isHeader: false; item: T; itemIndex: number; sectionIndex: number };\ntype FlatEntry<T> = FlatHeader | FlatItem<T>;\n\nfunction buildFlatEntries<T>(sections: Array<GroupSection<T>>): FlatEntry<T>[] {\n const flat: FlatEntry<T>[] = [];\n\n for (let s = 0; s < sections.length; s++) {\n const section = sections[s]!;\n\n flat.push({ isHeader: true, itemIndex: -1, label: section.label, sectionIndex: s });\n\n for (let i = 0; i < section.items.length; i++) {\n flat.push({ isHeader: false, item: section.items[i]!, itemIndex: i, sectionIndex: s });\n }\n }\n\n return flat;\n}\n\n// ─── Implementation ───────────────────────────────────────────────────────────\n\nexport function createGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: GroupVirtualizerOptions<T>,\n): GroupVirtualizer<T> {\n if (typeof options.estimateHeaderSize === 'number')\n requirePositiveNumber(options.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof options.estimateItemSize === 'number') requirePositiveNumber(options.estimateItemSize, 'estimateItemSize');\n\n if (options.overscan !== undefined) validateOverscan(options.overscan);\n\n if (options.scrollEndDelay !== undefined) requireNonNegativeNumber(options.scrollEndDelay, 'scrollEndDelay');\n\n let sections = options.sections;\n let flat = buildFlatEntries(sections);\n\n function buildEstimateHeader(\n estimateHeaderSize: GroupVirtualizerOptions<T>['estimateHeaderSize'],\n ): (index: number) => number {\n return typeof estimateHeaderSize === 'function'\n ? (index: number) => {\n const entry = flat[index]!;\n\n return (estimateHeaderSize as (section: GroupSection<T>, sectionIndex: number) => number)(\n sections[entry.sectionIndex]!,\n entry.sectionIndex,\n );\n }\n : resolveEstimateFn(\n typeof estimateHeaderSize === 'number' ? estimateHeaderSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n let estimateHeaderFn = buildEstimateHeader(options.estimateHeaderSize);\n let estimateItemUserFn: ((item: T, itemIndex: number, sectionIndex: number) => number) | null =\n typeof options.estimateItemSize === 'function' ? options.estimateItemSize : null;\n let estimateItemFixedFn: ((index: number) => number) | null = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof options.estimateItemSize === 'number' ? options.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n let userGetItemKey = options.getItemKey;\n\n function estimateFn(globalIndex: number): number {\n const entry = flat[globalIndex];\n\n if (!entry) return DEFAULT_ESTIMATE_SIZE;\n\n if (entry.isHeader) return estimateHeaderFn(globalIndex);\n\n if (estimateItemUserFn) return estimateItemUserFn(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return estimateItemFixedFn!(globalIndex);\n }\n\n function getItemKey(globalIndex: number): VirtualKey {\n const entry = flat[globalIndex];\n\n if (!entry) return globalIndex;\n\n if (entry.isHeader) return `__header_${entry.sectionIndex}`;\n\n if (userGetItemKey) return userGetItemKey(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return globalIndex;\n }\n\n let destroyed = false;\n let lastItems: Array<GroupVirtualItem<T>> = [];\n let onChange = options.onChange;\n let onScrollEnd = options.onScrollEnd;\n let onScrollingChange = options.onScrollingChange;\n\n function mapState(state: VirtualizerState): GroupVirtualizerState<T> {\n const items: Array<GroupVirtualItem<T>> = [];\n const headers: GroupVirtualHeader[] = [];\n let stickyHeader: GroupVirtualHeader | null = null;\n\n for (const vi of state.items) {\n const entry = flat[vi.index];\n\n if (!entry) continue;\n\n if (entry.isHeader) {\n headers.push({ ...vi, label: entry.label ?? '', sectionIndex: entry.sectionIndex });\n } else {\n items.push({ ...vi, data: entry.item, itemIndex: entry.itemIndex, sectionIndex: entry.sectionIndex });\n }\n }\n\n if (state.stickyItems.length > 0) {\n const svi = state.stickyItems[0]!;\n const entry = flat[svi.index];\n\n if (entry?.isHeader) {\n stickyHeader = { ...svi, label: entry.label ?? '', sectionIndex: entry.sectionIndex };\n }\n }\n\n lastItems = items;\n\n return { headers, items, stickyHeader, totalSize: state.totalSize };\n }\n\n const virtualizer = createVirtualizer(target, {\n count: flat.length,\n estimateSize: estimateFn,\n getItemKey,\n horizontal: options.horizontal,\n measurementCache: options.measurementCache,\n onChange: (state) => {\n const mapped = mapState(state);\n\n onChange?.(mapped);\n },\n onScrollEnd: (offset) => onScrollEnd?.(offset),\n onScrollingChange: (isScrolling) => onScrollingChange?.(isScrolling),\n overscan: options.overscan ?? DEFAULT_OVERSCAN,\n scrollEndDelay: options.scrollEndDelay,\n sticky: (i) => flat[i]?.isHeader ?? false,\n });\n\n const ac = new AbortController();\n\n function _dispose(): void {\n if (destroyed) return;\n\n destroyed = true;\n ac.abort();\n virtualizer.dispose();\n }\n\n // Build a flat-index lookup: [sectionIndex, itemIndex] → flat index.\n // Returns -1 when sectionIndex is out of range so callers can no-op safely.\n function flatIndexOf(sectionIndex: number, itemIndex?: number): number {\n if (sectionIndex < 0 || sectionIndex >= sections.length) return -1;\n\n let pos = 0;\n\n for (let s = 0; s < sections.length; s++) {\n if (s === sectionIndex) {\n if (itemIndex === undefined) return pos; // header\n\n return pos + 1 + itemIndex;\n }\n\n pos += 1 + sections[s]!.items.length;\n }\n\n return -1; // unreachable\n }\n\n return {\n get count() {\n return virtualizer.count;\n },\n get disposalSignal() {\n return ac.signal;\n },\n dispose: _dispose,\n get disposed() {\n return destroyed;\n },\n invalidate() {\n if (destroyed) return;\n\n virtualizer.invalidate();\n },\n get isScrolling() {\n return virtualizer.isScrolling;\n },\n get items() {\n return lastItems;\n },\n measure(index: number, size: number) {\n if (destroyed) return;\n\n virtualizer.measure(index, size);\n },\n measureBatch(entries: Array<{ index: number; size: number }>) {\n if (destroyed) return;\n\n virtualizer.measureBatch(entries);\n },\n measureEl(index: number, el: HTMLElement) {\n if (destroyed) return () => {};\n\n return virtualizer.measureEl(index, el);\n },\n refresh() {\n if (destroyed) return;\n\n virtualizer.refresh();\n },\n get scrollOffset() {\n return virtualizer.scrollOffset;\n },\n scrollToBottom(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToBottom(opts);\n },\n scrollToIndex(index: number, opts?: ScrollToIndexOptions) {\n if (destroyed) return;\n\n virtualizer.scrollToIndex(index, opts);\n },\n scrollToItem(sectionIndex, itemIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex, itemIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToOffset(offset: number, opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToOffset(offset, opts);\n },\n scrollToSection(sectionIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToTop(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToTop(opts);\n },\n get stickyItems() {\n return virtualizer.stickyItems;\n },\n [Symbol.dispose]: _dispose,\n get totalSize() {\n return virtualizer.totalSize;\n },\n /**\n * Replace all sections. Closures for estimateFn and getItemKey already\n * capture the live `flat`/`sections` references — only count is passed to\n * the underlying virtualizer to avoid discarding measured sizes on every\n * data refresh. `refresh()` rebuilds offsets while preserving the cache.\n */\n update(nextSections, opts?: GroupVirtualizerUpdateOptions<T>) {\n if (destroyed) return;\n\n if (opts) {\n if (typeof opts.estimateHeaderSize === 'number')\n requirePositiveNumber(opts.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof opts.estimateItemSize === 'number') requirePositiveNumber(opts.estimateItemSize, 'estimateItemSize');\n\n if (opts.overscan !== undefined) validateOverscan(opts.overscan);\n\n if (opts.scrollEndDelay !== undefined) requireNonNegativeNumber(opts.scrollEndDelay, 'scrollEndDelay');\n\n if (Object.hasOwn(opts, 'onChange')) onChange = opts.onChange;\n\n if (Object.hasOwn(opts, 'onScrollEnd')) onScrollEnd = opts.onScrollEnd;\n\n if (Object.hasOwn(opts, 'onScrollingChange')) onScrollingChange = opts.onScrollingChange;\n\n // Apply option overrides before rebuilding flat entries.\n if (opts.estimateHeaderSize !== undefined) {\n estimateHeaderFn = buildEstimateHeader(opts.estimateHeaderSize);\n }\n\n if (opts.estimateItemSize !== undefined) {\n estimateItemUserFn = typeof opts.estimateItemSize === 'function' ? opts.estimateItemSize : null;\n estimateItemFixedFn = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof opts.estimateItemSize === 'number' ? opts.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n if (opts.getItemKey !== undefined) userGetItemKey = opts.getItemKey;\n }\n\n sections = nextSections;\n\n const prevCount = flat.length;\n\n flat = buildFlatEntries(sections);\n\n const virtUpdateOpts: VirtualizerUpdateOptions = { count: flat.length };\n\n if (opts?.measurementCache !== undefined) virtUpdateOpts.measurementCache = opts.measurementCache;\n\n if (opts?.overscan !== undefined) virtUpdateOpts.overscan = opts.overscan;\n\n if (opts?.scrollEndDelay !== undefined) virtUpdateOpts.scrollEndDelay = opts.scrollEndDelay;\n\n if (\n flat.length !== prevCount ||\n opts?.measurementCache !== undefined ||\n opts?.overscan !== undefined ||\n opts?.scrollEndDelay !== undefined\n ) {\n virtualizer.update(virtUpdateOpts);\n } else {\n virtualizer.refresh();\n }\n },\n };\n}\n"],"mappings":"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"}
@@ -61,15 +61,12 @@ export interface GroupVirtualizerOptions<T> {
61
61
  export interface GroupVirtualizer<T> {
62
62
  readonly count: number;
63
63
  readonly disposalSignal: AbortSignal;
64
+ dispose: () => void;
64
65
  readonly disposed: boolean;
66
+ invalidate: () => void;
65
67
  /** `true` while the user is actively scrolling; `false` once scroll has settled. */
66
68
  readonly isScrolling: boolean;
67
69
  readonly items: ReadonlyArray<GroupVirtualItem<T>>;
68
- readonly scrollOffset: number;
69
- readonly stickyItems: VirtualItem[];
70
- readonly totalSize: number;
71
- dispose: () => void;
72
- invalidate: () => void;
73
70
  measure: (index: number, size: number) => void;
74
71
  measureBatch: (entries: Array<{
75
72
  index: number;
@@ -77,6 +74,7 @@ export interface GroupVirtualizer<T> {
77
74
  }>) => void;
78
75
  measureEl: (index: number, el: HTMLElement) => () => void;
79
76
  refresh: () => void;
77
+ readonly scrollOffset: number;
80
78
  scrollToBottom: (options?: {
81
79
  behavior?: ScrollBehavior;
82
80
  }) => void;
@@ -89,6 +87,8 @@ export interface GroupVirtualizer<T> {
89
87
  scrollToTop: (options?: {
90
88
  behavior?: ScrollBehavior;
91
89
  }) => void;
90
+ readonly stickyItems: VirtualItem[];
91
+ readonly totalSize: number;
92
92
  update: (sections: Array<GroupSection<T>>, opts?: GroupVirtualizerUpdateOptions<T>) => void;
93
93
  [Symbol.dispose]: () => void;
94
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"grouped-virtualizer.d.ts","sourceRoot":"","sources":["../src/grouped-virtualizer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grouped-virtualizer.d.ts","sourceRoot":"","sources":["../src/grouped-virtualizer.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"grouped-virtualizer.js","names":[],"sources":["../src/grouped-virtualizer.ts"],"sourcesContent":["import { resolveEstimateFn } from './_utils';\nimport { requireNonNegativeNumber, requirePositiveNumber, validateOverscan } from './_validation';\nimport {\n createVirtualizer,\n DEFAULT_ESTIMATE_SIZE,\n DEFAULT_OVERSCAN,\n type MeasurementCache,\n type Overscan,\n type ScrollTarget,\n type ScrollToIndexOptions,\n type VirtualItem,\n type VirtualizerState,\n type VirtualizerUpdateOptions,\n type VirtualKey,\n} from './virtualizer';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface GroupSection<T> {\n items: T[];\n label: string;\n}\n\nexport interface GroupVirtualItem<T> extends VirtualItem {\n /** Item data. */\n data: T;\n /** Index within the section. */\n itemIndex: number;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualHeader extends VirtualItem {\n label: string;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualizerState<T> {\n readonly headers: GroupVirtualHeader[];\n readonly items: Array<GroupVirtualItem<T>>;\n readonly stickyHeader: GroupVirtualHeader | null;\n readonly totalSize: number;\n}\n\n/**\n * Options accepted by `GroupVirtualizer.update()`. Overrides are applied\n * together with the new sections on the next render cycle.\n *\n * Intentionally excludes `horizontal` (axis cannot change at runtime) and\n * `initialOffset` (one-time bootstrap).\n */\nexport interface GroupVirtualizerUpdateOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n measurementCache?: MeasurementCache;\n onChange?: ((state: GroupVirtualizerState<T>) => void) | undefined;\n onScrollEnd?: ((offset: number) => void) | undefined;\n onScrollingChange?: ((isScrolling: boolean) => void) | undefined;\n overscan?: Overscan;\n scrollEndDelay?: number;\n}\n\nexport interface GroupVirtualizerOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n horizontal?: boolean;\n measurementCache?: MeasurementCache;\n /** Called after every render cycle with the new state. Replace through `update()`. */\n onChange?: (state: GroupVirtualizerState<T>) => void;\n /** Called when scrolling settles. Replace through `update()`. */\n onScrollEnd?: (offset: number) => void;\n /** Called when the scrolling state changes. Replace through `update()`. */\n onScrollingChange?: (isScrolling: boolean) => void;\n overscan?: Overscan;\n /**\n * Debounce delay (ms) for scroll-end detection. Defaults to 150.\n * See `VirtualizerOptions.scrollEndDelay` for details.\n */\n scrollEndDelay?: number;\n sections: Array<GroupSection<T>>;\n}\n\nexport interface GroupVirtualizer<T> {\n readonly count: number;\n readonly disposalSignal: AbortSignal;\n readonly disposed: boolean;\n /** `true` while the user is actively scrolling; `false` once scroll has settled. */\n readonly isScrolling: boolean;\n readonly items: ReadonlyArray<GroupVirtualItem<T>>;\n readonly scrollOffset: number;\n readonly stickyItems: VirtualItem[];\n readonly totalSize: number;\n dispose: () => void;\n invalidate: () => void;\n measure: (index: number, size: number) => void;\n measureBatch: (entries: Array<{ index: number; size: number }>) => void;\n measureEl: (index: number, el: HTMLElement) => () => void;\n refresh: () => void;\n scrollToBottom: (options?: { behavior?: ScrollBehavior }) => void;\n scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;\n scrollToItem: (sectionIndex: number, itemIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToOffset: (offset: number, options?: { behavior?: ScrollBehavior }) => void;\n scrollToSection: (sectionIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToTop: (options?: { behavior?: ScrollBehavior }) => void;\n update: (sections: Array<GroupSection<T>>, opts?: GroupVirtualizerUpdateOptions<T>) => void;\n [Symbol.dispose]: () => void;\n}\n\n// ─── Flat entry map ───────────────────────────────────────────────────────────\n\ntype FlatHeader = { isHeader: true; itemIndex: -1; label: string; sectionIndex: number };\ntype FlatItem<T> = { isHeader: false; item: T; itemIndex: number; sectionIndex: number };\ntype FlatEntry<T> = FlatHeader | FlatItem<T>;\n\nfunction buildFlatEntries<T>(sections: Array<GroupSection<T>>): FlatEntry<T>[] {\n const flat: FlatEntry<T>[] = [];\n\n for (let s = 0; s < sections.length; s++) {\n const section = sections[s]!;\n\n flat.push({ isHeader: true, itemIndex: -1, label: section.label, sectionIndex: s });\n\n for (let i = 0; i < section.items.length; i++) {\n flat.push({ isHeader: false, item: section.items[i]!, itemIndex: i, sectionIndex: s });\n }\n }\n\n return flat;\n}\n\n// ─── Implementation ───────────────────────────────────────────────────────────\n\nexport function createGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: GroupVirtualizerOptions<T>,\n): GroupVirtualizer<T> {\n if (typeof options.estimateHeaderSize === 'number')\n requirePositiveNumber(options.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof options.estimateItemSize === 'number') requirePositiveNumber(options.estimateItemSize, 'estimateItemSize');\n\n if (options.overscan !== undefined) validateOverscan(options.overscan);\n\n if (options.scrollEndDelay !== undefined) requireNonNegativeNumber(options.scrollEndDelay, 'scrollEndDelay');\n\n let sections = options.sections;\n let flat = buildFlatEntries(sections);\n\n function buildEstimateHeader(\n estimateHeaderSize: GroupVirtualizerOptions<T>['estimateHeaderSize'],\n ): (index: number) => number {\n return typeof estimateHeaderSize === 'function'\n ? (index: number) => {\n const entry = flat[index]!;\n\n return (estimateHeaderSize as (section: GroupSection<T>, sectionIndex: number) => number)(\n sections[entry.sectionIndex]!,\n entry.sectionIndex,\n );\n }\n : resolveEstimateFn(\n typeof estimateHeaderSize === 'number' ? estimateHeaderSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n let estimateHeaderFn = buildEstimateHeader(options.estimateHeaderSize);\n let estimateItemUserFn: ((item: T, itemIndex: number, sectionIndex: number) => number) | null =\n typeof options.estimateItemSize === 'function' ? options.estimateItemSize : null;\n let estimateItemFixedFn: ((index: number) => number) | null = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof options.estimateItemSize === 'number' ? options.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n let userGetItemKey = options.getItemKey;\n\n function estimateFn(globalIndex: number): number {\n const entry = flat[globalIndex];\n\n if (!entry) return DEFAULT_ESTIMATE_SIZE;\n\n if (entry.isHeader) return estimateHeaderFn(globalIndex);\n\n if (estimateItemUserFn) return estimateItemUserFn(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return estimateItemFixedFn!(globalIndex);\n }\n\n function getItemKey(globalIndex: number): VirtualKey {\n const entry = flat[globalIndex];\n\n if (!entry) return globalIndex;\n\n if (entry.isHeader) return `__header_${entry.sectionIndex}`;\n\n if (userGetItemKey) return userGetItemKey(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return globalIndex;\n }\n\n let destroyed = false;\n let lastItems: Array<GroupVirtualItem<T>> = [];\n let onChange = options.onChange;\n let onScrollEnd = options.onScrollEnd;\n let onScrollingChange = options.onScrollingChange;\n\n function mapState(state: VirtualizerState): GroupVirtualizerState<T> {\n const items: Array<GroupVirtualItem<T>> = [];\n const headers: GroupVirtualHeader[] = [];\n let stickyHeader: GroupVirtualHeader | null = null;\n\n for (const vi of state.items) {\n const entry = flat[vi.index];\n\n if (!entry) continue;\n\n if (entry.isHeader) {\n headers.push({ ...vi, label: entry.label ?? '', sectionIndex: entry.sectionIndex });\n } else {\n items.push({ ...vi, data: entry.item, itemIndex: entry.itemIndex, sectionIndex: entry.sectionIndex });\n }\n }\n\n if (state.stickyItems.length > 0) {\n const svi = state.stickyItems[0]!;\n const entry = flat[svi.index];\n\n if (entry?.isHeader) {\n stickyHeader = { ...svi, label: entry.label ?? '', sectionIndex: entry.sectionIndex };\n }\n }\n\n lastItems = items;\n\n return { headers, items, stickyHeader, totalSize: state.totalSize };\n }\n\n const virtualizer = createVirtualizer(target, {\n count: flat.length,\n estimateSize: estimateFn,\n getItemKey,\n horizontal: options.horizontal,\n measurementCache: options.measurementCache,\n onChange: (state) => {\n const mapped = mapState(state);\n\n onChange?.(mapped);\n },\n onScrollEnd: (offset) => onScrollEnd?.(offset),\n onScrollingChange: (isScrolling) => onScrollingChange?.(isScrolling),\n overscan: options.overscan ?? DEFAULT_OVERSCAN,\n scrollEndDelay: options.scrollEndDelay,\n sticky: (i) => flat[i]?.isHeader ?? false,\n });\n\n const ac = new AbortController();\n\n function _dispose(): void {\n if (destroyed) return;\n\n destroyed = true;\n ac.abort();\n virtualizer.dispose();\n }\n\n // Build a flat-index lookup: [sectionIndex, itemIndex] → flat index.\n // Returns -1 when sectionIndex is out of range so callers can no-op safely.\n function flatIndexOf(sectionIndex: number, itemIndex?: number): number {\n if (sectionIndex < 0 || sectionIndex >= sections.length) return -1;\n\n let pos = 0;\n\n for (let s = 0; s < sections.length; s++) {\n if (s === sectionIndex) {\n if (itemIndex === undefined) return pos; // header\n\n return pos + 1 + itemIndex;\n }\n\n pos += 1 + sections[s]!.items.length;\n }\n\n return -1; // unreachable\n }\n\n return {\n get count() {\n return virtualizer.count;\n },\n get disposalSignal() {\n return ac.signal;\n },\n dispose: _dispose,\n get disposed() {\n return destroyed;\n },\n invalidate() {\n if (destroyed) return;\n\n virtualizer.invalidate();\n },\n get isScrolling() {\n return virtualizer.isScrolling;\n },\n get items() {\n return lastItems;\n },\n measure(index: number, size: number) {\n if (destroyed) return;\n\n virtualizer.measure(index, size);\n },\n measureBatch(entries: Array<{ index: number; size: number }>) {\n if (destroyed) return;\n\n virtualizer.measureBatch(entries);\n },\n measureEl(index: number, el: HTMLElement) {\n if (destroyed) return () => {};\n\n return virtualizer.measureEl(index, el);\n },\n refresh() {\n if (destroyed) return;\n\n virtualizer.refresh();\n },\n get scrollOffset() {\n return virtualizer.scrollOffset;\n },\n scrollToBottom(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToBottom(opts);\n },\n scrollToIndex(index: number, opts?: ScrollToIndexOptions) {\n if (destroyed) return;\n\n virtualizer.scrollToIndex(index, opts);\n },\n scrollToItem(sectionIndex, itemIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex, itemIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToOffset(offset: number, opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToOffset(offset, opts);\n },\n scrollToSection(sectionIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToTop(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToTop(opts);\n },\n get stickyItems() {\n return virtualizer.stickyItems;\n },\n [Symbol.dispose]: _dispose,\n get totalSize() {\n return virtualizer.totalSize;\n },\n /**\n * Replace all sections. Closures for estimateFn and getItemKey already\n * capture the live `flat`/`sections` references — only count is passed to\n * the underlying virtualizer to avoid discarding measured sizes on every\n * data refresh. `refresh()` rebuilds offsets while preserving the cache.\n */\n update(nextSections, opts?: GroupVirtualizerUpdateOptions<T>) {\n if (destroyed) return;\n\n if (opts) {\n if (typeof opts.estimateHeaderSize === 'number')\n requirePositiveNumber(opts.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof opts.estimateItemSize === 'number') requirePositiveNumber(opts.estimateItemSize, 'estimateItemSize');\n\n if (opts.overscan !== undefined) validateOverscan(opts.overscan);\n\n if (opts.scrollEndDelay !== undefined) requireNonNegativeNumber(opts.scrollEndDelay, 'scrollEndDelay');\n\n if (Object.hasOwn(opts, 'onChange')) onChange = opts.onChange;\n\n if (Object.hasOwn(opts, 'onScrollEnd')) onScrollEnd = opts.onScrollEnd;\n\n if (Object.hasOwn(opts, 'onScrollingChange')) onScrollingChange = opts.onScrollingChange;\n\n // Apply option overrides before rebuilding flat entries.\n if (opts.estimateHeaderSize !== undefined) {\n estimateHeaderFn = buildEstimateHeader(opts.estimateHeaderSize);\n }\n\n if (opts.estimateItemSize !== undefined) {\n estimateItemUserFn = typeof opts.estimateItemSize === 'function' ? opts.estimateItemSize : null;\n estimateItemFixedFn = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof opts.estimateItemSize === 'number' ? opts.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n if (opts.getItemKey !== undefined) userGetItemKey = opts.getItemKey;\n }\n\n sections = nextSections;\n\n const prevCount = flat.length;\n\n flat = buildFlatEntries(sections);\n\n const virtUpdateOpts: VirtualizerUpdateOptions = { count: flat.length };\n\n if (opts?.measurementCache !== undefined) virtUpdateOpts.measurementCache = opts.measurementCache;\n\n if (opts?.overscan !== undefined) virtUpdateOpts.overscan = opts.overscan;\n\n if (opts?.scrollEndDelay !== undefined) virtUpdateOpts.scrollEndDelay = opts.scrollEndDelay;\n\n if (\n flat.length !== prevCount ||\n opts?.measurementCache !== undefined ||\n opts?.overscan !== undefined ||\n opts?.scrollEndDelay !== undefined\n ) {\n virtualizer.update(virtUpdateOpts);\n } else {\n virtualizer.refresh();\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"grouped-virtualizer.js","names":[],"sources":["../src/grouped-virtualizer.ts"],"sourcesContent":["import { resolveEstimateFn } from './_utils';\nimport { requireNonNegativeNumber, requirePositiveNumber, validateOverscan } from './_validation';\nimport {\n createVirtualizer,\n DEFAULT_ESTIMATE_SIZE,\n DEFAULT_OVERSCAN,\n type MeasurementCache,\n type Overscan,\n type ScrollTarget,\n type ScrollToIndexOptions,\n type VirtualItem,\n type VirtualizerState,\n type VirtualizerUpdateOptions,\n type VirtualKey,\n} from './virtualizer';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface GroupSection<T> {\n items: T[];\n label: string;\n}\n\nexport interface GroupVirtualItem<T> extends VirtualItem {\n /** Item data. */\n data: T;\n /** Index within the section. */\n itemIndex: number;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualHeader extends VirtualItem {\n label: string;\n sectionIndex: number;\n}\n\nexport interface GroupVirtualizerState<T> {\n readonly headers: GroupVirtualHeader[];\n readonly items: Array<GroupVirtualItem<T>>;\n readonly stickyHeader: GroupVirtualHeader | null;\n readonly totalSize: number;\n}\n\n/**\n * Options accepted by `GroupVirtualizer.update()`. Overrides are applied\n * together with the new sections on the next render cycle.\n *\n * Intentionally excludes `horizontal` (axis cannot change at runtime) and\n * `initialOffset` (one-time bootstrap).\n */\nexport interface GroupVirtualizerUpdateOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n measurementCache?: MeasurementCache;\n onChange?: ((state: GroupVirtualizerState<T>) => void) | undefined;\n onScrollEnd?: ((offset: number) => void) | undefined;\n onScrollingChange?: ((isScrolling: boolean) => void) | undefined;\n overscan?: Overscan;\n scrollEndDelay?: number;\n}\n\nexport interface GroupVirtualizerOptions<T> {\n estimateHeaderSize?: number | ((section: GroupSection<T>, sectionIndex: number) => number);\n estimateItemSize?: number | ((item: T, itemIndex: number, sectionIndex: number) => number);\n getItemKey?: (item: T, itemIndex: number, sectionIndex: number) => VirtualKey;\n horizontal?: boolean;\n measurementCache?: MeasurementCache;\n /** Called after every render cycle with the new state. Replace through `update()`. */\n onChange?: (state: GroupVirtualizerState<T>) => void;\n /** Called when scrolling settles. Replace through `update()`. */\n onScrollEnd?: (offset: number) => void;\n /** Called when the scrolling state changes. Replace through `update()`. */\n onScrollingChange?: (isScrolling: boolean) => void;\n overscan?: Overscan;\n /**\n * Debounce delay (ms) for scroll-end detection. Defaults to 150.\n * See `VirtualizerOptions.scrollEndDelay` for details.\n */\n scrollEndDelay?: number;\n sections: Array<GroupSection<T>>;\n}\n\nexport interface GroupVirtualizer<T> {\n readonly count: number;\n readonly disposalSignal: AbortSignal;\n dispose: () => void;\n readonly disposed: boolean;\n invalidate: () => void;\n /** `true` while the user is actively scrolling; `false` once scroll has settled. */\n readonly isScrolling: boolean;\n readonly items: ReadonlyArray<GroupVirtualItem<T>>;\n measure: (index: number, size: number) => void;\n measureBatch: (entries: Array<{ index: number; size: number }>) => void;\n measureEl: (index: number, el: HTMLElement) => () => void;\n refresh: () => void;\n readonly scrollOffset: number;\n scrollToBottom: (options?: { behavior?: ScrollBehavior }) => void;\n scrollToIndex: (index: number, options?: ScrollToIndexOptions) => void;\n scrollToItem: (sectionIndex: number, itemIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToOffset: (offset: number, options?: { behavior?: ScrollBehavior }) => void;\n scrollToSection: (sectionIndex: number, options?: ScrollToIndexOptions) => void;\n scrollToTop: (options?: { behavior?: ScrollBehavior }) => void;\n readonly stickyItems: VirtualItem[];\n readonly totalSize: number;\n update: (sections: Array<GroupSection<T>>, opts?: GroupVirtualizerUpdateOptions<T>) => void;\n [Symbol.dispose]: () => void;\n}\n\n// ─── Flat entry map ───────────────────────────────────────────────────────────\n\ntype FlatHeader = { isHeader: true; itemIndex: -1; label: string; sectionIndex: number };\ntype FlatItem<T> = { isHeader: false; item: T; itemIndex: number; sectionIndex: number };\ntype FlatEntry<T> = FlatHeader | FlatItem<T>;\n\nfunction buildFlatEntries<T>(sections: Array<GroupSection<T>>): FlatEntry<T>[] {\n const flat: FlatEntry<T>[] = [];\n\n for (let s = 0; s < sections.length; s++) {\n const section = sections[s]!;\n\n flat.push({ isHeader: true, itemIndex: -1, label: section.label, sectionIndex: s });\n\n for (let i = 0; i < section.items.length; i++) {\n flat.push({ isHeader: false, item: section.items[i]!, itemIndex: i, sectionIndex: s });\n }\n }\n\n return flat;\n}\n\n// ─── Implementation ───────────────────────────────────────────────────────────\n\nexport function createGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: GroupVirtualizerOptions<T>,\n): GroupVirtualizer<T> {\n if (typeof options.estimateHeaderSize === 'number')\n requirePositiveNumber(options.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof options.estimateItemSize === 'number') requirePositiveNumber(options.estimateItemSize, 'estimateItemSize');\n\n if (options.overscan !== undefined) validateOverscan(options.overscan);\n\n if (options.scrollEndDelay !== undefined) requireNonNegativeNumber(options.scrollEndDelay, 'scrollEndDelay');\n\n let sections = options.sections;\n let flat = buildFlatEntries(sections);\n\n function buildEstimateHeader(\n estimateHeaderSize: GroupVirtualizerOptions<T>['estimateHeaderSize'],\n ): (index: number) => number {\n return typeof estimateHeaderSize === 'function'\n ? (index: number) => {\n const entry = flat[index]!;\n\n return (estimateHeaderSize as (section: GroupSection<T>, sectionIndex: number) => number)(\n sections[entry.sectionIndex]!,\n entry.sectionIndex,\n );\n }\n : resolveEstimateFn(\n typeof estimateHeaderSize === 'number' ? estimateHeaderSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n let estimateHeaderFn = buildEstimateHeader(options.estimateHeaderSize);\n let estimateItemUserFn: ((item: T, itemIndex: number, sectionIndex: number) => number) | null =\n typeof options.estimateItemSize === 'function' ? options.estimateItemSize : null;\n let estimateItemFixedFn: ((index: number) => number) | null = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof options.estimateItemSize === 'number' ? options.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n let userGetItemKey = options.getItemKey;\n\n function estimateFn(globalIndex: number): number {\n const entry = flat[globalIndex];\n\n if (!entry) return DEFAULT_ESTIMATE_SIZE;\n\n if (entry.isHeader) return estimateHeaderFn(globalIndex);\n\n if (estimateItemUserFn) return estimateItemUserFn(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return estimateItemFixedFn!(globalIndex);\n }\n\n function getItemKey(globalIndex: number): VirtualKey {\n const entry = flat[globalIndex];\n\n if (!entry) return globalIndex;\n\n if (entry.isHeader) return `__header_${entry.sectionIndex}`;\n\n if (userGetItemKey) return userGetItemKey(entry.item, entry.itemIndex, entry.sectionIndex);\n\n return globalIndex;\n }\n\n let destroyed = false;\n let lastItems: Array<GroupVirtualItem<T>> = [];\n let onChange = options.onChange;\n let onScrollEnd = options.onScrollEnd;\n let onScrollingChange = options.onScrollingChange;\n\n function mapState(state: VirtualizerState): GroupVirtualizerState<T> {\n const items: Array<GroupVirtualItem<T>> = [];\n const headers: GroupVirtualHeader[] = [];\n let stickyHeader: GroupVirtualHeader | null = null;\n\n for (const vi of state.items) {\n const entry = flat[vi.index];\n\n if (!entry) continue;\n\n if (entry.isHeader) {\n headers.push({ ...vi, label: entry.label ?? '', sectionIndex: entry.sectionIndex });\n } else {\n items.push({ ...vi, data: entry.item, itemIndex: entry.itemIndex, sectionIndex: entry.sectionIndex });\n }\n }\n\n if (state.stickyItems.length > 0) {\n const svi = state.stickyItems[0]!;\n const entry = flat[svi.index];\n\n if (entry?.isHeader) {\n stickyHeader = { ...svi, label: entry.label ?? '', sectionIndex: entry.sectionIndex };\n }\n }\n\n lastItems = items;\n\n return { headers, items, stickyHeader, totalSize: state.totalSize };\n }\n\n const virtualizer = createVirtualizer(target, {\n count: flat.length,\n estimateSize: estimateFn,\n getItemKey,\n horizontal: options.horizontal,\n measurementCache: options.measurementCache,\n onChange: (state) => {\n const mapped = mapState(state);\n\n onChange?.(mapped);\n },\n onScrollEnd: (offset) => onScrollEnd?.(offset),\n onScrollingChange: (isScrolling) => onScrollingChange?.(isScrolling),\n overscan: options.overscan ?? DEFAULT_OVERSCAN,\n scrollEndDelay: options.scrollEndDelay,\n sticky: (i) => flat[i]?.isHeader ?? false,\n });\n\n const ac = new AbortController();\n\n function _dispose(): void {\n if (destroyed) return;\n\n destroyed = true;\n ac.abort();\n virtualizer.dispose();\n }\n\n // Build a flat-index lookup: [sectionIndex, itemIndex] → flat index.\n // Returns -1 when sectionIndex is out of range so callers can no-op safely.\n function flatIndexOf(sectionIndex: number, itemIndex?: number): number {\n if (sectionIndex < 0 || sectionIndex >= sections.length) return -1;\n\n let pos = 0;\n\n for (let s = 0; s < sections.length; s++) {\n if (s === sectionIndex) {\n if (itemIndex === undefined) return pos; // header\n\n return pos + 1 + itemIndex;\n }\n\n pos += 1 + sections[s]!.items.length;\n }\n\n return -1; // unreachable\n }\n\n return {\n get count() {\n return virtualizer.count;\n },\n get disposalSignal() {\n return ac.signal;\n },\n dispose: _dispose,\n get disposed() {\n return destroyed;\n },\n invalidate() {\n if (destroyed) return;\n\n virtualizer.invalidate();\n },\n get isScrolling() {\n return virtualizer.isScrolling;\n },\n get items() {\n return lastItems;\n },\n measure(index: number, size: number) {\n if (destroyed) return;\n\n virtualizer.measure(index, size);\n },\n measureBatch(entries: Array<{ index: number; size: number }>) {\n if (destroyed) return;\n\n virtualizer.measureBatch(entries);\n },\n measureEl(index: number, el: HTMLElement) {\n if (destroyed) return () => {};\n\n return virtualizer.measureEl(index, el);\n },\n refresh() {\n if (destroyed) return;\n\n virtualizer.refresh();\n },\n get scrollOffset() {\n return virtualizer.scrollOffset;\n },\n scrollToBottom(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToBottom(opts);\n },\n scrollToIndex(index: number, opts?: ScrollToIndexOptions) {\n if (destroyed) return;\n\n virtualizer.scrollToIndex(index, opts);\n },\n scrollToItem(sectionIndex, itemIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex, itemIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToOffset(offset: number, opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToOffset(offset, opts);\n },\n scrollToSection(sectionIndex, opts = {}) {\n if (destroyed) return;\n\n const globalIndex = flatIndexOf(sectionIndex);\n\n if (globalIndex < 0) return;\n\n virtualizer.scrollToIndex(globalIndex, opts);\n },\n scrollToTop(opts?: { behavior?: ScrollBehavior }) {\n if (destroyed) return;\n\n virtualizer.scrollToTop(opts);\n },\n get stickyItems() {\n return virtualizer.stickyItems;\n },\n [Symbol.dispose]: _dispose,\n get totalSize() {\n return virtualizer.totalSize;\n },\n /**\n * Replace all sections. Closures for estimateFn and getItemKey already\n * capture the live `flat`/`sections` references — only count is passed to\n * the underlying virtualizer to avoid discarding measured sizes on every\n * data refresh. `refresh()` rebuilds offsets while preserving the cache.\n */\n update(nextSections, opts?: GroupVirtualizerUpdateOptions<T>) {\n if (destroyed) return;\n\n if (opts) {\n if (typeof opts.estimateHeaderSize === 'number')\n requirePositiveNumber(opts.estimateHeaderSize, 'estimateHeaderSize');\n\n if (typeof opts.estimateItemSize === 'number') requirePositiveNumber(opts.estimateItemSize, 'estimateItemSize');\n\n if (opts.overscan !== undefined) validateOverscan(opts.overscan);\n\n if (opts.scrollEndDelay !== undefined) requireNonNegativeNumber(opts.scrollEndDelay, 'scrollEndDelay');\n\n if (Object.hasOwn(opts, 'onChange')) onChange = opts.onChange;\n\n if (Object.hasOwn(opts, 'onScrollEnd')) onScrollEnd = opts.onScrollEnd;\n\n if (Object.hasOwn(opts, 'onScrollingChange')) onScrollingChange = opts.onScrollingChange;\n\n // Apply option overrides before rebuilding flat entries.\n if (opts.estimateHeaderSize !== undefined) {\n estimateHeaderFn = buildEstimateHeader(opts.estimateHeaderSize);\n }\n\n if (opts.estimateItemSize !== undefined) {\n estimateItemUserFn = typeof opts.estimateItemSize === 'function' ? opts.estimateItemSize : null;\n estimateItemFixedFn = estimateItemUserFn\n ? null\n : resolveEstimateFn(\n typeof opts.estimateItemSize === 'number' ? opts.estimateItemSize : undefined,\n DEFAULT_ESTIMATE_SIZE,\n );\n }\n\n if (opts.getItemKey !== undefined) userGetItemKey = opts.getItemKey;\n }\n\n sections = nextSections;\n\n const prevCount = flat.length;\n\n flat = buildFlatEntries(sections);\n\n const virtUpdateOpts: VirtualizerUpdateOptions = { count: flat.length };\n\n if (opts?.measurementCache !== undefined) virtUpdateOpts.measurementCache = opts.measurementCache;\n\n if (opts?.overscan !== undefined) virtUpdateOpts.overscan = opts.overscan;\n\n if (opts?.scrollEndDelay !== undefined) virtUpdateOpts.scrollEndDelay = opts.scrollEndDelay;\n\n if (\n flat.length !== prevCount ||\n opts?.measurementCache !== undefined ||\n opts?.overscan !== undefined ||\n opts?.scrollEndDelay !== undefined\n ) {\n virtualizer.update(virtUpdateOpts);\n } else {\n virtualizer.refresh();\n }\n },\n };\n}\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./errors.cjs"),t=require("./_utils.cjs"),n=require("./virtualizer.cjs"),r=require("./dom-virtual-list.cjs"),i=require("./grid-virtualizer.cjs"),a=require("./grouped-virtualizer.cjs"),o=require("./reactive.cjs");exports.DEFAULT_ESTIMATE_SIZE=t.DEFAULT_ESTIMATE_SIZE,exports.DEFAULT_OVERSCAN=t.DEFAULT_OVERSCAN,exports.ScrollConfigurationError=e.ScrollConfigurationError,exports.ScrollError=e.ScrollError,exports.ScrollRangeError=e.ScrollRangeError,exports.createDomVirtualList=r.createDomVirtualList,exports.createGridVirtualizer=i.createGridVirtualizer,exports.createGroupedVirtualizer=a.createGroupedVirtualizer,exports.createMeasurementCache=t.createMeasurementCache,exports.createReactiveGroupedVirtualizer=o.createReactiveGroupedVirtualizer,exports.createReactiveVirtualizer=o.createReactiveVirtualizer,exports.createVirtualScroller=r.createVirtualScroller,exports.createVirtualizer=n.createVirtualizer;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_utils.cjs"),t=require("./errors.cjs"),n=require("./virtualizer.cjs"),r=require("./dom-virtual-list.cjs"),i=require("./grid-virtualizer.cjs"),a=require("./grouped-virtualizer.cjs"),o=require("./reactive.cjs");exports.DEFAULT_ESTIMATE_SIZE=e.DEFAULT_ESTIMATE_SIZE,exports.DEFAULT_OVERSCAN=e.DEFAULT_OVERSCAN,exports.ScrollConfigurationError=t.ScrollConfigurationError,exports.ScrollError=t.ScrollError,exports.ScrollRangeError=t.ScrollRangeError,exports.createDomVirtualList=r.createDomVirtualList,exports.createGridVirtualizer=i.createGridVirtualizer,exports.createGroupedVirtualizer=a.createGroupedVirtualizer,exports.createMeasurementCache=e.createMeasurementCache,exports.createReactiveGroupedVirtualizer=o.createReactiveGroupedVirtualizer,exports.createReactiveVirtualizer=o.createReactiveVirtualizer,exports.createVirtualScroller=r.createVirtualScroller,exports.createVirtualizer=n.createVirtualizer;
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- export { ScrollConfigurationError, ScrollError, ScrollRangeError } from './errors';
2
- export { createDomVirtualList, createVirtualScroller } from './dom-virtual-list';
3
1
  export type { DomVirtualListController, DomVirtualListOptions, DomVirtualListRenderArgs, RecycleFn, StickToBottomOptions, VirtualRenderItem, VirtualScrollerOptions, } from './dom-virtual-list';
4
- export { createGridVirtualizer } from './grid-virtualizer';
2
+ export { createDomVirtualList, createVirtualScroller } from './dom-virtual-list';
3
+ export { ScrollConfigurationError, ScrollError, ScrollRangeError } from './errors';
5
4
  export type { GridRangeChangeEvent, GridVirtualizer, GridVirtualizerOptions, GridVirtualizerState, GridVirtualizerUpdateOptions, ScrollToCellOptions, } from './grid-virtualizer';
6
- export { createGroupedVirtualizer } from './grouped-virtualizer';
5
+ export { createGridVirtualizer } from './grid-virtualizer';
7
6
  export type { GroupSection, GroupVirtualHeader, GroupVirtualItem, GroupVirtualizer, GroupVirtualizerOptions, GroupVirtualizerState, GroupVirtualizerUpdateOptions, } from './grouped-virtualizer';
8
- export { createReactiveGroupedVirtualizer, createReactiveVirtualizer } from './reactive';
7
+ export { createGroupedVirtualizer } from './grouped-virtualizer';
9
8
  export type { ReactiveGroupVirtualizer, ReactiveVirtualizer, Signal } from './reactive';
10
- export { createMeasurementCache, createVirtualizer, DEFAULT_ESTIMATE_SIZE, DEFAULT_OVERSCAN } from './virtualizer';
9
+ export { createReactiveGroupedVirtualizer, createReactiveVirtualizer } from './reactive';
11
10
  export type { MeasurementCache, Overscan, ScrollTarget, ScrollToIndexOptions, VirtualItem, Virtualizer, VirtualizerOptions, VirtualizerState, VirtualizerUpdateOptions, VirtualKey, } from './virtualizer';
11
+ export { createMeasurementCache, createVirtualizer, DEFAULT_ESTIMATE_SIZE, DEFAULT_OVERSCAN } from './virtualizer';
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjF,YAAY,EACV,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,4BAA4B,EAC5B,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,gCAAgC,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACzF,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACnH,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,UAAU,GACX,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,wBAAwB,EACxB,qBAAqB,EACrB,wBAAwB,EACxB,SAAS,EACT,oBAAoB,EACpB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EAAE,wBAAwB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACnF,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,sBAAsB,EACtB,oBAAoB,EACpB,4BAA4B,EAC5B,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACjE,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,gCAAgC,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACzF,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{ScrollConfigurationError as e,ScrollError as t,ScrollRangeError as n}from"./errors.js";import{DEFAULT_ESTIMATE_SIZE as r,DEFAULT_OVERSCAN as i,createMeasurementCache as a}from"./_utils.js";import{createVirtualizer as o}from"./virtualizer.js";import{createDomVirtualList as s,createVirtualScroller as c}from"./dom-virtual-list.js";import{createGridVirtualizer as l}from"./grid-virtualizer.js";import{createGroupedVirtualizer as u}from"./grouped-virtualizer.js";import{createReactiveGroupedVirtualizer as d,createReactiveVirtualizer as f}from"./reactive.js";export{r as DEFAULT_ESTIMATE_SIZE,i as DEFAULT_OVERSCAN,e as ScrollConfigurationError,t as ScrollError,n as ScrollRangeError,s as createDomVirtualList,l as createGridVirtualizer,u as createGroupedVirtualizer,a as createMeasurementCache,d as createReactiveGroupedVirtualizer,f as createReactiveVirtualizer,c as createVirtualScroller,o as createVirtualizer};
1
+ import{DEFAULT_ESTIMATE_SIZE as e,DEFAULT_OVERSCAN as t,createMeasurementCache as n}from"./_utils.js";import{ScrollConfigurationError as r,ScrollError as i,ScrollRangeError as a}from"./errors.js";import{createVirtualizer as o}from"./virtualizer.js";import{createDomVirtualList as s,createVirtualScroller as c}from"./dom-virtual-list.js";import{createGridVirtualizer as l}from"./grid-virtualizer.js";import{createGroupedVirtualizer as u}from"./grouped-virtualizer.js";import{createReactiveGroupedVirtualizer as d,createReactiveVirtualizer as f}from"./reactive.js";export{e as DEFAULT_ESTIMATE_SIZE,t as DEFAULT_OVERSCAN,r as ScrollConfigurationError,i as ScrollError,a as ScrollRangeError,s as createDomVirtualList,l as createGridVirtualizer,u as createGroupedVirtualizer,n as createMeasurementCache,d as createReactiveGroupedVirtualizer,f as createReactiveVirtualizer,c as createVirtualScroller,o as createVirtualizer};
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.cjs","names":[],"sources":["../src/reactive.ts"],"sourcesContent":["/**\n * F1: Ripple integration layer.\n * Wraps `createVirtualizer` so the current state is exposed as a reactive\n * `Signal<VirtualizerState>` from `@vielzeug/ripple`.\n */\nimport { signal, type Signal } from '@vielzeug/ripple';\n\nimport {\n createGroupedVirtualizer,\n type GroupVirtualizer,\n type GroupVirtualizerOptions,\n type GroupVirtualizerState,\n} from './grouped-virtualizer';\nimport {\n createVirtualizer,\n type ScrollTarget,\n type Virtualizer,\n type VirtualizerOptions,\n type VirtualizerState,\n} from './virtualizer';\n\nexport type { Signal };\n\nexport interface ReactiveGroupVirtualizer<T> extends GroupVirtualizer<T> {\n /** Reactive signal carrying the current grouped virtualizer state. */\n readonly state: Signal<GroupVirtualizerState<T>>;\n}\n\nexport interface ReactiveVirtualizer extends Virtualizer {\n /** Reactive signal carrying the current virtualizer state. */\n readonly state: Signal<VirtualizerState>;\n}\n\nfunction withState<THandle extends object, TState>(\n handle: THandle,\n state: Signal<TState>,\n): THandle & { readonly state: Signal<TState> } {\n return Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(handle),\n state: { configurable: true, enumerable: true, value: state },\n },\n ) as THandle & { readonly state: Signal<TState> };\n}\n\n/**\n * Create a grouped virtualizer whose current state is exposed as a reactive signal.\n *\n * All `GroupVirtualizer` accessors remain live through copied property descriptors.\n *\n * @example\n * ```ts\n * const v = createReactiveGroupedVirtualizer(el, { sections, estimateItemSize: 48 });\n * effect(() => {\n * const { headers, items, stickyHeader, totalSize } = v.state.value;\n * render(headers, items, totalSize);\n * });\n * ```\n */\nexport function createReactiveGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: Omit<GroupVirtualizerOptions<T>, 'onChange'>,\n): ReactiveGroupVirtualizer<T> {\n const state = signal<GroupVirtualizerState<T>>({ headers: [], items: [], stickyHeader: null, totalSize: 0 });\n\n let userOnChange: ((state: GroupVirtualizerState<T>) => void) | undefined;\n\n function onChange(next: GroupVirtualizerState<T>): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createGroupedVirtualizer<T>(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(sections: Array<{ items: T[]; label: string }>, next?: Parameters<typeof v.update>[1]) {\n if (!next || !Object.hasOwn(next, 'onChange')) {\n v.update(sections, next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update(sections, { ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n\n/**\n * Create a virtualizer whose current state is exposed as a reactive signal.\n *\n * All `Virtualizer` accessors (count, items, totalSize, scrollOffset, stickyItems)\n * remain live through copied property descriptors, avoiding snapshots from object spread.\n *\n * @example\n * ```ts\n * const v = createReactiveVirtualizer(el, { count: 1000, estimateSize: 40 });\n * effect(() => {\n * const { items, totalSize } = v.state.value;\n * render(items, totalSize);\n * });\n * ```\n */\nexport function createReactiveVirtualizer(\n target: ScrollTarget,\n options: Omit<VirtualizerOptions, 'onChange'>,\n): ReactiveVirtualizer {\n const state = signal<VirtualizerState>({ items: [], stickyItems: [], totalSize: 0 });\n\n let userOnChange: ((state: VirtualizerState) => void) | undefined;\n\n function onChange(next: VirtualizerState): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createVirtualizer(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(next: Parameters<typeof v.update>[0]) {\n if (!Object.hasOwn(next, 'onChange')) {\n v.update(next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update({ ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n"],"mappings":"8GAiCA,SAAS,EACP,EACA,EAC8C,CAC9C,OAAO,OAAO,iBACZ,CAAC,EACD,CACE,GAAG,OAAO,0BAA0B,CAAM,EAC1C,MAAO,CAAE,aAAc,GAAM,WAAY,GAAM,MAAO,CAAM,CAC9D,CACF,CACF,CAgBA,SAAgB,EACd,EACA,EAC6B,CAC7B,IAAM,GAAA,EAAQ,EAAA,OAAA,CAAiC,CAAE,QAAS,CAAC,EAAG,MAAO,CAAC,EAAG,aAAc,KAAM,UAAW,CAAE,CAAC,EAEvG,EAEJ,SAAS,EAAS,EAAsC,CACtD,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAAA,yBAA4B,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EAChE,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAgD,EAAuC,CAC3F,GAAI,CAAC,GAAQ,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CAC7C,EAAE,OAAO,EAAU,CAAI,EAEvB,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,EAAU,CAAE,GAAG,EAAa,UAAS,CAAC,CACjD,CACF,CAAC,EAEM,CACT,CAiBA,SAAgB,EACd,EACA,EACqB,CACrB,IAAM,GAAA,EAAQ,EAAA,OAAA,CAAyB,CAAE,MAAO,CAAC,EAAG,YAAa,CAAC,EAAG,UAAW,CAAE,CAAC,EAE/E,EAEJ,SAAS,EAAS,EAA8B,CAC9C,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAAA,kBAAkB,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EACtD,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAsC,CAC1C,GAAI,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CACpC,EAAE,OAAO,CAAI,EAEb,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,CAAE,GAAG,EAAa,UAAS,CAAC,CACvC,CACF,CAAC,EAEM,CACT"}
1
+ {"version":3,"file":"reactive.cjs","names":[],"sources":["../src/reactive.ts"],"sourcesContent":["/**\n * F1: Ripple integration layer.\n * Wraps `createVirtualizer` so the current state is exposed as a reactive\n * `Signal<VirtualizerState>` from `@vielzeug/ripple`.\n */\nimport { type Signal, signal } from '@vielzeug/ripple';\n\nimport {\n createGroupedVirtualizer,\n type GroupVirtualizer,\n type GroupVirtualizerOptions,\n type GroupVirtualizerState,\n} from './grouped-virtualizer';\nimport {\n createVirtualizer,\n type ScrollTarget,\n type Virtualizer,\n type VirtualizerOptions,\n type VirtualizerState,\n} from './virtualizer';\n\nexport type { Signal };\n\nexport interface ReactiveGroupVirtualizer<T> extends GroupVirtualizer<T> {\n /** Reactive signal carrying the current grouped virtualizer state. */\n readonly state: Signal<GroupVirtualizerState<T>>;\n}\n\nexport interface ReactiveVirtualizer extends Virtualizer {\n /** Reactive signal carrying the current virtualizer state. */\n readonly state: Signal<VirtualizerState>;\n}\n\nfunction withState<THandle extends object, TState>(\n handle: THandle,\n state: Signal<TState>,\n): THandle & { readonly state: Signal<TState> } {\n return Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(handle),\n state: { configurable: true, enumerable: true, value: state },\n },\n ) as THandle & { readonly state: Signal<TState> };\n}\n\n/**\n * Create a grouped virtualizer whose current state is exposed as a reactive signal.\n *\n * All `GroupVirtualizer` accessors remain live through copied property descriptors.\n *\n * @example\n * ```ts\n * const v = createReactiveGroupedVirtualizer(el, { sections, estimateItemSize: 48 });\n * effect(() => {\n * const { headers, items, stickyHeader, totalSize } = v.state.value;\n * render(headers, items, totalSize);\n * });\n * ```\n */\nexport function createReactiveGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: Omit<GroupVirtualizerOptions<T>, 'onChange'>,\n): ReactiveGroupVirtualizer<T> {\n const state = signal<GroupVirtualizerState<T>>({ headers: [], items: [], stickyHeader: null, totalSize: 0 });\n\n let userOnChange: ((state: GroupVirtualizerState<T>) => void) | undefined;\n\n function onChange(next: GroupVirtualizerState<T>): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createGroupedVirtualizer<T>(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(sections: Array<{ items: T[]; label: string }>, next?: Parameters<typeof v.update>[1]) {\n if (!next || !Object.hasOwn(next, 'onChange')) {\n v.update(sections, next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update(sections, { ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n\n/**\n * Create a virtualizer whose current state is exposed as a reactive signal.\n *\n * All `Virtualizer` accessors (count, items, totalSize, scrollOffset, stickyItems)\n * remain live through copied property descriptors, avoiding snapshots from object spread.\n *\n * @example\n * ```ts\n * const v = createReactiveVirtualizer(el, { count: 1000, estimateSize: 40 });\n * effect(() => {\n * const { items, totalSize } = v.state.value;\n * render(items, totalSize);\n * });\n * ```\n */\nexport function createReactiveVirtualizer(\n target: ScrollTarget,\n options: Omit<VirtualizerOptions, 'onChange'>,\n): ReactiveVirtualizer {\n const state = signal<VirtualizerState>({ items: [], stickyItems: [], totalSize: 0 });\n\n let userOnChange: ((state: VirtualizerState) => void) | undefined;\n\n function onChange(next: VirtualizerState): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createVirtualizer(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(next: Parameters<typeof v.update>[0]) {\n if (!Object.hasOwn(next, 'onChange')) {\n v.update(next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update({ ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n"],"mappings":"8GAiCA,SAAS,EACP,EACA,EAC8C,CAC9C,OAAO,OAAO,iBACZ,CAAC,EACD,CACE,GAAG,OAAO,0BAA0B,CAAM,EAC1C,MAAO,CAAE,aAAc,GAAM,WAAY,GAAM,MAAO,CAAM,CAC9D,CACF,CACF,CAgBA,SAAgB,EACd,EACA,EAC6B,CAC7B,IAAM,GAAA,EAAQ,EAAA,OAAA,CAAiC,CAAE,QAAS,CAAC,EAAG,MAAO,CAAC,EAAG,aAAc,KAAM,UAAW,CAAE,CAAC,EAEvG,EAEJ,SAAS,EAAS,EAAsC,CACtD,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAAA,yBAA4B,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EAChE,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAgD,EAAuC,CAC3F,GAAI,CAAC,GAAQ,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CAC7C,EAAE,OAAO,EAAU,CAAI,EAEvB,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,EAAU,CAAE,GAAG,EAAa,UAAS,CAAC,CACjD,CACF,CAAC,EAEM,CACT,CAiBA,SAAgB,EACd,EACA,EACqB,CACrB,IAAM,GAAA,EAAQ,EAAA,OAAA,CAAyB,CAAE,MAAO,CAAC,EAAG,YAAa,CAAC,EAAG,UAAW,CAAE,CAAC,EAE/E,EAEJ,SAAS,EAAS,EAA8B,CAC9C,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAAA,kBAAkB,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EACtD,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAsC,CAC1C,GAAI,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CACpC,EAAE,OAAO,CAAI,EAEb,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,CAAE,GAAG,EAAa,UAAS,CAAC,CACvC,CACF,CAAC,EAEM,CACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB,MAAM,WAAW,wBAAwB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IACtE,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC;CAC1C;AAeD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gCAAgC,CAAC,CAAC,EAChD,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GACpD,wBAAwB,CAAC,CAAC,CAAC,CAgC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAC5C,mBAAmB,CAgCrB"}
1
+ {"version":3,"file":"reactive.d.ts","sourceRoot":"","sources":["../src/reactive.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAEvB,YAAY,EAAE,MAAM,EAAE,CAAC;AAEvB,MAAM,WAAW,wBAAwB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;IACtE,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC;CAClD;AAED,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC;CAC1C;AAeD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gCAAgC,CAAC,CAAC,EAChD,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GACpD,wBAAwB,CAAC,CAAC,CAAC,CAgC7B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,GAC5C,mBAAmB,CAgCrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"reactive.js","names":[],"sources":["../src/reactive.ts"],"sourcesContent":["/**\n * F1: Ripple integration layer.\n * Wraps `createVirtualizer` so the current state is exposed as a reactive\n * `Signal<VirtualizerState>` from `@vielzeug/ripple`.\n */\nimport { signal, type Signal } from '@vielzeug/ripple';\n\nimport {\n createGroupedVirtualizer,\n type GroupVirtualizer,\n type GroupVirtualizerOptions,\n type GroupVirtualizerState,\n} from './grouped-virtualizer';\nimport {\n createVirtualizer,\n type ScrollTarget,\n type Virtualizer,\n type VirtualizerOptions,\n type VirtualizerState,\n} from './virtualizer';\n\nexport type { Signal };\n\nexport interface ReactiveGroupVirtualizer<T> extends GroupVirtualizer<T> {\n /** Reactive signal carrying the current grouped virtualizer state. */\n readonly state: Signal<GroupVirtualizerState<T>>;\n}\n\nexport interface ReactiveVirtualizer extends Virtualizer {\n /** Reactive signal carrying the current virtualizer state. */\n readonly state: Signal<VirtualizerState>;\n}\n\nfunction withState<THandle extends object, TState>(\n handle: THandle,\n state: Signal<TState>,\n): THandle & { readonly state: Signal<TState> } {\n return Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(handle),\n state: { configurable: true, enumerable: true, value: state },\n },\n ) as THandle & { readonly state: Signal<TState> };\n}\n\n/**\n * Create a grouped virtualizer whose current state is exposed as a reactive signal.\n *\n * All `GroupVirtualizer` accessors remain live through copied property descriptors.\n *\n * @example\n * ```ts\n * const v = createReactiveGroupedVirtualizer(el, { sections, estimateItemSize: 48 });\n * effect(() => {\n * const { headers, items, stickyHeader, totalSize } = v.state.value;\n * render(headers, items, totalSize);\n * });\n * ```\n */\nexport function createReactiveGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: Omit<GroupVirtualizerOptions<T>, 'onChange'>,\n): ReactiveGroupVirtualizer<T> {\n const state = signal<GroupVirtualizerState<T>>({ headers: [], items: [], stickyHeader: null, totalSize: 0 });\n\n let userOnChange: ((state: GroupVirtualizerState<T>) => void) | undefined;\n\n function onChange(next: GroupVirtualizerState<T>): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createGroupedVirtualizer<T>(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(sections: Array<{ items: T[]; label: string }>, next?: Parameters<typeof v.update>[1]) {\n if (!next || !Object.hasOwn(next, 'onChange')) {\n v.update(sections, next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update(sections, { ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n\n/**\n * Create a virtualizer whose current state is exposed as a reactive signal.\n *\n * All `Virtualizer` accessors (count, items, totalSize, scrollOffset, stickyItems)\n * remain live through copied property descriptors, avoiding snapshots from object spread.\n *\n * @example\n * ```ts\n * const v = createReactiveVirtualizer(el, { count: 1000, estimateSize: 40 });\n * effect(() => {\n * const { items, totalSize } = v.state.value;\n * render(items, totalSize);\n * });\n * ```\n */\nexport function createReactiveVirtualizer(\n target: ScrollTarget,\n options: Omit<VirtualizerOptions, 'onChange'>,\n): ReactiveVirtualizer {\n const state = signal<VirtualizerState>({ items: [], stickyItems: [], totalSize: 0 });\n\n let userOnChange: ((state: VirtualizerState) => void) | undefined;\n\n function onChange(next: VirtualizerState): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createVirtualizer(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(next: Parameters<typeof v.update>[0]) {\n if (!Object.hasOwn(next, 'onChange')) {\n v.update(next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update({ ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n"],"mappings":"mKAiCA,SAAS,EACP,EACA,EAC8C,CAC9C,OAAO,OAAO,iBACZ,CAAC,EACD,CACE,GAAG,OAAO,0BAA0B,CAAM,EAC1C,MAAO,CAAE,aAAc,GAAM,WAAY,GAAM,MAAO,CAAM,CAC9D,CACF,CACF,CAgBA,SAAgB,EACd,EACA,EAC6B,CAC7B,IAAM,EAAQ,EAAiC,CAAE,QAAS,CAAC,EAAG,MAAO,CAAC,EAAG,aAAc,KAAM,UAAW,CAAE,CAAC,EAEvG,EAEJ,SAAS,EAAS,EAAsC,CACtD,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAA4B,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EAChE,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAgD,EAAuC,CAC3F,GAAI,CAAC,GAAQ,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CAC7C,EAAE,OAAO,EAAU,CAAI,EAEvB,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,EAAU,CAAE,GAAG,EAAa,UAAS,CAAC,CACjD,CACF,CAAC,EAEM,CACT,CAiBA,SAAgB,EACd,EACA,EACqB,CACrB,IAAM,EAAQ,EAAyB,CAAE,MAAO,CAAC,EAAG,YAAa,CAAC,EAAG,UAAW,CAAE,CAAC,EAE/E,EAEJ,SAAS,EAAS,EAA8B,CAC9C,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAAkB,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EACtD,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAsC,CAC1C,GAAI,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CACpC,EAAE,OAAO,CAAI,EAEb,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,CAAE,GAAG,EAAa,UAAS,CAAC,CACvC,CACF,CAAC,EAEM,CACT"}
1
+ {"version":3,"file":"reactive.js","names":[],"sources":["../src/reactive.ts"],"sourcesContent":["/**\n * F1: Ripple integration layer.\n * Wraps `createVirtualizer` so the current state is exposed as a reactive\n * `Signal<VirtualizerState>` from `@vielzeug/ripple`.\n */\nimport { type Signal, signal } from '@vielzeug/ripple';\n\nimport {\n createGroupedVirtualizer,\n type GroupVirtualizer,\n type GroupVirtualizerOptions,\n type GroupVirtualizerState,\n} from './grouped-virtualizer';\nimport {\n createVirtualizer,\n type ScrollTarget,\n type Virtualizer,\n type VirtualizerOptions,\n type VirtualizerState,\n} from './virtualizer';\n\nexport type { Signal };\n\nexport interface ReactiveGroupVirtualizer<T> extends GroupVirtualizer<T> {\n /** Reactive signal carrying the current grouped virtualizer state. */\n readonly state: Signal<GroupVirtualizerState<T>>;\n}\n\nexport interface ReactiveVirtualizer extends Virtualizer {\n /** Reactive signal carrying the current virtualizer state. */\n readonly state: Signal<VirtualizerState>;\n}\n\nfunction withState<THandle extends object, TState>(\n handle: THandle,\n state: Signal<TState>,\n): THandle & { readonly state: Signal<TState> } {\n return Object.defineProperties(\n {},\n {\n ...Object.getOwnPropertyDescriptors(handle),\n state: { configurable: true, enumerable: true, value: state },\n },\n ) as THandle & { readonly state: Signal<TState> };\n}\n\n/**\n * Create a grouped virtualizer whose current state is exposed as a reactive signal.\n *\n * All `GroupVirtualizer` accessors remain live through copied property descriptors.\n *\n * @example\n * ```ts\n * const v = createReactiveGroupedVirtualizer(el, { sections, estimateItemSize: 48 });\n * effect(() => {\n * const { headers, items, stickyHeader, totalSize } = v.state.value;\n * render(headers, items, totalSize);\n * });\n * ```\n */\nexport function createReactiveGroupedVirtualizer<T>(\n target: ScrollTarget,\n options: Omit<GroupVirtualizerOptions<T>, 'onChange'>,\n): ReactiveGroupVirtualizer<T> {\n const state = signal<GroupVirtualizerState<T>>({ headers: [], items: [], stickyHeader: null, totalSize: 0 });\n\n let userOnChange: ((state: GroupVirtualizerState<T>) => void) | undefined;\n\n function onChange(next: GroupVirtualizerState<T>): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createGroupedVirtualizer<T>(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(sections: Array<{ items: T[]; label: string }>, next?: Parameters<typeof v.update>[1]) {\n if (!next || !Object.hasOwn(next, 'onChange')) {\n v.update(sections, next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update(sections, { ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n\n/**\n * Create a virtualizer whose current state is exposed as a reactive signal.\n *\n * All `Virtualizer` accessors (count, items, totalSize, scrollOffset, stickyItems)\n * remain live through copied property descriptors, avoiding snapshots from object spread.\n *\n * @example\n * ```ts\n * const v = createReactiveVirtualizer(el, { count: 1000, estimateSize: 40 });\n * effect(() => {\n * const { items, totalSize } = v.state.value;\n * render(items, totalSize);\n * });\n * ```\n */\nexport function createReactiveVirtualizer(\n target: ScrollTarget,\n options: Omit<VirtualizerOptions, 'onChange'>,\n): ReactiveVirtualizer {\n const state = signal<VirtualizerState>({ items: [], stickyItems: [], totalSize: 0 });\n\n let userOnChange: ((state: VirtualizerState) => void) | undefined;\n\n function onChange(next: VirtualizerState): void {\n state.value = next;\n userOnChange?.(next);\n }\n\n const v = createVirtualizer(target, { ...options, onChange });\n const reactive = withState(v, state);\n\n Object.defineProperty(reactive, 'update', {\n configurable: true,\n enumerable: true,\n value(next: Parameters<typeof v.update>[0]) {\n if (!Object.hasOwn(next, 'onChange')) {\n v.update(next);\n\n return;\n }\n\n userOnChange = next.onChange;\n\n const { onChange: _, ...nextOptions } = next;\n\n v.update({ ...nextOptions, onChange });\n },\n });\n\n return reactive;\n}\n"],"mappings":"mKAiCA,SAAS,EACP,EACA,EAC8C,CAC9C,OAAO,OAAO,iBACZ,CAAC,EACD,CACE,GAAG,OAAO,0BAA0B,CAAM,EAC1C,MAAO,CAAE,aAAc,GAAM,WAAY,GAAM,MAAO,CAAM,CAC9D,CACF,CACF,CAgBA,SAAgB,EACd,EACA,EAC6B,CAC7B,IAAM,EAAQ,EAAiC,CAAE,QAAS,CAAC,EAAG,MAAO,CAAC,EAAG,aAAc,KAAM,UAAW,CAAE,CAAC,EAEvG,EAEJ,SAAS,EAAS,EAAsC,CACtD,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAA4B,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EAChE,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAgD,EAAuC,CAC3F,GAAI,CAAC,GAAQ,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CAC7C,EAAE,OAAO,EAAU,CAAI,EAEvB,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,EAAU,CAAE,GAAG,EAAa,UAAS,CAAC,CACjD,CACF,CAAC,EAEM,CACT,CAiBA,SAAgB,EACd,EACA,EACqB,CACrB,IAAM,EAAQ,EAAyB,CAAE,MAAO,CAAC,EAAG,YAAa,CAAC,EAAG,UAAW,CAAE,CAAC,EAE/E,EAEJ,SAAS,EAAS,EAA8B,CAC9C,EAAM,MAAQ,EACd,IAAe,CAAI,CACrB,CAEA,IAAM,EAAI,EAAkB,EAAQ,CAAE,GAAG,EAAS,UAAS,CAAC,EACtD,EAAW,EAAU,EAAG,CAAK,EAoBnC,OAlBA,OAAO,eAAe,EAAU,SAAU,CACxC,aAAc,GACd,WAAY,GACZ,MAAM,EAAsC,CAC1C,GAAI,CAAC,OAAO,OAAO,EAAM,UAAU,EAAG,CACpC,EAAE,OAAO,CAAI,EAEb,MACF,CAEA,EAAe,EAAK,SAEpB,GAAM,CAAE,SAAU,EAAG,GAAG,GAAgB,EAExC,EAAE,OAAO,CAAE,GAAG,EAAa,UAAS,CAAC,CACvC,CACF,CAAC,EAEM,CACT"}
package/dist/scroll.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/ripple");var t=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},n=class extends t{},r=class extends t{};function i(){return new Map}var a=36,o=3;function s(e,t=0){return Number.isFinite(e)?Math.max(0,Math.floor(e)):t}function c(e,t){return!Number.isFinite(e)||e<=0||e>1e7?t:e}function l(e){return typeof Window<`u`&&e instanceof Window||typeof e.innerHeight==`number`&&typeof e.document==`object`}function u(e,t){if(typeof e==`number`){let n=s(e,t);return{end:n,start:n}}return{end:s(e?.end??t),start:s(e?.start??t)}}function d(e,t,n){let r=new ResizeObserver(e=>{for(let t of e)n(t)});return r.observe(t),e.addEventListener(`abort`,()=>r.disconnect(),{once:!0}),()=>r.disconnect()}function f(e,t){if(typeof e==`function`)return n=>{try{return c(e(n),t)}catch(e){return`${n}${e}`,t}};let n=typeof e==`number`?c(e,t):t;return()=>n}function p(e,t){if(!Number.isFinite(e)||!Number.isInteger(e)||e<0)throw new n(`${t} must be a finite non-negative integer.`);return e}function m(e,t){if(!Number.isFinite(e)||e<0)throw new n(`${t} must be a finite non-negative number.`);return e}function h(e,t){if(!Number.isFinite(e)||e<=0||e>1e7)throw new n(`${t} must be a finite positive number no greater than 10000000.`);return e}function g(e,t=`overscan`){if(typeof e==`number`){p(e,t);return}if(typeof e!=`object`||!e||Array.isArray(e))throw new n(`${t} must be a finite non-negative integer or an overscan object.`);e.start!==void 0&&p(e.start,`${t}.start`),e.end!==void 0&&p(e.end,`${t}.end`)}function _(e,t,n){if(l(e))return e.addEventListener(`scroll`,t,{passive:!0}),e.addEventListener(`resize`,n,{passive:!0}),{detach(){e.removeEventListener(`scroll`,t),e.removeEventListener(`resize`,n)},scrollTo:(t,n,r)=>e.scrollTo({behavior:r,left:t,top:n}),x:{readOffset:()=>e.scrollX,readViewportSize:()=>e.innerWidth,writeOffset:(t,n)=>e.scrollTo({behavior:n,left:t})},y:{readOffset:()=>e.scrollY,readViewportSize:()=>e.innerHeight,writeOffset:(t,n)=>e.scrollTo({behavior:n,top:t})}};let r=new ResizeObserver(n);return e.addEventListener(`scroll`,t,{passive:!0}),r.observe(e),{detach(){e.removeEventListener(`scroll`,t),r.disconnect()},scrollTo:(t,n,r)=>e.scrollTo({behavior:r,left:t,top:n}),x:{readOffset:()=>e.scrollLeft,readViewportSize:()=>e.clientWidth,writeOffset:(t,n)=>e.scrollTo({behavior:n,left:t})},y:{readOffset:()=>e.scrollTop,readViewportSize:()=>e.clientHeight,writeOffset:(t,n)=>e.scrollTo({behavior:n,top:t})}}}function v(e,t,n){let r=e,i=n,a=t,o=[],s=0,c=-1,l=-1,u=-1,d=!1,f=1/0;function p(e){return o[e]??0}function m(e){return p(e)+a(e)}function h(e=!1){e&&(c=-1,l=-1,u=-1);let t=[0],n=0;for(let e=0;e<r;e++)n+=a(e)+(e<r-1?i:0),t.push(n);o=t,s=n}function g(e){if(!Number.isFinite(e)||e>=r)return;c=-1,l=-1,u=-1;let t=o[e]??0;for(let n=e;n<r;n++)o[n]=t,t+=a(n)+(n<r-1?i:0);o[r]=t,s=t}function _(e){let t=0,n=r-1;for(;t<n;){let r=t+n>>1;m(r)<=e?t=r+1:n=r}return t}function v(e,t){let n=t,i=r-1;for(;n<i;){let t=n+i+1>>1;p(t)<e?n=t:i=t-1}return n}function y(e,t,n,i){let a=_(e),o=v(t,a);return{renderEnd:Math.min(r-1,o+i),renderStart:Math.max(0,a-n)}}function b(e,t){return e===c&&t===l&&s===u}function x(e,t){c=e,l=t,u=s}function S(){c=-1,l=-1,u=-1}function C(e){d||(d=!0,queueMicrotask(()=>{d=!1;let t=f;f=1/0,g(t),e()}))}function w(e){e<f&&(f=e)}function T(e){let t=p(e),n=a(e);return{end:t+n,index:e,size:n,start:t}}return{commitDedup:x,computeRange:y,consumeMinChangedIndex(){let e=f;return f=1/0,e},get count(){return r},endAt:m,findFirst:_,findLast:v,get gap(){return i},isDedupSame:b,itemAt:T,markChanged:w,get minChangedIndex(){return f},get pendingBuild(){return d},get prevEnd(){return l},get prevStart(){return c},get prevTotalSize(){return u},rebuild:h,rebuildFrom:g,resetDedup:S,scheduleBuild:C,setCount(e){r=e},setGap(e){i=e},sizeAt(e){return a(e)},startAt:p,get totalSize(){return s}}}function y(e,t){typeof t.estimateSize==`number`&&h(t.estimateSize,`estimateSize`),t.gap!==void 0&&p(t.gap,`gap`),t.initialOffset!==void 0&&m(t.initialOffset,`initialOffset`),t.overscan!==void 0&&g(t.overscan),t.scrollEndDelay!==void 0&&m(t.scrollEndDelay,`scrollEndDelay`);let n=!!t.horizontal,r=e=>e,i=p(t.count,`count`),a=f(t.estimateSize,36),o=s(t.gap??0),l=t.getItemKey??r,y=u(t.overscan,3),b=t.sticky??null,x=t.onChange,S=t.onScrollEnd,C=t.onScrollingChange,w=t.scrollEndDelay??150,T=!1,E=null,D=`onscrollend`in e;function O(){T&&(T=!1,C?.(!1),S?.(I))}function k(){T||(T=!0,C?.(!0)),D||(E!==null&&clearTimeout(E),E=setTimeout(O,w))}let A=t.measurementCache??new Map,j=[],M=[],N=v(i,e=>A.get(l(e))??a(e),o),P=-1,F=0,I=0,L=0,R=-1,z=!1;function B(e){let t=Number.isFinite(e)?e:0,n=Math.max(0,N.totalSize-L);return Math.min(n,Math.max(0,t))}function V(){if(!b||i===0||I<=0)return[];let e=-1,t=0,n=i-1;for(;t<=n;){let r=t+n>>1;N.startAt(r)<I?(e=r,t=r+1):n=r-1}if(e<0)return[];let r=-1;for(let t=e;t>=0;t--)if(b(t)){r=t;break}if(r===-1)return[];let a=N.sizeAt(r),o=1/0;for(let e=r+1;e<i;e++)if(b(e)){o=N.startAt(e);break}let s=Math.min(I,o-a);return[{end:s+a,index:r,size:a,start:s}]}function H(){if(z)return;if(i===0||L<=0){(N.prevStart!==-1||N.prevTotalSize!==N.totalSize)&&(N.commitDedup(-1,-1),j=[],M=[],x&&x({items:j,stickyItems:M,totalSize:N.totalSize}));return}let{renderEnd:e,renderStart:t}=N.computeRange(I,I+L,y.start,y.end),n=b!==null&&I!==R;if(N.isDedupSame(t,e)&&!n)return;N.commitDedup(t,e),R=I;let r=[];for(let n=t;n<=e;n++)r.push(N.itemAt(n));j=r,M=b?V():[],x&&x({items:j,stickyItems:M,totalSize:N.totalSize})}function ee(e,t){if(!Number.isFinite(e))return!1;let n=Math.floor(e);if(n<0||n>=i)return!1;let r=c(t,-1);if(r<=0)return!1;let a=l(n);return A.get(a)!==r&&(A.set(a,r),N.markChanged(n),!0)}function U(){if(I<=0||i===0){P=-1;return}P=N.findFirst(I),F=I-N.startAt(P)}function W(){if(P<0)return;let e=N.startAt(P)+F-I;if(P=-1,Math.abs(e)>=1){let t=B(I+e);$.writeOffset(t,`auto`),I=t}}function G(e){if(z)return;let t=!1;for(let{index:n,size:r}of e)ee(n,r)&&(t=!0);t&&(N.pendingBuild||U(),N.scheduleBuild(()=>{W(),H()}))}function K(e,t){G([{index:e,size:t}])}function te(e,t){return z?()=>{}:d(Z.signal,t,t=>{K(e,n?t.contentRect.width:t.contentRect.height)})}function ne(e){e.count!==void 0&&p(e.count,`count`),typeof e.estimateSize==`number`&&h(e.estimateSize,`estimateSize`),e.gap!==void 0&&p(e.gap,`gap`),e.overscan!==void 0&&g(e.overscan),e.scrollEndDelay!==void 0&&m(e.scrollEndDelay,`scrollEndDelay`);let t=!1,n=!1;if(Object.hasOwn(e,`onChange`)&&(x=e.onChange),Object.hasOwn(e,`onScrollEnd`)&&(S=e.onScrollEnd),Object.hasOwn(e,`onScrollingChange`)&&(C=e.onScrollingChange),e.scrollEndDelay!==void 0&&(w=e.scrollEndDelay),e.count!==void 0){let n=e.count;n!==i&&(i=n,N.setCount(i),t=!0)}if(Object.hasOwn(e,`estimateSize`)&&(a=f(e.estimateSize,36),A.clear(),t=!0),e.gap!==void 0){let n=e.gap;n!==o&&(o=n,N.setGap(o),t=!0)}if(Object.hasOwn(e,`getItemKey`)){let n=e.getItemKey??r;n!==l&&(l=n,A.clear(),t=!0)}if(Object.hasOwn(e,`measurementCache`)&&e.measurementCache!==void 0&&(A=e.measurementCache,t=!0),e.overscan!==void 0){let t=u(e.overscan,3);(t.start!==y.start||t.end!==y.end)&&(y=t,n=!0)}if(Object.hasOwn(e,`sticky`)){let t=e.sticky??null;t!==b&&(b=t,N.resetDedup()),n=!0}t&&(U(),N.rebuild(!0),W()),(n||t)&&H()}function re(){z||(A.clear(),N.rebuild(!0),H())}function ie(){z||(N.rebuild(!0),H())}function q(e){if(z)return;let t=s(e);if(t===0)return;i+=t,N.setCount(i),N.rebuild(!0);let n=N.startAt(t),r=B(I+n);$.writeOffset(r,`auto`),I=r,H()}function J(e){z||ne(e)}function ae(t,n={}){if(z||i<=0)return;let r=Math.max(0,Math.min(Number.isFinite(t)?Math.floor(t):0,i-1)),a=n.align??`auto`,o=n.behavior??`auto`,s=N.startAt(r),c=N.sizeAt(r),l=s+c,u;if(a===`start`)u=s;else if(a===`end`)u=l-L;else if(a===`center`)u=s-(L-c)/2;else{let e=I,t=e+L;if(s>=e&&l<=t){n.onComplete&&queueMicrotask(n.onComplete);return}u=s<e?s:l-L}$.writeOffset(B(u),o),n.onComplete&&(o===`smooth`&&`onscrollend`in e?e.addEventListener(`scrollend`,n.onComplete,{once:!0}):queueMicrotask(n.onComplete))}function Y(e,t={}){z||$.writeOffset(B(e),t.behavior??`auto`)}function X(e={}){Y(0,e)}function oe(e={}){Y(Math.max(0,N.totalSize-L),e)}function se(e=0){return N.totalSize-(I+L)<=e}let Z=new AbortController;function ce(){z||(z=!0,Z.abort(),E!==null&&(clearTimeout(E),E=null),D&&e.removeEventListener(`scrollend`,O),Q.detach())}function le(){I=B($.readOffset()),k(),H()}function ue(){L=$.readViewportSize(),H()}let Q=_(e,le,ue),$=n?Q.x:Q.y;return D&&e.addEventListener(`scrollend`,O,{passive:!0}),N.rebuild(!0),t.initialOffset!==void 0&&$.writeOffset(B(t.initialOffset),`auto`),I=B($.readOffset()),L=$.readViewportSize(),H(),{get count(){return i},get disposalSignal(){return Z.signal},dispose:ce,get disposed(){return z},invalidate:re,isAtEnd:se,get isScrolling(){return T},get items(){return j},measure:K,measureBatch:G,measureEl:te,prepend:q,refresh:ie,get scrollOffset(){return I},scrollToBottom:oe,scrollToIndex:ae,scrollToOffset:Y,scrollToTop:X,get stickyItems(){return M},[Symbol.dispose]:ce,get totalSize(){return N.totalSize},update:J}}function b(){let e=new Map,t=new Map,n=[],r=!1;return{acquire(i,a){if(!r)return a();let o=e.get(i);if(o)return t.set(i,o),o;let s=n.pop()??a();return t.set(i,s),s},beginCycle(){t=new Map,r=!0},clear(){for(let t of e.values())t.remove();e.clear(),t.clear(),n.length=0,r=!1},endCycle(){if(r){r=!1;for(let[r,i]of e)t.has(r)||(i.remove(),n.push(i));e=t}}}}function x(e){if(typeof e.estimateSize==`number`&&h(e.estimateSize,`estimateSize`),e.gap!==void 0&&p(e.gap,`gap`),e.overscan!==void 0&&g(e.overscan),e.stickToBottom!==void 0&&typeof e.stickToBottom!=`boolean`){if(e.stickToBottom===null||Array.isArray(e.stickToBottom))throw new n(`stickToBottom must be a boolean or options object.`);e.stickToBottom.threshold!==void 0&&m(e.stickToBottom.threshold,`stickToBottom.threshold`)}let t=[],i=!1,a=new AbortController,o=e.listElement,s=b(),c=null;function l(n){let r=t[n];return r!==void 0&&e.getItemKey?e.getItemKey(n,r):n}function u(n){if(e.estimateSize===void 0)return 36;if(typeof e.estimateSize==`number`)return e.estimateSize;let r=t[n];return r===void 0?36:e.estimateSize(n,r)}function d(t){e.horizontal?(o.style.height=``,o.style.width=`${t}px`):(o.style.height=`${t}px`,o.style.width=``)}function f(e){let n=t[e.index];if(n===void 0)throw new r(`toRenderItem: index ${e.index} is out of range (currentItems.length=${t.length})`);return{...e,data:n}}function _(t){d(t.totalSize),s.beginCycle();try{e.render({items:t.items.map(f),listEl:o,recycle:(e,t)=>s.acquire(e,t),stickyItems:t.stickyItems.map(f),totalSize:t.totalSize})}finally{s.endCycle()}}function v(){s.clear(),e.clear?e.clear(o):o.textContent=``,o.style.height=``,o.style.width=``,o.style.position=``,o.style.contain=``}function x(){let t=e.stickToBottom;return t?t===!0?{enabled:!0,threshold:48}:{enabled:t.enabled??!0,threshold:t.threshold??48}:{enabled:!1,threshold:48}}function S(){let n=y(e.scrollElement,{count:t.length,estimateSize:u,gap:e.gap,getItemKey:l,horizontal:e.horizontal,measurementCache:e.measurementCache,onChange:_,overscan:e.overscan??3,sticky:e.sticky?n=>{let r=t[n];return r!==void 0&&e.sticky(n,r)}:void 0});return c=n,o.style.position=`relative`,o.style.contain=`layout`,n}function C(){i||(i=!0,a.abort(),c?.dispose(),c=null,v())}return{get count(){return c?.count??0},get disposalSignal(){return a.signal},dispose:C,get disposed(){return i},invalidate(){i||c?.invalidate()},isAtEnd(e){return c?.isAtEnd(e)??!0},get isScrolling(){return c?.isScrolling??!1},get items(){return c?.items??[]},measure(e,t){i||c?.measure(e,t)},measureBatch(e){i||c?.measureBatch(e)},measureEl(e,t){return i?()=>{}:c?.measureEl(e,t)??(()=>{})},refresh(){i||c?.refresh()},get scrollOffset(){return c?.scrollOffset??0},scrollToBottom(e){i||c?.scrollToBottom(e)},scrollToIndex(e,t){i||c?.scrollToIndex(e,t)},scrollToOffset(e,t){i||c?.scrollToOffset(e,t)},scrollToTop(e){i||c?.scrollToTop(e)},setItems(n){if(i)return;let r=x(),a=r.enabled&&(c?.isAtEnd(r.threshold)??!0);if(t=n,n.length===0){c?.dispose(),c=null,v();return}if(!c){let e=S();a&&e.scrollToBottom();return}let o=n.length!==c.count;c.update({count:n.length}),o?e.getItemKey||c.invalidate():e.getItemKey?c.refresh():c.invalidate(),a&&c.scrollToBottom()},get stickyItems(){return c?.stickyItems??[]},[Symbol.dispose]:C,get totalSize(){return c?.totalSize??0}}}function S(e,t){let n=document.createElement(`div`);n.style.cssText=t.horizontal?`overflow: auto hidden; width: 100%; height: 100%;`:`overflow: hidden auto; width: 100%; height: 100%;`,t.containerClass&&(n.className=t.containerClass);let r=document.createElement(`div`);n.appendChild(r),e.appendChild(n);let i;try{i=x({...t,listElement:r,scrollElement:n})}catch(e){throw n.remove(),e}let a=i.dispose.bind(i);return Object.assign(i,{dispose(){a(),n.remove()},[Symbol.dispose](){a(),n.remove()}})}function C(e,t,n,r,i,a){return a===`start`?e:a===`end`?t-i:a===`center`?e-(i-n)/2:e>=r&&t<=r+i?null:e<r?e:t-i}function w(e,t){typeof t.estimateRowSize==`number`&&h(t.estimateRowSize,`estimateRowSize`),typeof t.estimateColSize==`number`&&h(t.estimateColSize,`estimateColSize`),t.initialScrollTop!==void 0&&m(t.initialScrollTop,`initialScrollTop`),t.initialScrollLeft!==void 0&&m(t.initialScrollLeft,`initialScrollLeft`),t.rowGap!==void 0&&p(t.rowGap,`rowGap`),t.colGap!==void 0&&p(t.colGap,`colGap`),t.overscanY!==void 0&&g(t.overscanY,`overscanY`),t.overscanX!==void 0&&g(t.overscanX,`overscanX`);let n=p(t.rowCount,`rowCount`),r=p(t.colCount,`colCount`),i=f(t.estimateRowSize,36),a=f(t.estimateColSize,36),o=u(t.overscanY,3),l=u(t.overscanX,3),y=t.onChange,b=t.onRangeChange,x=t.rowMeasurementCache??new Map,S=t.colMeasurementCache??new Map,w=0,T=0,E=0,D=0,O=[],k=[],A=!1,j=v(n,e=>x.get(e)??i(e),s(t.rowGap??0)),M=v(r,e=>S.get(e)??a(e),s(t.colGap??0)),N=!1;function P(e){let t=Number.isFinite(e)?e:0;return Math.min(Math.max(0,j.totalSize-E),Math.max(0,t))}function F(e){let t=Number.isFinite(e)?e:0;return Math.min(Math.max(0,M.totalSize-D),Math.max(0,t))}function I(){if(A)return;let e=j.totalSize,t=M.totalSize;if(n===0||r===0||E<=0||D<=0){(j.prevStart!==-1||j.prevTotalSize!==e||M.prevTotalSize!==t)&&(j.commitDedup(-1,-1),M.commitDedup(-1,-1),O=[],k=[],y?.({cols:[],rows:[],totalHeight:e,totalWidth:t}));return}let{renderEnd:i,renderStart:a}=j.computeRange(w,w+E,o.start,o.end),{renderEnd:s,renderStart:c}=M.computeRange(T,T+D,l.start,l.end),u=j.isDedupSame(a,i),d=M.isDedupSame(c,s);if(u&&d)return;j.commitDedup(a,i),M.commitDedup(c,s),(!u||!d)&&b&&b({firstCol:c,firstRow:a,lastCol:s,lastRow:i});let f=[];for(let e=a;e<=i;e++)f.push(j.itemAt(e));let p=[];for(let e=c;e<=s;e++)p.push(M.itemAt(e));O=f,k=p,y?.({cols:k,rows:O,totalHeight:e,totalWidth:t})}function L(e,t){if(!Number.isFinite(e))return!1;let r=Math.floor(e);if(r<0||r>=n)return!1;let i=c(t,-1);return i<=0||x.get(r)===i?!1:(x.set(r,i),j.markChanged(r),!0)}function R(e,t){if(!Number.isFinite(e))return!1;let n=Math.floor(e);if(n<0||n>=r)return!1;let i=c(t,-1);return i<=0||S.get(n)===i?!1:(S.set(n,i),M.markChanged(n),!0)}function z(){N||(N=!0,queueMicrotask(()=>{N=!1;let e=j.consumeMinChangedIndex();e!==1/0&&j.rebuildFrom(e);let t=M.consumeMinChangedIndex();t!==1/0&&M.rebuildFrom(t),I()}))}function B(e,t){A||L(e,t)&&z()}function V(e,t){A||R(e,t)&&z()}function H(e,t){if(A)return;let n=!1;for(let{index:t,size:r}of e)L(t,r)&&(n=!0);for(let{index:e,size:r}of t)R(e,r)&&(n=!0);n&&z()}function ee(e,t){return A?()=>{}:d(q.signal,t,t=>B(e,t.contentRect.height))}function U(e,t){return A?()=>{}:d(q.signal,t,t=>V(e,t.contentRect.width))}function W(){A||(x.clear(),S.clear(),j.rebuild(!0),M.rebuild(!0),I())}function G(){A||(j.rebuild(!0),M.rebuild(!0),I())}function K(e){if(A)return;let t=s(e);if(t===0)return;n+=t,j.setCount(n),j.rebuild(!0);let r=j.startAt(t),i=P(w+r);X.scrollTo(T,i,`auto`),w=i,I()}function te(e,t={}){if(A||n===0)return;let r=Math.max(0,Math.min(Math.floor(Number.isFinite(e)?e:0),n-1)),i=t.behavior??`auto`,a=j.startAt(r),o=j.sizeAt(r),s=C(a,a+o,o,w,E,t.rowAlign??`auto`);s!==null&&X.scrollTo(T,P(s),i)}function ne(e,t={}){if(A||r===0)return;let n=Math.max(0,Math.min(Math.floor(Number.isFinite(e)?e:0),r-1)),i=t.behavior??`auto`,a=M.startAt(n),o=M.sizeAt(n),s=C(a,a+o,o,T,D,t.colAlign??`auto`);s!==null&&X.scrollTo(F(s),w,i)}function re(e,t,i={}){if(A||n===0||r===0)return;let a=Math.max(0,Math.min(Math.floor(Number.isFinite(e)?e:0),n-1)),o=Math.max(0,Math.min(Math.floor(Number.isFinite(t)?t:0),r-1)),s=i.behavior??`auto`,c=j.startAt(a),l=j.sizeAt(a),u=M.startAt(o),d=M.sizeAt(o),f=C(c,c+l,l,w,E,i.rowAlign??`auto`),p=C(u,u+d,d,T,D,i.colAlign??`auto`);(f!==null||p!==null)&&X.scrollTo(p===null?T:F(p),f===null?w:P(f),s)}function ie(e){if(A)return;e.rowCount!==void 0&&p(e.rowCount,`rowCount`),e.colCount!==void 0&&p(e.colCount,`colCount`),typeof e.estimateRowSize==`number`&&h(e.estimateRowSize,`estimateRowSize`),typeof e.estimateColSize==`number`&&h(e.estimateColSize,`estimateColSize`),e.rowGap!==void 0&&p(e.rowGap,`rowGap`),e.colGap!==void 0&&p(e.colGap,`colGap`),e.overscanY!==void 0&&g(e.overscanY,`overscanY`),e.overscanX!==void 0&&g(e.overscanX,`overscanX`);let t=!1,s=!1,c=!1;if(Object.hasOwn(e,`onChange`)&&(y=e.onChange),Object.hasOwn(e,`onRangeChange`)&&(b=e.onRangeChange),e.rowCount!==void 0){let r=e.rowCount;r!==n&&(n=r,j.setCount(n),t=!0)}if(e.colCount!==void 0){let t=e.colCount;t!==r&&(r=t,M.setCount(r),s=!0)}if(e.rowGap!==void 0){let n=e.rowGap;n!==j.gap&&(j.setGap(n),t=!0)}if(e.colGap!==void 0){let t=e.colGap;t!==M.gap&&(M.setGap(t),s=!0)}if(`estimateRowSize`in e&&(i=f(e.estimateRowSize,36),x.clear(),t=!0),`estimateColSize`in e&&(a=f(e.estimateColSize,36),S.clear(),s=!0),e.overscanY!==void 0){let t=u(e.overscanY,3);(t.start!==o.start||t.end!==o.end)&&(o=t,c=!0)}if(e.overscanX!==void 0){let t=u(e.overscanX,3);(t.start!==l.start||t.end!==l.end)&&(l=t,c=!0)}t&&j.rebuild(!0),s&&M.rebuild(!0),(t||s||c)&&I()}let q=new AbortController;function J(){A||(A=!0,q.abort(),X.detach())}function ae(){w=P(X.y.readOffset()),T=F(X.x.readOffset()),I()}function Y(){E=X.y.readViewportSize(),D=X.x.readViewportSize(),I()}let X=_(e,ae,Y);return j.rebuild(!0),M.rebuild(!0),E=X.y.readViewportSize(),D=X.x.readViewportSize(),t.initialScrollTop===void 0?t.initialScrollLeft!==void 0&&X.scrollTo(F(t.initialScrollLeft),0,`auto`):X.scrollTo(t.initialScrollLeft??0,P(t.initialScrollTop),`auto`),w=P(X.y.readOffset()),T=F(X.x.readOffset()),I(),{get cols(){return k},get disposalSignal(){return q.signal},dispose:J,get disposed(){return A},invalidate:W,measureBatch:H,measureColEl:U,measureColumn:V,measureRow:B,measureRowEl:ee,prependRows:K,refresh:G,get rows(){return O},get scrollLeft(){return T},scrollToCell:re,scrollToColumn:ne,get scrollTop(){return w},scrollToRow:te,[Symbol.dispose]:J,get totalHeight(){return j.totalSize},get totalWidth(){return M.totalSize},update:ie}}function T(e){let t=[];for(let n=0;n<e.length;n++){let r=e[n];t.push({isHeader:!0,itemIndex:-1,label:r.label,sectionIndex:n});for(let e=0;e<r.items.length;e++)t.push({isHeader:!1,item:r.items[e],itemIndex:e,sectionIndex:n})}return t}function E(e,t){typeof t.estimateHeaderSize==`number`&&h(t.estimateHeaderSize,`estimateHeaderSize`),typeof t.estimateItemSize==`number`&&h(t.estimateItemSize,`estimateItemSize`),t.overscan!==void 0&&g(t.overscan),t.scrollEndDelay!==void 0&&m(t.scrollEndDelay,`scrollEndDelay`);let n=t.sections,r=T(n);function i(e){return typeof e==`function`?t=>{let i=r[t];return e(n[i.sectionIndex],i.sectionIndex)}:f(typeof e==`number`?e:void 0,36)}let a=i(t.estimateHeaderSize),o=typeof t.estimateItemSize==`function`?t.estimateItemSize:null,s=o?null:f(typeof t.estimateItemSize==`number`?t.estimateItemSize:void 0,36),c=t.getItemKey;function l(e){let t=r[e];return t?t.isHeader?a(e):o?o(t.item,t.itemIndex,t.sectionIndex):s(e):36}function u(e){let t=r[e];return t?t.isHeader?`__header_${t.sectionIndex}`:c?c(t.item,t.itemIndex,t.sectionIndex):e:e}let d=!1,p=[],_=t.onChange,v=t.onScrollEnd,b=t.onScrollingChange;function x(e){let t=[],n=[],i=null;for(let i of e.items){let e=r[i.index];e&&(e.isHeader?n.push({...i,label:e.label??``,sectionIndex:e.sectionIndex}):t.push({...i,data:e.item,itemIndex:e.itemIndex,sectionIndex:e.sectionIndex}))}if(e.stickyItems.length>0){let t=e.stickyItems[0],n=r[t.index];n?.isHeader&&(i={...t,label:n.label??``,sectionIndex:n.sectionIndex})}return p=t,{headers:n,items:t,stickyHeader:i,totalSize:e.totalSize}}let S=y(e,{count:r.length,estimateSize:l,getItemKey:u,horizontal:t.horizontal,measurementCache:t.measurementCache,onChange:e=>{let t=x(e);_?.(t)},onScrollEnd:e=>v?.(e),onScrollingChange:e=>b?.(e),overscan:t.overscan??3,scrollEndDelay:t.scrollEndDelay,sticky:e=>r[e]?.isHeader??!1}),C=new AbortController;function w(){d||(d=!0,C.abort(),S.dispose())}function E(e,t){if(e<0||e>=n.length)return-1;let r=0;for(let i=0;i<n.length;i++){if(i===e)return t===void 0?r:r+1+t;r+=1+n[i].items.length}return-1}return{get count(){return S.count},get disposalSignal(){return C.signal},dispose:w,get disposed(){return d},invalidate(){d||S.invalidate()},get isScrolling(){return S.isScrolling},get items(){return p},measure(e,t){d||S.measure(e,t)},measureBatch(e){d||S.measureBatch(e)},measureEl(e,t){return d?()=>{}:S.measureEl(e,t)},refresh(){d||S.refresh()},get scrollOffset(){return S.scrollOffset},scrollToBottom(e){d||S.scrollToBottom(e)},scrollToIndex(e,t){d||S.scrollToIndex(e,t)},scrollToItem(e,t,n={}){if(d)return;let r=E(e,t);r<0||S.scrollToIndex(r,n)},scrollToOffset(e,t){d||S.scrollToOffset(e,t)},scrollToSection(e,t={}){if(d)return;let n=E(e);n<0||S.scrollToIndex(n,t)},scrollToTop(e){d||S.scrollToTop(e)},get stickyItems(){return S.stickyItems},[Symbol.dispose]:w,get totalSize(){return S.totalSize},update(e,t){if(d)return;t&&(typeof t.estimateHeaderSize==`number`&&h(t.estimateHeaderSize,`estimateHeaderSize`),typeof t.estimateItemSize==`number`&&h(t.estimateItemSize,`estimateItemSize`),t.overscan!==void 0&&g(t.overscan),t.scrollEndDelay!==void 0&&m(t.scrollEndDelay,`scrollEndDelay`),Object.hasOwn(t,`onChange`)&&(_=t.onChange),Object.hasOwn(t,`onScrollEnd`)&&(v=t.onScrollEnd),Object.hasOwn(t,`onScrollingChange`)&&(b=t.onScrollingChange),t.estimateHeaderSize!==void 0&&(a=i(t.estimateHeaderSize)),t.estimateItemSize!==void 0&&(o=typeof t.estimateItemSize==`function`?t.estimateItemSize:null,s=o?null:f(typeof t.estimateItemSize==`number`?t.estimateItemSize:void 0,36)),t.getItemKey!==void 0&&(c=t.getItemKey)),n=e;let l=r.length;r=T(n);let u={count:r.length};t?.measurementCache!==void 0&&(u.measurementCache=t.measurementCache),t?.overscan!==void 0&&(u.overscan=t.overscan),t?.scrollEndDelay!==void 0&&(u.scrollEndDelay=t.scrollEndDelay),r.length!==l||t?.measurementCache!==void 0||t?.overscan!==void 0||t?.scrollEndDelay!==void 0?S.update(u):S.refresh()}}}function D(e,t){return Object.defineProperties({},{...Object.getOwnPropertyDescriptors(e),state:{configurable:!0,enumerable:!0,value:t}})}function O(t,n){let r=(0,e.signal)({headers:[],items:[],stickyHeader:null,totalSize:0}),i;function a(e){r.value=e,i?.(e)}let o=E(t,{...n,onChange:a}),s=D(o,r);return Object.defineProperty(s,"update",{configurable:!0,enumerable:!0,value(e,t){if(!t||!Object.hasOwn(t,`onChange`)){o.update(e,t);return}i=t.onChange;let{onChange:n,...r}=t;o.update(e,{...r,onChange:a})}}),s}function k(t,n){let r=(0,e.signal)({items:[],stickyItems:[],totalSize:0}),i;function a(e){r.value=e,i?.(e)}let o=y(t,{...n,onChange:a}),s=D(o,r);return Object.defineProperty(s,"update",{configurable:!0,enumerable:!0,value(e){if(!Object.hasOwn(e,`onChange`)){o.update(e);return}i=e.onChange;let{onChange:t,...n}=e;o.update({...n,onChange:a})}}),s}exports.DEFAULT_ESTIMATE_SIZE=a,exports.DEFAULT_OVERSCAN=o,exports.ScrollConfigurationError=n,exports.ScrollError=t,exports.ScrollRangeError=r,exports.createDomVirtualList=x,exports.createGridVirtualizer=w,exports.createGroupedVirtualizer=E,exports.createMeasurementCache=i,exports.createReactiveGroupedVirtualizer=O,exports.createReactiveVirtualizer=k,exports.createVirtualScroller=S,exports.createVirtualizer=y;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/ripple");function t(){return new Map}var n=36,r=3;function i(e,t=0){return Number.isFinite(e)?Math.max(0,Math.floor(e)):t}function a(e,t){return!Number.isFinite(e)||e<=0||e>1e7?t:e}function o(e){return typeof Window<`u`&&e instanceof Window||typeof e.innerHeight==`number`&&typeof e.document==`object`}function s(e,t){if(typeof e==`number`){let n=i(e,t);return{end:n,start:n}}return{end:i(e?.end??t),start:i(e?.start??t)}}function c(e,t,n){let r=new ResizeObserver(e=>{for(let t of e)n(t)});return r.observe(t),e.addEventListener(`abort`,()=>r.disconnect(),{once:!0}),()=>r.disconnect()}function l(e,t){if(typeof e==`function`)return n=>{try{return a(e(n),t)}catch(e){return`${n}${e}`,t}};let n=typeof e==`number`?a(e,t):t;return()=>n}var u=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},d=class extends u{},f=class extends u{};function p(e,t){if(!Number.isFinite(e)||!Number.isInteger(e)||e<0)throw new d(`${t} must be a finite non-negative integer.`);return e}function m(e,t){if(!Number.isFinite(e)||e<0)throw new d(`${t} must be a finite non-negative number.`);return e}function h(e,t){if(!Number.isFinite(e)||e<=0||e>1e7)throw new d(`${t} must be a finite positive number no greater than 10000000.`);return e}function g(e,t=`overscan`){if(typeof e==`number`){p(e,t);return}if(typeof e!=`object`||!e||Array.isArray(e))throw new d(`${t} must be a finite non-negative integer or an overscan object.`);e.start!==void 0&&p(e.start,`${t}.start`),e.end!==void 0&&p(e.end,`${t}.end`)}function _(e,t,n){if(o(e))return e.addEventListener(`scroll`,t,{passive:!0}),e.addEventListener(`resize`,n,{passive:!0}),{detach(){e.removeEventListener(`scroll`,t),e.removeEventListener(`resize`,n)},scrollTo:(t,n,r)=>e.scrollTo({behavior:r,left:t,top:n}),x:{readOffset:()=>e.scrollX,readViewportSize:()=>e.innerWidth,writeOffset:(t,n)=>e.scrollTo({behavior:n,left:t})},y:{readOffset:()=>e.scrollY,readViewportSize:()=>e.innerHeight,writeOffset:(t,n)=>e.scrollTo({behavior:n,top:t})}};let r=new ResizeObserver(n);return e.addEventListener(`scroll`,t,{passive:!0}),r.observe(e),{detach(){e.removeEventListener(`scroll`,t),r.disconnect()},scrollTo:(t,n,r)=>e.scrollTo({behavior:r,left:t,top:n}),x:{readOffset:()=>e.scrollLeft,readViewportSize:()=>e.clientWidth,writeOffset:(t,n)=>e.scrollTo({behavior:n,left:t})},y:{readOffset:()=>e.scrollTop,readViewportSize:()=>e.clientHeight,writeOffset:(t,n)=>e.scrollTo({behavior:n,top:t})}}}function v(e,t,n){let r=e,i=n,a=t,o=[],s=0,c=-1,l=-1,u=-1,d=!1,f=1/0;function p(e){return o[e]??0}function m(e){return p(e)+a(e)}function h(e=!1){e&&(c=-1,l=-1,u=-1);let t=[0],n=0;for(let e=0;e<r;e++)n+=a(e)+(e<r-1?i:0),t.push(n);o=t,s=n}function g(e){if(!Number.isFinite(e)||e>=r)return;c=-1,l=-1,u=-1;let t=o[e]??0;for(let n=e;n<r;n++)o[n]=t,t+=a(n)+(n<r-1?i:0);o[r]=t,s=t}function _(e){let t=0,n=r-1;for(;t<n;){let r=t+n>>1;m(r)<=e?t=r+1:n=r}return t}function v(e,t){let n=t,i=r-1;for(;n<i;){let t=n+i+1>>1;p(t)<e?n=t:i=t-1}return n}function y(e,t,n,i){let a=_(e),o=v(t,a);return{renderEnd:Math.min(r-1,o+i),renderStart:Math.max(0,a-n)}}function b(e,t){return e===c&&t===l&&s===u}function x(e,t){c=e,l=t,u=s}function S(){c=-1,l=-1,u=-1}function C(e){d||(d=!0,queueMicrotask(()=>{d=!1;let t=f;f=1/0,g(t),e()}))}function w(e){e<f&&(f=e)}function T(e){let t=p(e),n=a(e);return{end:t+n,index:e,size:n,start:t}}return{commitDedup:x,computeRange:y,consumeMinChangedIndex(){let e=f;return f=1/0,e},get count(){return r},endAt:m,findFirst:_,findLast:v,get gap(){return i},isDedupSame:b,itemAt:T,markChanged:w,get minChangedIndex(){return f},get pendingBuild(){return d},get prevEnd(){return l},get prevStart(){return c},get prevTotalSize(){return u},rebuild:h,rebuildFrom:g,resetDedup:S,scheduleBuild:C,setCount(e){r=e},setGap(e){i=e},sizeAt(e){return a(e)},startAt:p,get totalSize(){return s}}}function y(e,t){typeof t.estimateSize==`number`&&h(t.estimateSize,`estimateSize`),t.gap!==void 0&&p(t.gap,`gap`),t.initialOffset!==void 0&&m(t.initialOffset,`initialOffset`),t.overscan!==void 0&&g(t.overscan),t.scrollEndDelay!==void 0&&m(t.scrollEndDelay,`scrollEndDelay`);let n=!!t.horizontal,r=e=>e,o=p(t.count,`count`),u=l(t.estimateSize,36),d=i(t.gap??0),f=t.getItemKey??r,y=s(t.overscan,3),b=t.sticky??null,x=t.onChange,S=t.onScrollEnd,C=t.onScrollingChange,w=t.scrollEndDelay??150,T=!1,E=null,D=`onscrollend`in e;function O(){T&&(T=!1,C?.(!1),S?.(I))}function k(){T||(T=!0,C?.(!0)),D||(E!==null&&clearTimeout(E),E=setTimeout(O,w))}let A=t.measurementCache??new Map,j=[],M=[],N=v(o,e=>A.get(f(e))??u(e),d),P=-1,F=0,I=0,L=0,R=-1,z=!1;function B(e){let t=Number.isFinite(e)?e:0,n=Math.max(0,N.totalSize-L);return Math.min(n,Math.max(0,t))}function V(){if(!b||o===0||I<=0)return[];let e=-1,t=0,n=o-1;for(;t<=n;){let r=t+n>>1;N.startAt(r)<I?(e=r,t=r+1):n=r-1}if(e<0)return[];let r=-1;for(let t=e;t>=0;t--)if(b(t)){r=t;break}if(r===-1)return[];let i=N.sizeAt(r),a=1/0;for(let e=r+1;e<o;e++)if(b(e)){a=N.startAt(e);break}let s=Math.min(I,a-i);return[{end:s+i,index:r,size:i,start:s}]}function H(){if(z)return;if(o===0||L<=0){(N.prevStart!==-1||N.prevTotalSize!==N.totalSize)&&(N.commitDedup(-1,-1),j=[],M=[],x&&x({items:j,stickyItems:M,totalSize:N.totalSize}));return}let{renderEnd:e,renderStart:t}=N.computeRange(I,I+L,y.start,y.end),n=b!==null&&I!==R;if(N.isDedupSame(t,e)&&!n)return;N.commitDedup(t,e),R=I;let r=[];for(let n=t;n<=e;n++)r.push(N.itemAt(n));j=r,M=b?V():[],x&&x({items:j,stickyItems:M,totalSize:N.totalSize})}function ee(e,t){if(!Number.isFinite(e))return!1;let n=Math.floor(e);if(n<0||n>=o)return!1;let r=a(t,-1);if(r<=0)return!1;let i=f(n);return A.get(i)!==r&&(A.set(i,r),N.markChanged(n),!0)}function U(){if(I<=0||o===0){P=-1;return}P=N.findFirst(I),F=I-N.startAt(P)}function W(){if(P<0)return;let e=N.startAt(P)+F-I;if(P=-1,Math.abs(e)>=1){let t=B(I+e);$.writeOffset(t,`auto`),I=t}}function G(e){if(z)return;let t=!1;for(let{index:n,size:r}of e)ee(n,r)&&(t=!0);t&&(N.pendingBuild||U(),N.scheduleBuild(()=>{W(),H()}))}function K(e,t){G([{index:e,size:t}])}function te(e,t){return z?()=>{}:c(Z.signal,t,t=>{K(e,n?t.contentRect.width:t.contentRect.height)})}function ne(e){e.count!==void 0&&p(e.count,`count`),typeof e.estimateSize==`number`&&h(e.estimateSize,`estimateSize`),e.gap!==void 0&&p(e.gap,`gap`),e.overscan!==void 0&&g(e.overscan),e.scrollEndDelay!==void 0&&m(e.scrollEndDelay,`scrollEndDelay`);let t=!1,n=!1;if(Object.hasOwn(e,`onChange`)&&(x=e.onChange),Object.hasOwn(e,`onScrollEnd`)&&(S=e.onScrollEnd),Object.hasOwn(e,`onScrollingChange`)&&(C=e.onScrollingChange),e.scrollEndDelay!==void 0&&(w=e.scrollEndDelay),e.count!==void 0){let n=e.count;n!==o&&(o=n,N.setCount(o),t=!0)}if(Object.hasOwn(e,`estimateSize`)&&(u=l(e.estimateSize,36),A.clear(),t=!0),e.gap!==void 0){let n=e.gap;n!==d&&(d=n,N.setGap(d),t=!0)}if(Object.hasOwn(e,`getItemKey`)){let n=e.getItemKey??r;n!==f&&(f=n,A.clear(),t=!0)}if(Object.hasOwn(e,`measurementCache`)&&e.measurementCache!==void 0&&(A=e.measurementCache,t=!0),e.overscan!==void 0){let t=s(e.overscan,3);(t.start!==y.start||t.end!==y.end)&&(y=t,n=!0)}if(Object.hasOwn(e,`sticky`)){let t=e.sticky??null;t!==b&&(b=t,N.resetDedup()),n=!0}t&&(U(),N.rebuild(!0),W()),(n||t)&&H()}function re(){z||(A.clear(),N.rebuild(!0),H())}function ie(){z||(N.rebuild(!0),H())}function q(e){if(z)return;let t=i(e);if(t===0)return;o+=t,N.setCount(o),N.rebuild(!0);let n=N.startAt(t),r=B(I+n);$.writeOffset(r,`auto`),I=r,H()}function J(e){z||ne(e)}function ae(t,n={}){if(z||o<=0)return;let r=Math.max(0,Math.min(Number.isFinite(t)?Math.floor(t):0,o-1)),i=n.align??`auto`,a=n.behavior??`auto`,s=N.startAt(r),c=N.sizeAt(r),l=s+c,u;if(i===`start`)u=s;else if(i===`end`)u=l-L;else if(i===`center`)u=s-(L-c)/2;else{let e=I,t=e+L;if(s>=e&&l<=t){n.onComplete&&queueMicrotask(n.onComplete);return}u=s<e?s:l-L}$.writeOffset(B(u),a),n.onComplete&&(a===`smooth`&&`onscrollend`in e?e.addEventListener(`scrollend`,n.onComplete,{once:!0}):queueMicrotask(n.onComplete))}function Y(e,t={}){z||$.writeOffset(B(e),t.behavior??`auto`)}function X(e={}){Y(0,e)}function oe(e={}){Y(Math.max(0,N.totalSize-L),e)}function se(e=0){return N.totalSize-(I+L)<=e}let Z=new AbortController;function ce(){z||(z=!0,Z.abort(),E!==null&&(clearTimeout(E),E=null),D&&e.removeEventListener(`scrollend`,O),Q.detach())}function le(){I=B($.readOffset()),k(),H()}function ue(){L=$.readViewportSize(),H()}let Q=_(e,le,ue),$=n?Q.x:Q.y;return D&&e.addEventListener(`scrollend`,O,{passive:!0}),N.rebuild(!0),t.initialOffset!==void 0&&$.writeOffset(B(t.initialOffset),`auto`),I=B($.readOffset()),L=$.readViewportSize(),H(),{get count(){return o},get disposalSignal(){return Z.signal},dispose:ce,get disposed(){return z},invalidate:re,isAtEnd:se,get isScrolling(){return T},get items(){return j},measure:K,measureBatch:G,measureEl:te,prepend:q,refresh:ie,get scrollOffset(){return I},scrollToBottom:oe,scrollToIndex:ae,scrollToOffset:Y,scrollToTop:X,get stickyItems(){return M},[Symbol.dispose]:ce,get totalSize(){return N.totalSize},update:J}}function b(){let e=new Map,t=new Map,n=[],r=!1;return{acquire(i,a){if(!r)return a();let o=e.get(i);if(o)return t.set(i,o),o;let s=n.pop()??a();return t.set(i,s),s},beginCycle(){t=new Map,r=!0},clear(){for(let t of e.values())t.remove();e.clear(),t.clear(),n.length=0,r=!1},endCycle(){if(r){r=!1;for(let[r,i]of e)t.has(r)||(i.remove(),n.push(i));e=t}}}}function x(e){if(typeof e.estimateSize==`number`&&h(e.estimateSize,`estimateSize`),e.gap!==void 0&&p(e.gap,`gap`),e.overscan!==void 0&&g(e.overscan),e.stickToBottom!==void 0&&typeof e.stickToBottom!=`boolean`){if(e.stickToBottom===null||Array.isArray(e.stickToBottom))throw new d(`stickToBottom must be a boolean or options object.`);e.stickToBottom.threshold!==void 0&&m(e.stickToBottom.threshold,`stickToBottom.threshold`)}let t=[],n=!1,r=new AbortController,i=e.listElement,a=b(),o=null;function s(n){let r=t[n];return r!==void 0&&e.getItemKey?e.getItemKey(n,r):n}function c(n){if(e.estimateSize===void 0)return 36;if(typeof e.estimateSize==`number`)return e.estimateSize;let r=t[n];return r===void 0?36:e.estimateSize(n,r)}function l(t){e.horizontal?(i.style.height=``,i.style.width=`${t}px`):(i.style.height=`${t}px`,i.style.width=``)}function u(e){let n=t[e.index];if(n===void 0)throw new f(`toRenderItem: index ${e.index} is out of range (currentItems.length=${t.length})`);return{...e,data:n}}function _(t){l(t.totalSize),a.beginCycle();try{e.render({items:t.items.map(u),listEl:i,recycle:(e,t)=>a.acquire(e,t),stickyItems:t.stickyItems.map(u),totalSize:t.totalSize})}finally{a.endCycle()}}function v(){a.clear(),e.clear?e.clear(i):i.textContent=``,i.style.height=``,i.style.width=``,i.style.position=``,i.style.contain=``}function x(){let t=e.stickToBottom;return t?t===!0?{enabled:!0,threshold:48}:{enabled:t.enabled??!0,threshold:t.threshold??48}:{enabled:!1,threshold:48}}function S(){let n=y(e.scrollElement,{count:t.length,estimateSize:c,gap:e.gap,getItemKey:s,horizontal:e.horizontal,measurementCache:e.measurementCache,onChange:_,overscan:e.overscan??3,sticky:e.sticky?n=>{let r=t[n];return r!==void 0&&e.sticky(n,r)}:void 0});return o=n,i.style.position=`relative`,i.style.contain=`layout`,n}function C(){n||(n=!0,r.abort(),o?.dispose(),o=null,v())}return{get count(){return o?.count??0},get disposalSignal(){return r.signal},dispose:C,get disposed(){return n},invalidate(){n||o?.invalidate()},isAtEnd(e){return o?.isAtEnd(e)??!0},get isScrolling(){return o?.isScrolling??!1},get items(){return o?.items??[]},measure(e,t){n||o?.measure(e,t)},measureBatch(e){n||o?.measureBatch(e)},measureEl(e,t){return n?()=>{}:o?.measureEl(e,t)??(()=>{})},refresh(){n||o?.refresh()},get scrollOffset(){return o?.scrollOffset??0},scrollToBottom(e){n||o?.scrollToBottom(e)},scrollToIndex(e,t){n||o?.scrollToIndex(e,t)},scrollToOffset(e,t){n||o?.scrollToOffset(e,t)},scrollToTop(e){n||o?.scrollToTop(e)},setItems(r){if(n)return;let i=x(),a=i.enabled&&(o?.isAtEnd(i.threshold)??!0);if(t=r,r.length===0){o?.dispose(),o=null,v();return}if(!o){let e=S();a&&e.scrollToBottom();return}let s=r.length!==o.count;o.update({count:r.length}),s?e.getItemKey||o.invalidate():e.getItemKey?o.refresh():o.invalidate(),a&&o.scrollToBottom()},get stickyItems(){return o?.stickyItems??[]},[Symbol.dispose]:C,get totalSize(){return o?.totalSize??0}}}function S(e,t){let n=document.createElement(`div`);n.style.cssText=t.horizontal?`overflow: auto hidden; width: 100%; height: 100%;`:`overflow: hidden auto; width: 100%; height: 100%;`,t.containerClass&&(n.className=t.containerClass);let r=document.createElement(`div`);n.appendChild(r),e.appendChild(n);let i;try{i=x({...t,listElement:r,scrollElement:n})}catch(e){throw n.remove(),e}let a=i.dispose.bind(i);return Object.assign(i,{dispose(){a(),n.remove()},[Symbol.dispose](){a(),n.remove()}})}function C(e,t,n,r,i,a){return a===`start`?e:a===`end`?t-i:a===`center`?e-(i-n)/2:e>=r&&t<=r+i?null:e<r?e:t-i}function w(e,t){typeof t.estimateRowSize==`number`&&h(t.estimateRowSize,`estimateRowSize`),typeof t.estimateColSize==`number`&&h(t.estimateColSize,`estimateColSize`),t.initialScrollTop!==void 0&&m(t.initialScrollTop,`initialScrollTop`),t.initialScrollLeft!==void 0&&m(t.initialScrollLeft,`initialScrollLeft`),t.rowGap!==void 0&&p(t.rowGap,`rowGap`),t.colGap!==void 0&&p(t.colGap,`colGap`),t.overscanY!==void 0&&g(t.overscanY,`overscanY`),t.overscanX!==void 0&&g(t.overscanX,`overscanX`);let n=p(t.rowCount,`rowCount`),r=p(t.colCount,`colCount`),o=l(t.estimateRowSize,36),u=l(t.estimateColSize,36),d=s(t.overscanY,3),f=s(t.overscanX,3),y=t.onChange,b=t.onRangeChange,x=t.rowMeasurementCache??new Map,S=t.colMeasurementCache??new Map,w=0,T=0,E=0,D=0,O=[],k=[],A=!1,j=v(n,e=>x.get(e)??o(e),i(t.rowGap??0)),M=v(r,e=>S.get(e)??u(e),i(t.colGap??0)),N=!1;function P(e){let t=Number.isFinite(e)?e:0;return Math.min(Math.max(0,j.totalSize-E),Math.max(0,t))}function F(e){let t=Number.isFinite(e)?e:0;return Math.min(Math.max(0,M.totalSize-D),Math.max(0,t))}function I(){if(A)return;let e=j.totalSize,t=M.totalSize;if(n===0||r===0||E<=0||D<=0){(j.prevStart!==-1||j.prevTotalSize!==e||M.prevTotalSize!==t)&&(j.commitDedup(-1,-1),M.commitDedup(-1,-1),O=[],k=[],y?.({cols:[],rows:[],totalHeight:e,totalWidth:t}));return}let{renderEnd:i,renderStart:a}=j.computeRange(w,w+E,d.start,d.end),{renderEnd:o,renderStart:s}=M.computeRange(T,T+D,f.start,f.end),c=j.isDedupSame(a,i),l=M.isDedupSame(s,o);if(c&&l)return;j.commitDedup(a,i),M.commitDedup(s,o),(!c||!l)&&b&&b({firstCol:s,firstRow:a,lastCol:o,lastRow:i});let u=[];for(let e=a;e<=i;e++)u.push(j.itemAt(e));let p=[];for(let e=s;e<=o;e++)p.push(M.itemAt(e));O=u,k=p,y?.({cols:k,rows:O,totalHeight:e,totalWidth:t})}function L(e,t){if(!Number.isFinite(e))return!1;let r=Math.floor(e);if(r<0||r>=n)return!1;let i=a(t,-1);return i<=0||x.get(r)===i?!1:(x.set(r,i),j.markChanged(r),!0)}function R(e,t){if(!Number.isFinite(e))return!1;let n=Math.floor(e);if(n<0||n>=r)return!1;let i=a(t,-1);return i<=0||S.get(n)===i?!1:(S.set(n,i),M.markChanged(n),!0)}function z(){N||(N=!0,queueMicrotask(()=>{N=!1;let e=j.consumeMinChangedIndex();e!==1/0&&j.rebuildFrom(e);let t=M.consumeMinChangedIndex();t!==1/0&&M.rebuildFrom(t),I()}))}function B(e,t){A||L(e,t)&&z()}function V(e,t){A||R(e,t)&&z()}function H(e,t){if(A)return;let n=!1;for(let{index:t,size:r}of e)L(t,r)&&(n=!0);for(let{index:e,size:r}of t)R(e,r)&&(n=!0);n&&z()}function ee(e,t){return A?()=>{}:c(q.signal,t,t=>B(e,t.contentRect.height))}function U(e,t){return A?()=>{}:c(q.signal,t,t=>V(e,t.contentRect.width))}function W(){A||(x.clear(),S.clear(),j.rebuild(!0),M.rebuild(!0),I())}function G(){A||(j.rebuild(!0),M.rebuild(!0),I())}function K(e){if(A)return;let t=i(e);if(t===0)return;n+=t,j.setCount(n),j.rebuild(!0);let r=j.startAt(t),a=P(w+r);X.scrollTo(T,a,`auto`),w=a,I()}function te(e,t={}){if(A||n===0)return;let r=Math.max(0,Math.min(Math.floor(Number.isFinite(e)?e:0),n-1)),i=t.behavior??`auto`,a=j.startAt(r),o=j.sizeAt(r),s=C(a,a+o,o,w,E,t.rowAlign??`auto`);s!==null&&X.scrollTo(T,P(s),i)}function ne(e,t={}){if(A||r===0)return;let n=Math.max(0,Math.min(Math.floor(Number.isFinite(e)?e:0),r-1)),i=t.behavior??`auto`,a=M.startAt(n),o=M.sizeAt(n),s=C(a,a+o,o,T,D,t.colAlign??`auto`);s!==null&&X.scrollTo(F(s),w,i)}function re(e,t,i={}){if(A||n===0||r===0)return;let a=Math.max(0,Math.min(Math.floor(Number.isFinite(e)?e:0),n-1)),o=Math.max(0,Math.min(Math.floor(Number.isFinite(t)?t:0),r-1)),s=i.behavior??`auto`,c=j.startAt(a),l=j.sizeAt(a),u=M.startAt(o),d=M.sizeAt(o),f=C(c,c+l,l,w,E,i.rowAlign??`auto`),p=C(u,u+d,d,T,D,i.colAlign??`auto`);(f!==null||p!==null)&&X.scrollTo(p===null?T:F(p),f===null?w:P(f),s)}function ie(e){if(A)return;e.rowCount!==void 0&&p(e.rowCount,`rowCount`),e.colCount!==void 0&&p(e.colCount,`colCount`),typeof e.estimateRowSize==`number`&&h(e.estimateRowSize,`estimateRowSize`),typeof e.estimateColSize==`number`&&h(e.estimateColSize,`estimateColSize`),e.rowGap!==void 0&&p(e.rowGap,`rowGap`),e.colGap!==void 0&&p(e.colGap,`colGap`),e.overscanY!==void 0&&g(e.overscanY,`overscanY`),e.overscanX!==void 0&&g(e.overscanX,`overscanX`);let t=!1,i=!1,a=!1;if(Object.hasOwn(e,`onChange`)&&(y=e.onChange),Object.hasOwn(e,`onRangeChange`)&&(b=e.onRangeChange),e.rowCount!==void 0){let r=e.rowCount;r!==n&&(n=r,j.setCount(n),t=!0)}if(e.colCount!==void 0){let t=e.colCount;t!==r&&(r=t,M.setCount(r),i=!0)}if(e.rowGap!==void 0){let n=e.rowGap;n!==j.gap&&(j.setGap(n),t=!0)}if(e.colGap!==void 0){let t=e.colGap;t!==M.gap&&(M.setGap(t),i=!0)}if(`estimateRowSize`in e&&(o=l(e.estimateRowSize,36),x.clear(),t=!0),`estimateColSize`in e&&(u=l(e.estimateColSize,36),S.clear(),i=!0),e.overscanY!==void 0){let t=s(e.overscanY,3);(t.start!==d.start||t.end!==d.end)&&(d=t,a=!0)}if(e.overscanX!==void 0){let t=s(e.overscanX,3);(t.start!==f.start||t.end!==f.end)&&(f=t,a=!0)}t&&j.rebuild(!0),i&&M.rebuild(!0),(t||i||a)&&I()}let q=new AbortController;function J(){A||(A=!0,q.abort(),X.detach())}function ae(){w=P(X.y.readOffset()),T=F(X.x.readOffset()),I()}function Y(){E=X.y.readViewportSize(),D=X.x.readViewportSize(),I()}let X=_(e,ae,Y);return j.rebuild(!0),M.rebuild(!0),E=X.y.readViewportSize(),D=X.x.readViewportSize(),t.initialScrollTop===void 0?t.initialScrollLeft!==void 0&&X.scrollTo(F(t.initialScrollLeft),0,`auto`):X.scrollTo(t.initialScrollLeft??0,P(t.initialScrollTop),`auto`),w=P(X.y.readOffset()),T=F(X.x.readOffset()),I(),{get cols(){return k},get disposalSignal(){return q.signal},dispose:J,get disposed(){return A},invalidate:W,measureBatch:H,measureColEl:U,measureColumn:V,measureRow:B,measureRowEl:ee,prependRows:K,refresh:G,get rows(){return O},get scrollLeft(){return T},scrollToCell:re,scrollToColumn:ne,get scrollTop(){return w},scrollToRow:te,[Symbol.dispose]:J,get totalHeight(){return j.totalSize},get totalWidth(){return M.totalSize},update:ie}}function T(e){let t=[];for(let n=0;n<e.length;n++){let r=e[n];t.push({isHeader:!0,itemIndex:-1,label:r.label,sectionIndex:n});for(let e=0;e<r.items.length;e++)t.push({isHeader:!1,item:r.items[e],itemIndex:e,sectionIndex:n})}return t}function E(e,t){typeof t.estimateHeaderSize==`number`&&h(t.estimateHeaderSize,`estimateHeaderSize`),typeof t.estimateItemSize==`number`&&h(t.estimateItemSize,`estimateItemSize`),t.overscan!==void 0&&g(t.overscan),t.scrollEndDelay!==void 0&&m(t.scrollEndDelay,`scrollEndDelay`);let n=t.sections,r=T(n);function i(e){return typeof e==`function`?t=>{let i=r[t];return e(n[i.sectionIndex],i.sectionIndex)}:l(typeof e==`number`?e:void 0,36)}let a=i(t.estimateHeaderSize),o=typeof t.estimateItemSize==`function`?t.estimateItemSize:null,s=o?null:l(typeof t.estimateItemSize==`number`?t.estimateItemSize:void 0,36),c=t.getItemKey;function u(e){let t=r[e];return t?t.isHeader?a(e):o?o(t.item,t.itemIndex,t.sectionIndex):s(e):36}function d(e){let t=r[e];return t?t.isHeader?`__header_${t.sectionIndex}`:c?c(t.item,t.itemIndex,t.sectionIndex):e:e}let f=!1,p=[],_=t.onChange,v=t.onScrollEnd,b=t.onScrollingChange;function x(e){let t=[],n=[],i=null;for(let i of e.items){let e=r[i.index];e&&(e.isHeader?n.push({...i,label:e.label??``,sectionIndex:e.sectionIndex}):t.push({...i,data:e.item,itemIndex:e.itemIndex,sectionIndex:e.sectionIndex}))}if(e.stickyItems.length>0){let t=e.stickyItems[0],n=r[t.index];n?.isHeader&&(i={...t,label:n.label??``,sectionIndex:n.sectionIndex})}return p=t,{headers:n,items:t,stickyHeader:i,totalSize:e.totalSize}}let S=y(e,{count:r.length,estimateSize:u,getItemKey:d,horizontal:t.horizontal,measurementCache:t.measurementCache,onChange:e=>{let t=x(e);_?.(t)},onScrollEnd:e=>v?.(e),onScrollingChange:e=>b?.(e),overscan:t.overscan??3,scrollEndDelay:t.scrollEndDelay,sticky:e=>r[e]?.isHeader??!1}),C=new AbortController;function w(){f||(f=!0,C.abort(),S.dispose())}function E(e,t){if(e<0||e>=n.length)return-1;let r=0;for(let i=0;i<n.length;i++){if(i===e)return t===void 0?r:r+1+t;r+=1+n[i].items.length}return-1}return{get count(){return S.count},get disposalSignal(){return C.signal},dispose:w,get disposed(){return f},invalidate(){f||S.invalidate()},get isScrolling(){return S.isScrolling},get items(){return p},measure(e,t){f||S.measure(e,t)},measureBatch(e){f||S.measureBatch(e)},measureEl(e,t){return f?()=>{}:S.measureEl(e,t)},refresh(){f||S.refresh()},get scrollOffset(){return S.scrollOffset},scrollToBottom(e){f||S.scrollToBottom(e)},scrollToIndex(e,t){f||S.scrollToIndex(e,t)},scrollToItem(e,t,n={}){if(f)return;let r=E(e,t);r<0||S.scrollToIndex(r,n)},scrollToOffset(e,t){f||S.scrollToOffset(e,t)},scrollToSection(e,t={}){if(f)return;let n=E(e);n<0||S.scrollToIndex(n,t)},scrollToTop(e){f||S.scrollToTop(e)},get stickyItems(){return S.stickyItems},[Symbol.dispose]:w,get totalSize(){return S.totalSize},update(e,t){if(f)return;t&&(typeof t.estimateHeaderSize==`number`&&h(t.estimateHeaderSize,`estimateHeaderSize`),typeof t.estimateItemSize==`number`&&h(t.estimateItemSize,`estimateItemSize`),t.overscan!==void 0&&g(t.overscan),t.scrollEndDelay!==void 0&&m(t.scrollEndDelay,`scrollEndDelay`),Object.hasOwn(t,`onChange`)&&(_=t.onChange),Object.hasOwn(t,`onScrollEnd`)&&(v=t.onScrollEnd),Object.hasOwn(t,`onScrollingChange`)&&(b=t.onScrollingChange),t.estimateHeaderSize!==void 0&&(a=i(t.estimateHeaderSize)),t.estimateItemSize!==void 0&&(o=typeof t.estimateItemSize==`function`?t.estimateItemSize:null,s=o?null:l(typeof t.estimateItemSize==`number`?t.estimateItemSize:void 0,36)),t.getItemKey!==void 0&&(c=t.getItemKey)),n=e;let u=r.length;r=T(n);let d={count:r.length};t?.measurementCache!==void 0&&(d.measurementCache=t.measurementCache),t?.overscan!==void 0&&(d.overscan=t.overscan),t?.scrollEndDelay!==void 0&&(d.scrollEndDelay=t.scrollEndDelay),r.length!==u||t?.measurementCache!==void 0||t?.overscan!==void 0||t?.scrollEndDelay!==void 0?S.update(d):S.refresh()}}}function D(e,t){return Object.defineProperties({},{...Object.getOwnPropertyDescriptors(e),state:{configurable:!0,enumerable:!0,value:t}})}function O(t,n){let r=(0,e.signal)({headers:[],items:[],stickyHeader:null,totalSize:0}),i;function a(e){r.value=e,i?.(e)}let o=E(t,{...n,onChange:a}),s=D(o,r);return Object.defineProperty(s,"update",{configurable:!0,enumerable:!0,value(e,t){if(!t||!Object.hasOwn(t,`onChange`)){o.update(e,t);return}i=t.onChange;let{onChange:n,...r}=t;o.update(e,{...r,onChange:a})}}),s}function k(t,n){let r=(0,e.signal)({items:[],stickyItems:[],totalSize:0}),i;function a(e){r.value=e,i?.(e)}let o=y(t,{...n,onChange:a}),s=D(o,r);return Object.defineProperty(s,"update",{configurable:!0,enumerable:!0,value(e){if(!Object.hasOwn(e,`onChange`)){o.update(e);return}i=e.onChange;let{onChange:t,...n}=e;o.update({...n,onChange:a})}}),s}exports.DEFAULT_ESTIMATE_SIZE=n,exports.DEFAULT_OVERSCAN=r,exports.ScrollConfigurationError=d,exports.ScrollError=u,exports.ScrollRangeError=f,exports.createDomVirtualList=x,exports.createGridVirtualizer=w,exports.createGroupedVirtualizer=E,exports.createMeasurementCache=t,exports.createReactiveGroupedVirtualizer=O,exports.createReactiveVirtualizer=k,exports.createVirtualScroller=S,exports.createVirtualizer=y;
2
2
  //# sourceMappingURL=scroll.cjs.map