Packages
moon
2.90.2
2.90.5
retired
2.90.4
2.90.3
2.90.2
2.90.1
2.90.0
2.89.4
2.89.1
2.89.0
2.88.0
2.87.11
2.87.10
2.87.9
2.87.8
2.87.7
2.87.6
2.87.5
2.87.4
2.87.3
2.87.2
2.87.1
2.87.0
2.86.1
2.86.0
2.85.1
2.85.0
2.84.0
2.83.0
2.82.0
2.81.4
2.81.3
2.81.2
2.81.1
2.81.0
2.80.2
2.80.1
2.80.0
2.79.13
2.79.12
2.79.11
2.79.10
2.79.9
2.79.8
2.79.7
2.79.6
2.79.5
2.79.4
2.79.3
2.79.2
2.79.1
2.79.0
2.78.4
2.78.3
2.78.2
2.78.1
2.78.0
2.77.0
2.76.5
2.76.4
2.76.3
2.76.2
2.76.1
2.76.0
2.75.0
2.74.1
2.74.0
2.73.8
2.73.7
2.73.6
2.73.5
2.73.4
2.73.3
2.73.2
2.73.1
2.73.0
2.72.5
2.72.4
2.72.3
2.72.2
2.72.1
2.72.0
2.71.1
2.71.0
2.70.0
2.69.2
2.69.1
2.69.0
2.68.11
2.68.10
Components-based design system written in elixir
Current section
Files
Jump to
Current section
Files
assets/node_modules/smooth-scroll-into-view-if-needed/src/index.ts
import scrollIntoView, {
Options,
StandardBehaviorOptions,
CustomBehaviorOptions,
} from 'scroll-into-view-if-needed'
export interface CustomEasing {
(t: number): number
}
type OnScrollChangeCallback = (scrollState: {
target: Element
elapsed: number
value: number
left: number
top: number
}) => void
export interface SmoothBehaviorOptions extends Options {
behavior?: 'smooth'
duration?: number
ease?: CustomEasing
onScrollChange?: OnScrollChangeCallback
}
// Memoize so we're much more friendly to non-dom envs
let memoizedNow: () => number
const now = () => {
if (!memoizedNow) {
memoizedNow =
'performance' in window ? performance.now.bind(performance) : Date.now
}
return memoizedNow()
}
type SmoothScrollAction = {
el: Element
// [start, end] tuples of the distance animated
left: [number, number]
top: [number, number]
}
type Context = {
scrollable: Element
method: (elapsed: number, value: number, x: number, y: number) => void
startTime: number
startX: number
startY: number
x: number
y: number
duration: number
ease: CustomEasing
cb: Function
}
function step(context: Context) {
const time = now()
const elapsed = Math.min((time - context.startTime) / context.duration, 1)
// apply easing to elapsed time
const value = context.ease(elapsed)
const currentX = context.startX + (context.x - context.startX) * value
const currentY = context.startY + (context.y - context.startY) * value
context.method(currentX, currentY, elapsed, value)
// scroll more if we have not reached our destination
if (currentX !== context.x || currentY !== context.y) {
requestAnimationFrame(() => step(context))
} else {
// If nothing left to scroll lets fire the callback
context.cb()
}
}
function smoothScroll(
el: Element,
x: number,
y: number,
duration = 600,
ease: CustomEasing = (t) => 1 + --t * t * t * t * t,
cb: Function,
onScrollChange?: OnScrollChangeCallback
) {
// define scroll context
const scrollable = el
const startX = el.scrollLeft
const startY = el.scrollTop
const method = (x: number, y: number, elapsed: number, value: number) => {
// @TODO use Element.scroll if it exists, as it is potentially better performing
// use ceil to include the the fractional part of the number for the scrolling
const left = Math.ceil(x)
const top = Math.ceil(y)
el.scrollLeft = left
el.scrollTop = top
onScrollChange?.({
target: el,
elapsed,
value,
left,
top,
})
}
// scroll looping over a frame if needed
step({
scrollable: scrollable,
method: method,
startTime: now(),
startX: startX,
startY: startY,
x: x,
y: y,
duration,
ease,
cb,
})
}
const shouldSmoothScroll = <T>(options: any): options is T => {
return (options && !options.behavior) || options.behavior === 'smooth'
}
function scroll(target: Element, options?: SmoothBehaviorOptions): Promise<any>
function scroll<T>(target: Element, options: CustomBehaviorOptions<T>): T
function scroll(target: Element, options: StandardBehaviorOptions): void
function scroll<T>(target: Element, options?: any) {
const overrides = options || {}
if (shouldSmoothScroll<SmoothBehaviorOptions>(overrides)) {
return scrollIntoView<Promise<SmoothScrollAction[]>>(target, {
block: overrides.block,
inline: overrides.inline,
scrollMode: overrides.scrollMode,
boundary: overrides.boundary,
skipOverflowHiddenElements: overrides.skipOverflowHiddenElements,
behavior: (actions) =>
Promise.all(
actions.reduce(
(results: Promise<SmoothScrollAction>[], { el, left, top }) => {
const startLeft = el.scrollLeft
const startTop = el.scrollTop
if (startLeft === left && startTop === top) {
return results
}
return [
...results,
new Promise((resolve) => {
return smoothScroll(
el,
left,
top,
overrides.duration,
overrides.ease,
() =>
resolve({
el,
left: [startLeft, left],
top: [startTop, top],
}),
overrides.onScrollChange
)
}),
]
},
[]
)
),
})
}
return Promise.resolve(scrollIntoView<T>(target, options))
}
// re-assign here makes the flowtype generation work
const smoothScrollIntoView = scroll
export default smoothScrollIntoView