Skip to content

Commit 6472ede

Browse files
committed
fix: always use el.scroll()
1 parent 2587cdb commit 6472ede

File tree

1 file changed

+60
-36
lines changed

1 file changed

+60
-36
lines changed

src/index.ts

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,26 @@ export type Options<T = unknown> =
99
| StandardBehaviorOptions
1010
| CustomBehaviorOptions<T>
1111

12-
/** @public */
12+
/**
13+
* Only scrolls if the `node` is partially out of view:
14+
* ```ts
15+
* scrollIntoView(node, { scrollMode: 'if-needed' })
16+
* ```
17+
* Skips scrolling `overflow: hidden` elements:
18+
* ```ts
19+
* scrollIntoView(node, { skipOverflowHiddenElements: true })
20+
* ```
21+
* When scrolling is needed do the least and smoothest scrolling possible:
22+
* ```ts
23+
* scrollIntoView(node, {
24+
* behavior: 'smooth',
25+
* scrollMode: 'if-needed',
26+
* block: 'nearest',
27+
* inline: 'nearest',
28+
* })
29+
* ```
30+
* @public
31+
*/
1332
export interface StandardBehaviorOptions extends BaseOptions {
1433
/**
1534
* @defaultValue 'auto
@@ -52,51 +71,56 @@ let getOptions = (options: any): StandardBehaviorOptions => {
5271
return { block: 'start', inline: 'nearest' }
5372
}
5473

55-
// Some people might use both "auto" and "ponyfill" modes in the same file, so we also provide a named export so
56-
// that imports in userland code (like if they use native smooth scrolling on some browsers, and the ponyfill for everything else)
57-
// the named export allows this `import {auto as autoScrollIntoView, ponyfill as smoothScrollIntoView} from ...`
58-
/** @public */
59-
export default function scrollIntoView<T>(
60-
target: Element,
61-
options: CustomBehaviorOptions<T>
62-
): T
63-
/** @public */
64-
export default function scrollIntoView(
74+
/**
75+
* Scrolls the given element into view, with options for when, and how.
76+
* Supports the same `options` as [`Element.prototype.scrollIntoView`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) with additions such as `scrollMode`, `behavior: Function` and `skipOverflowHiddenElements`.
77+
* @public
78+
*/
79+
function scrollIntoView(
6580
target: Element,
6681
options?: StandardBehaviorOptions | boolean
6782
): void
68-
/** @public */
69-
export default function scrollIntoView<T = unknown>(
83+
/**
84+
* Scrolls the given element into view, with options for when, and how.
85+
* Supports the same `options` as [`Element.prototype.scrollIntoView`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) with additions such as `scrollMode`, `behavior: Function` and `skipOverflowHiddenElements`.
86+
*
87+
* You can set the expected return type for `behavior: Function`:
88+
* ```ts
89+
* await scrollIntoView<Promise<boolean[]>>(node, {
90+
* behavior: async actions => {
91+
* return Promise.all(actions.map(
92+
* // animate() resolves to `true` if anything was animated, `false` if the element already were in the end state
93+
* ({ el, left, top }) => animate(el, {scroll: {left, top}})
94+
* ))
95+
* }
96+
* })
97+
* ```
98+
* @public
99+
*/
100+
function scrollIntoView<T>(
101+
target: Element,
102+
options: CustomBehaviorOptions<T>
103+
): T
104+
function scrollIntoView<T = unknown>(
70105
target: Element,
71106
options?: StandardBehaviorOptions | CustomBehaviorOptions<T> | boolean
72107
): T | void {
73108
// Browsers treats targets that aren't in the dom as a no-op and so should we
74-
let isTargetAttached =
75-
target.isConnected ||
76-
target.ownerDocument!.documentElement!.contains(target)
109+
if (
110+
!target.isConnected ||
111+
!target.ownerDocument!.documentElement!.contains(target)
112+
) {
113+
return
114+
}
77115

78116
if (isCustomScrollBehavior<T>(options)) {
79-
return options.behavior(isTargetAttached ? compute(target, options) : [])
117+
return options.behavior(compute(target, options))
80118
}
81119

82-
// Don't do anything if using a standard behavior on an element that is not in the document
83-
if (!isTargetAttached) {
84-
return
120+
let behavior = typeof options === 'boolean' ? undefined : options?.behavior
121+
for (let { el, top, left } of compute(target, getOptions(options))) {
122+
el.scroll({ top, left, behavior })
85123
}
86-
87-
// @TODO see if it's possible to avoid this assignment
88-
let computeOptions = getOptions(options)
89-
let actions = compute(target, computeOptions)
90-
let canSmoothScroll = 'scrollBehavior' in document.body.style
91-
92-
actions.forEach(({ el, top, left }) => {
93-
// browser implements the new Element.prototype.scroll API that supports `behavior`
94-
// and guard window.scroll with supportsScrollBehavior
95-
if (el.scroll && canSmoothScroll) {
96-
el.scroll({ top, left, behavior: computeOptions.behavior })
97-
} else {
98-
el.scrollTop = top
99-
el.scrollLeft = left
100-
}
101-
})
102124
}
125+
126+
export default scrollIntoView

0 commit comments

Comments
 (0)