• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

humanspeak / svelte-virtual-list / 27078076147

03 Jun 2026 01:02AM UTC coverage: 73.275% (+5.7%) from 67.565%
27078076147

push

github

web-flow
build(docs): update docs-kit to 2026.6.5 (#403)

* build(docs): update docs-kit to 2026.6.5

* build: refresh pnpm 11 tooling updates

- Use pnpm/action-setup v6 across CI workflows
- Declare pnpm 11.5.0 as the package manager
- Refresh package versions, lockfile, and Wrangler types

* Missed a spot

384 of 573 branches covered (67.02%)

Branch coverage included in aggregate %.

710 of 920 relevant lines covered (77.17%)

488.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.43
/src/lib/utils/scrollCalculation.ts
1
import type { SvelteVirtualListScrollAlign } from '$lib/types.js'
2
import { clampValue, getScrollOffsetForIndex } from './virtualList.js'
3

4
/**
5
 * Calculates the scroll target for aligning an item to a specific edge.
6
 *
7
 * @param {number} itemTop - The top position of the item in pixels
8
 * @param {number} itemBottom - The bottom position of the item in pixels
9
 * @param {number} scrollTop - Current scroll position in pixels
10
 * @param {number} viewportHeight - Height of the viewport in pixels
11
 * @param {'top' | 'bottom' | 'nearest'} align - The alignment mode
12
 * @returns {number | null} The scroll target position, or null if item is already visible (for 'nearest')
13
 */
14
export const alignToEdge = (
4✔
15
    itemTop: number,
16
    itemBottom: number,
17
    scrollTop: number,
18
    viewportHeight: number,
19
    align: 'top' | 'bottom' | 'nearest'
20
): number | null => {
21
    if (align === 'top') {
29✔
22
        return itemTop
9✔
23
    }
24

25
    if (align === 'bottom') {
20✔
26
        return clampValue(itemBottom - viewportHeight, 0, Infinity)
10✔
27
    }
28

29
    // 'nearest' alignment
30
    const viewportBottom = scrollTop + viewportHeight
10✔
31
    const isVisible = itemTop < viewportBottom && itemBottom > scrollTop
10✔
32

33
    if (isVisible) {
29✔
34
        // Already visible, no scroll needed
35
        return null
6✔
36
    }
37

38
    // Not visible - align to nearest edge
39
    const distanceToTop = Math.abs(scrollTop - itemTop)
4✔
40
    const distanceToBottom = Math.abs(viewportBottom - itemBottom)
4✔
41

42
    return distanceToTop < distanceToBottom
4✔
43
        ? itemTop
44
        : clampValue(itemBottom - viewportHeight, 0, Infinity)
45
}
46

47
/**
48
 * Calculates the scroll target for aligning a visible item to its nearest edge.
49
 *
50
 * Unlike alignToEdge with 'nearest', this always returns a scroll position
51
 * even when the item is visible. Used for 'auto' alignment mode when item
52
 * is within the visible range.
53
 *
54
 * @param {number} itemTop - The top position of the item in pixels
55
 * @param {number} itemBottom - The bottom position of the item in pixels
56
 * @param {number} scrollTop - Current scroll position in pixels
57
 * @param {number} viewportHeight - Height of the viewport in pixels
58
 * @returns {number} The scroll target position aligned to nearest edge
59
 *
60
 * @example
61
 * ```typescript
62
 * // For a visible item, align to whichever edge is closer
63
 * const scrollTarget = alignVisibleToNearestEdge(400, 450, 200, 400)
64
 * viewportElement.scrollTo({ top: scrollTarget })
65
 * ```
66
 */
67
export const alignVisibleToNearestEdge = (
4✔
68
    itemTop: number,
69
    itemBottom: number,
70
    scrollTop: number,
71
    viewportHeight: number
72
): number => {
73
    const viewportBottom = scrollTop + viewportHeight
16✔
74
    const distanceToTop = Math.abs(scrollTop - itemTop)
16✔
75
    const distanceToBottom = Math.abs(viewportBottom - itemBottom)
16✔
76

77
    return distanceToTop < distanceToBottom
16✔
78
        ? itemTop
79
        : clampValue(itemBottom - viewportHeight, 0, Infinity)
80
}
81

82
/**
83
 * Parameters for calculating scroll target position
84
 */
85
export interface ScrollTargetParams {
86
    align: SvelteVirtualListScrollAlign
87
    targetIndex: number
88
    itemsLength: number
89
    calculatedItemHeight: number
90
    height: number
91
    scrollTop: number
92
    firstVisibleIndex: number
93
    lastVisibleIndex: number
94
    heightCache: Record<number, number>
95
}
96

97
/**
98
 * Calculates the target scroll position for scrolling to a specific item index.
99
 *
100
 * This function handles different alignment options (auto, top, bottom, nearest)
101
 * and calculates the optimal scroll position based on the current viewport state.
102
 *
103
 * @param params - Parameters for scroll target calculation
104
 * @returns The target scroll position in pixels, or null if no scroll is needed
105
 *
106
 * @example
107
 * ```typescript
108
 * const scrollTarget = calculateScrollTarget({
109
 *     align: 'auto',
110
 *     targetIndex: 100,
111
 *     itemsLength: 1000,
112
 *     calculatedItemHeight: 50,
113
 *     height: 400,
114
 *     scrollTop: 200,
115
 *     firstVisibleIndex: 4,
116
 *     lastVisibleIndex: 12,
117
 *     heightCache: {}
118
 * })
119
 *
120
 * if (scrollTarget !== null) {
121
 *     viewportElement.scrollTo({ top: scrollTarget })
122
 * }
123
 * ```
124
 */
125
export const calculateScrollTarget = (params: ScrollTargetParams): number | null => {
4✔
126
    const {
127
        align,
128
        targetIndex,
129
        calculatedItemHeight,
130
        height,
131
        scrollTop,
132
        firstVisibleIndex,
133
        lastVisibleIndex,
134
        heightCache
135
    } = params
14✔
136

137
    return calculateTopToBottomScrollTarget({
14✔
138
        align,
139
        targetIndex,
140
        calculatedItemHeight,
141
        height,
142
        scrollTop,
143
        firstVisibleIndex,
144
        lastVisibleIndex,
145
        heightCache
146
    })
147
}
148

149
/**
150
 * Parameters for scroll calculation.
151
 *
152
 * @interface TopToBottomScrollParams
153
 */
154
interface TopToBottomScrollParams {
155
    /** Alignment mode for the target item. */
156
    align: SvelteVirtualListScrollAlign
157
    /** Index of the item to scroll to. */
158
    targetIndex: number
159
    /** Calculated average height of items in pixels. */
160
    calculatedItemHeight: number
161
    /** Height of the viewport in pixels. */
162
    height: number
163
    /** Current scroll position in pixels. */
164
    scrollTop: number
165
    /** Index of the first visible item. */
166
    firstVisibleIndex: number
167
    /** Index of the last visible item. */
168
    lastVisibleIndex: number
169
    /** Cache of measured item heights. */
170
    heightCache: Record<number, number>
171
}
172

173
/**
174
 * Calculates the target scroll position for top-to-bottom mode.
175
 *
176
 * This is the standard scroll mode where items are rendered from the top of the
177
 * viewport downward. The function calculates the optimal scroll position based
178
 * on the alignment option and current viewport state.
179
 *
180
 * @param {TopToBottomScrollParams} params - Parameters for scroll calculation.
181
 * @returns {number | null} The target scroll position in pixels, or null if no
182
 *     scroll is needed (item already visible with 'nearest' alignment).
183
 */
184
const calculateTopToBottomScrollTarget = (params: TopToBottomScrollParams): number | null => {
4✔
185
    const {
186
        align,
187
        targetIndex,
188
        calculatedItemHeight,
189
        height,
190
        scrollTop,
191
        firstVisibleIndex,
192
        lastVisibleIndex,
193
        heightCache
194
    } = params
14✔
195

196
    // Calculate item boundaries
197
    const itemTop = getScrollOffsetForIndex(heightCache, calculatedItemHeight, targetIndex)
14✔
198
    const itemBottom = getScrollOffsetForIndex(heightCache, calculatedItemHeight, targetIndex + 1)
14✔
199

200
    if (align === 'auto') {
14✔
201
        // If item is above the viewport, align to top
202
        if (targetIndex < firstVisibleIndex) {
9✔
203
            return alignToEdge(itemTop, itemBottom, scrollTop, height, 'top')
1✔
204
        }
205
        // If item is below the viewport, align to bottom
206
        else if (targetIndex > lastVisibleIndex - 1) {
8✔
207
            return alignToEdge(itemTop, itemBottom, scrollTop, height, 'bottom')
3✔
208
        } else {
209
            // Item is visible - align to nearest edge (always returns a value)
210
            return alignVisibleToNearestEdge(itemTop, itemBottom, scrollTop, height)
5✔
211
        }
212
    }
213

214
    if (align === 'top' || align === 'bottom' || align === 'nearest') {
5!
215
        return alignToEdge(itemTop, itemBottom, scrollTop, height, align)
5✔
216
    }
217

218
    return null
×
219
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc