1- import compute , { Options as ComputeOptions } from './compute'
1+ import compute from './compute'
2+ import {
3+ ScrollBehavior ,
4+ CustomScrollBehaviorCallback ,
5+ CustomScrollAction ,
6+ Options as BaseOptions ,
7+ } from './types'
28
3- export interface Options {
4- behavior ?: 'auto' | 'smooth' | 'instant' | Function
5- scrollMode ?: ComputeOptions [ 'scrollMode' ]
6- boundary ?: ComputeOptions [ 'boundary' ]
7- block ?: ComputeOptions [ 'block' ]
8- inline ?: ComputeOptions [ 'inline' ]
9+ export interface StandardBehaviorOptions extends BaseOptions {
10+ behavior ?: ScrollBehavior
11+ }
12+ export interface CustomBehaviorOptions < T > extends BaseOptions {
13+ behavior : CustomScrollBehaviorCallback < T >
14+ }
15+
16+ export interface Options < T = any > extends BaseOptions {
17+ behavior ?: ScrollBehavior | CustomScrollBehaviorCallback < T >
918}
1019
1120// Wait with checking if native smooth-scrolling exists until scrolling is invoked
1221// This is much more friendly to server side rendering envs, and testing envs like jest
1322let supportsScrollBehavior
1423
15- // Some people might use both "auto" and "ponyfill" modes in the same file, so we also provide a named export so
16- // that imports in userland code (like if they use native smooth scrolling on some browsers, and the ponyfill for everything else)
17- // the named export allows this `import {auto as autoScrollIntoView, ponyfill as smoothScrollIntoView} from ...`
18- export default ( target : Element , maybeOptions : Options | boolean = true ) => {
19- let options : Options = { }
24+ const isFunction = ( arg : any ) : arg is Function => {
25+ return typeof arg == 'function'
26+ }
27+ const isOptionsObject = < T > ( options : any ) : options is T => {
28+ return options === Object ( options ) && Object . keys ( options ) . length !== 0
29+ }
2030
31+ const defaultBehavior = (
32+ actions : CustomScrollAction [ ] ,
33+ behavior : ScrollBehavior = 'auto'
34+ ) => {
2135 if ( supportsScrollBehavior === undefined ) {
2236 supportsScrollBehavior = 'scrollBehavior' in document . documentElement . style
2337 }
2438
25- // Handle alignToTop for legacy reasons, to be compatible with the spec
26- if ( maybeOptions === true || maybeOptions === null ) {
27- options = { block : 'start' , inline : 'nearest' }
28- } else if ( maybeOptions === false ) {
29- options = { block : 'end' , inline : 'nearest' }
30- } else if ( maybeOptions === Object ( maybeOptions ) ) {
31- // @TODO check if passing an empty object is handled like defined by the spec (for now it makes the web platform tests pass)
32- options =
33- Object . keys ( maybeOptions ) . length === 0
34- ? { block : 'start' , inline : 'nearest' }
35- : { block : 'center' , inline : 'nearest' , ...maybeOptions }
36- }
37-
38- const { behavior = 'auto' , ...computeOptions } = options
39- const instructions = compute ( target , computeOptions )
40-
41- if ( typeof behavior == 'function' ) {
42- return behavior ( instructions )
43- }
44-
45- instructions . forEach ( ( { el, top, left } ) => {
39+ actions . forEach ( ( { el, top, left } ) => {
4640 // browser implements the new Element.prototype.scroll API that supports `behavior`
4741 // and guard window.scroll with supportsScrollBehavior
4842 if ( el . scroll && supportsScrollBehavior ) {
@@ -57,3 +51,42 @@ export default (target: Element, maybeOptions: Options | boolean = true) => {
5751 }
5852 } )
5953}
54+
55+ const getOptions = ( options : any = true ) : StandardBehaviorOptions => {
56+ // Handle alignToTop for legacy reasons, to be compatible with the spec
57+ if ( options === true || options === null ) {
58+ return { block : 'start' , inline : 'nearest' }
59+ } else if ( options === false ) {
60+ return { block : 'end' , inline : 'nearest' }
61+ } else if ( isOptionsObject < StandardBehaviorOptions > ( options ) ) {
62+ return { block : 'center' , inline : 'nearest' , ...options }
63+ }
64+
65+ // if options = {}, based on w3c web platform test
66+ return { block : 'start' , inline : 'nearest' }
67+ }
68+
69+ // Some people might use both "auto" and "ponyfill" modes in the same file, so we also provide a named export so
70+ // that imports in userland code (like if they use native smooth scrolling on some browsers, and the ponyfill for everything else)
71+ // the named export allows this `import {auto as autoScrollIntoView, ponyfill as smoothScrollIntoView} from ...`
72+ function scrollIntoView < T > (
73+ target : Element ,
74+ options : CustomBehaviorOptions < T >
75+ ) : T
76+ function scrollIntoView ( target : Element , options ?: Options | boolean ) : void
77+ function scrollIntoView < T > ( target , options : Options < T > | boolean = true ) {
78+ if (
79+ isOptionsObject < CustomBehaviorOptions < T > > ( options ) &&
80+ isFunction ( options . behavior )
81+ ) {
82+ return options . behavior ( compute ( target , options ) )
83+ }
84+
85+ const computeOptions = getOptions ( options )
86+ return defaultBehavior (
87+ compute ( target , computeOptions ) ,
88+ computeOptions . behavior
89+ )
90+ }
91+
92+ export default scrollIntoView
0 commit comments