diff --git a/dist/index.cjs b/dist/index.cjs index d409f97..17290c8 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -85,6 +85,16 @@ function debounce (fn, interval) { }; } +/** + * parses offsetString of the format calc( + ) + * @param {string|undefined} offsetString + * @param {AbsoluteOffsetContext} absoluteOffsetContext + */ +function parseOffsetCalc(offsetString, absoluteOffsetContext) { + const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); + return transformAbsoluteOffsetToNumber(match[1], absoluteOffsetContext) + transformAbsoluteOffsetToNumber(match[6], absoluteOffsetContext); +} + /** * Convert an absolute offset as string to number of pixels * @@ -100,7 +110,9 @@ function transformAbsoluteOffsetToNumber (offsetString, absoluteOffsetContext) { ? parseInt(offsetString) * absoluteOffsetContext.viewportHeight / 100 : /^-?\d+vw$/.test(offsetString) ? parseInt(offsetString) * absoluteOffsetContext.viewportWidth / 100 - : parseInt(offsetString) || 0 + : /^calc\s*\(\s*-?\d+((px)|(vh)|(vw))\s*\+\s*-?\d+((px)|(vh)|(vw))\s*\)\s*$/.test(offsetString) + ? parseOffsetCalc(offsetString) + : parseInt(offsetString) || 0 : 0; } @@ -137,6 +149,10 @@ function transformRangeToPosition (range, viewportSize, rect) { startPosition = Math.max(start, end - viewportSize); duration = Math.min(viewportSize, height); } + else if (name === 'exit-crossing') { + startPosition = start; + duration = height; + } else if (name === 'cover') { startPosition = start - viewportSize; duration = height + viewportSize; @@ -218,6 +234,7 @@ function computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absolut } } }); + return newAbsoluteRange; } @@ -244,28 +261,38 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, if (typeof duration === 'string') { startRange = { name: duration, offset: 0 }; endRange = { name: duration, offset: 100 }; + startOffset = transformRangeToPosition(startRange, viewportSize, rect); endOffset = transformRangeToPosition(endRange, viewportSize, rect); overrideDuration = endOffset - startOffset; + const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, startOffset, endOffset, viewportSize, isHorizontal); + startOffset = newAbsoluteRange.start; endOffset = newAbsoluteRange.end; } else { if (startRange || start?.name) { startRange = startRange || start; + const startAdd = transformAbsoluteOffsetToNumber(startRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...startRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...startRange, offset: 100}, viewportSize, rect); + // we take 0% to 100% of the named range for start, and we compute the position by adding the sticky addition for the given start offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); + startOffset = newAbsoluteRange.start + (startRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + startAdd; } + if (endRange || end?.name) { endRange = endRange || end; + const endAdd = transformAbsoluteOffsetToNumber(endRange.add, absoluteOffsetContext); const absoluteStartOffset = transformRangeToPosition({...endRange, offset: 0}, viewportSize, rect); const absoluteEndOffset = transformRangeToPosition({...endRange, offset: 100}, viewportSize, rect); + // we take 0% to 100% of the named range for end, and we compute the position by adding the sticky addition for the given end offset const newAbsoluteRange = computeStickinessIntoFullRange(offsetTree, absoluteStartOffset, absoluteEndOffset, viewportSize, isHorizontal); + endOffset = newAbsoluteRange.start + (endRange.offset / 100) * (newAbsoluteRange.end - newAbsoluteRange.start) + endAdd; } else if (typeof duration === 'number') { @@ -273,7 +300,7 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, } } - return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration }; + return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration || (endOffset - startOffset) }; } /** @@ -355,15 +382,15 @@ function getStickyData (style, isHorizontal) { /** * Returns a converted scene data from ranges into offsets in pixels. * - * @param {ScrollScene} scene + * @param {ScrollScene[]} scene * @param {Window|HTMLElement} root * @param {number} viewportSize * @param {boolean} isHorizontal * @param {AbsoluteOffsetContext} absoluteOffsetContext - * @return {ScrollScene} + * @return {ScrollScene[]} */ -function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteOffsetContext) { - const element = scene.viewSource; +function getTransformedSceneGroup (scenes, root, viewportSize, isHorizontal, absoluteOffsetContext) { + const element = scenes[0].viewSource; const elementStyle = window.getComputedStyle(element); const isElementSticky = getIsSticky(elementStyle); const elementStickiness = isElementSticky ? getStickyData(elementStyle, isHorizontal) : undefined; @@ -417,19 +444,17 @@ function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteO offsetTree.reverse(); - const transformedScene = transformSceneRangesToOffsets( + const transformedScenes = scenes.map(scene => transformSceneRangesToOffsets( scene, {start: elementLayoutStart, end: elementLayoutStart + size}, viewportSize, isHorizontal, absoluteOffsetContext, offsetTree - ); + )); + transformedScenes.forEach(scene => {scene.isFixed = isFixed;}); - transformedScene.isFixed = isFixed; - - - return transformedScene; + return transformedScenes; } const VIEWPORT_RESIZE_INTERVAL = 100; @@ -523,45 +548,58 @@ function getController (config) { /* * Prepare scenes data. */ - _config.scenes = config.scenes.map((scene, index) => { - scene.index = index; - - if (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)) { - scene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + _config.scenes = Object.values( + config.scenes.reduce((acc, scene, index) => { + const key = scene.groupId || String(index); + if (acc[key]) { + acc[key].push(scene); + } else { + acc[key] = [scene]; + } + return acc; + }, + {}) + ).flatMap(sceneGroup => { + if (sceneGroup.every(scene => (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)))) { + sceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); if (_config.observeSourcesResize) { - rangesToObserve.push(scene); + rangesToObserve.push(sceneGroup); } - } - else if (scene.end == null) { - scene.end = scene.start + scene.duration; - } - - if (scene.duration == null) { - scene.duration = scene.end - scene.start; + } else { + sceneGroup.forEach(scene => { + if (scene.end == null) { + scene.end = scene.start + scene.duration; + } + if (scene.duration == null) { + scene.duration = scene.end - scene.start; + } + }); } - return scene; + return sceneGroup; }); + _config.scenes.forEach((scene, index) => {scene.index = index;}); if (rangesToObserve.length) { if (window.ResizeObserver) { - const targetToScene = new Map(); + const targetToSceneGroup = new Map(); rangesResizeObserver = new window.ResizeObserver(function (entries) { entries.forEach(entry => { - const scene = targetToScene.get(entry.target); + const sceneGroup = targetToSceneGroup.get(entry.target); // TODO: try to optimize by using `const {blockSize, inlineSize} = entry.borderBoxSize[0]` - _config.scenes[scene.index] = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + const transformedSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + transformedSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = transformedSceneGroup[localIndex];}); // replace the old object from the cache with the new one - rangesToObserve.splice(rangesToObserve.indexOf(scene), 1, _config.scenes[scene.index]); + rangesToObserve.splice(rangesToObserve.indexOf(sceneGroup), 1, transformedSceneGroup); }); }); - rangesToObserve.forEach(scene => { - rangesResizeObserver.observe(scene.viewSource, {box: 'border-box'}); - targetToScene.set(scene.viewSource, scene); + rangesToObserve.forEach(sceneGroup => { + rangesResizeObserver.observe(sceneGroup[0].viewSource, {box: 'border-box'}); + targetToSceneGroup.set(sceneGroup[0].viewSource, sceneGroup); }); } @@ -569,12 +607,11 @@ function getController (config) { viewportResizeHandler = debounce(function () { viewportSize = getViewportSize(root, horizontal); - const newRanges = rangesToObserve.map(scene => { - const newScene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); - - _config.scenes[scene.index] = newScene; + const newRanges = rangesToObserve.map(sceneGroup => { + const newSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + newSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = newSceneGroup[localIndex];}); - return newScene; + return newSceneGroup; }); // reset cache @@ -912,6 +949,8 @@ class Scroll { * @property {boolean} [disabled] whether to perform updates on the scene. Defaults to false. * @property {Element} [viewSource] an element to be used for observing intersection with viewport for disabling/enabling the scene, or the source of a ViewTimeline if scene start/end are provided as ranges. * @property {function} [destroy] a function clean up the scene when it's controller is destroyed. + * @property {string} [groupId] a string id to group together scenes + * @property {Promise} [ready] a promise that is resolved once the effects are ready. */ /** diff --git a/docs/reference/index.html b/docs/reference/index.html index 7b82862..0b036fa 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -323,7 +323,7 @@

fizban

  • - getTransformedScene + getTransformedSceneGroup @@ -2659,7 +2659,7 @@

    - getTransformedScene + getTransformedSceneGroup

    @@ -2668,7 +2668,7 @@

    Returns a converted scene data from ranges into offsets in pixels.

    -
    getTransformedScene(scene: ScrollScene, root: (Window | HTMLElement), viewportSize: number, isHorizontal: boolean, absoluteOffsetContext: AbsoluteOffsetContext): ScrollScene
    +
    getTransformedSceneGroup(scene: ScrollScene, root: (Window | HTMLElement), viewportSize: number, isHorizontal: boolean, absoluteOffsetContext: AbsoluteOffsetContext): ScrollScene
    diff --git a/src/Scroll.js b/src/Scroll.js index bde320a..1465ebd 100644 --- a/src/Scroll.js +++ b/src/Scroll.js @@ -213,6 +213,8 @@ export class Scroll { * @property {boolean} [disabled] whether to perform updates on the scene. Defaults to false. * @property {Element} [viewSource] an element to be used for observing intersection with viewport for disabling/enabling the scene, or the source of a ViewTimeline if scene start/end are provided as ranges. * @property {function} [destroy] a function clean up the scene when it's controller is destroyed. + * @property {string} [groupId] a string id to group together scenes + * @property {Promise} [ready] a promise that is resolved once the effects are ready. */ /** diff --git a/src/controller.js b/src/controller.js index 0807b7e..7bed6e6 100644 --- a/src/controller.js +++ b/src/controller.js @@ -1,5 +1,5 @@ import { debounce, defaultTo } from './utilities.js'; -import { getTransformedScene } from './view.js'; +import { getTransformedSceneGroup } from './view.js'; const VIEWPORT_RESIZE_INTERVAL = 100; @@ -92,45 +92,58 @@ export function getController (config) { /* * Prepare scenes data. */ - _config.scenes = config.scenes.map((scene, index) => { - scene.index = index; - - if (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)) { - scene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + _config.scenes = Object.values( + config.scenes.reduce((acc, scene, index) => { + const key = scene.groupId || String(index); + if (acc[key]) { + acc[key].push(scene) + } else { + acc[key] = [scene]; + } + return acc; + }, + {}) + ).flatMap(sceneGroup => { + if (sceneGroup.every(scene => (scene.viewSource && (typeof scene.duration === 'string' || scene.start?.name)))) { + sceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); if (_config.observeSourcesResize) { - rangesToObserve.push(scene); + rangesToObserve.push(sceneGroup); } - } - else if (scene.end == null) { - scene.end = scene.start + scene.duration; - } - - if (scene.duration == null) { - scene.duration = scene.end - scene.start; + } else { + sceneGroup.forEach(scene => { + if (scene.end == null) { + scene.end = scene.start + scene.duration; + } + if (scene.duration == null) { + scene.duration = scene.end - scene.start; + } + }); } - return scene; + return sceneGroup; }); + _config.scenes.forEach((scene, index) => {scene.index = index;}) if (rangesToObserve.length) { if (window.ResizeObserver) { - const targetToScene = new Map(); + const targetToSceneGroup = new Map(); rangesResizeObserver = new window.ResizeObserver(function (entries) { entries.forEach(entry => { - const scene = targetToScene.get(entry.target); + const sceneGroup = targetToSceneGroup.get(entry.target); // TODO: try to optimize by using `const {blockSize, inlineSize} = entry.borderBoxSize[0]` - _config.scenes[scene.index] = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); + const transformedSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + transformedSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = transformedSceneGroup[localIndex];}); // replace the old object from the cache with the new one - rangesToObserve.splice(rangesToObserve.indexOf(scene), 1, _config.scenes[scene.index]); + rangesToObserve.splice(rangesToObserve.indexOf(sceneGroup), 1, transformedSceneGroup); }) }); - rangesToObserve.forEach(scene => { - rangesResizeObserver.observe(scene.viewSource, {box: 'border-box'}); - targetToScene.set(scene.viewSource, scene); + rangesToObserve.forEach(sceneGroup => { + rangesResizeObserver.observe(sceneGroup[0].viewSource, {box: 'border-box'}); + targetToSceneGroup.set(sceneGroup[0].viewSource, sceneGroup); }); } @@ -138,12 +151,11 @@ export function getController (config) { viewportResizeHandler = debounce(function () { viewportSize = getViewportSize(root, horizontal); - const newRanges = rangesToObserve.map(scene => { - const newScene = getTransformedScene(scene, root, viewportSize, horizontal, absoluteOffsetContext); - - _config.scenes[scene.index] = newScene; + const newRanges = rangesToObserve.map(sceneGroup => { + const newSceneGroup = getTransformedSceneGroup(sceneGroup, root, viewportSize, horizontal, absoluteOffsetContext); + newSceneGroup.forEach((scene, localIndex) => {_config.scenes[scene.index] = newSceneGroup[localIndex];}); - return newScene; + return newSceneGroup; }); // reset cache diff --git a/src/view.js b/src/view.js index 8301c0f..c969535 100644 --- a/src/view.js +++ b/src/view.js @@ -1,3 +1,13 @@ +/** + * parses offsetString of the format calc( + ) + * @param {string|undefined} offsetString + * @param {AbsoluteOffsetContext} absoluteOffsetContext + */ +function parseOffsetCalc(offsetString, absoluteOffsetContext) { + const match = offsetString.match(/^calc\s*\(\s*(-?\d+((px)|(vh)|(vw)))\s*\+\s*(-?\d+((px)|(vh)|(vw)))\s*\)\s*$/); + return transformAbsoluteOffsetToNumber(match[1], absoluteOffsetContext) + transformAbsoluteOffsetToNumber(match[6], absoluteOffsetContext); +} + /** * Convert an absolute offset as string to number of pixels * @@ -13,7 +23,9 @@ function transformAbsoluteOffsetToNumber (offsetString, absoluteOffsetContext) { ? parseInt(offsetString) * absoluteOffsetContext.viewportHeight / 100 : /^-?\d+vw$/.test(offsetString) ? parseInt(offsetString) * absoluteOffsetContext.viewportWidth / 100 - : parseInt(offsetString) || 0 + : /^calc\s*\(\s*-?\d+((px)|(vh)|(vw))\s*\+\s*-?\d+((px)|(vh)|(vw))\s*\)\s*$/.test(offsetString) + ? parseOffsetCalc(offsetString, absoluteOffsetContext) + : parseInt(offsetString) || 0 : 0; } @@ -50,6 +62,10 @@ function transformRangeToPosition (range, viewportSize, rect) { startPosition = Math.max(start, end - viewportSize); duration = Math.min(viewportSize, height); } + else if (name === 'exit-crossing') { + startPosition = start; + duration = height; + } else if (name === 'cover') { startPosition = start - viewportSize; duration = height + viewportSize; @@ -197,7 +213,7 @@ function transformSceneRangesToOffsets (scene, rect, viewportSize, isHorizontal, } } - return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration }; + return {...scene, start: startOffset, end: endOffset, startRange, endRange, duration: overrideDuration || duration || (endOffset - startOffset) }; } /** @@ -279,15 +295,15 @@ function getStickyData (style, isHorizontal) { /** * Returns a converted scene data from ranges into offsets in pixels. * - * @param {ScrollScene} scene + * @param {ScrollScene[]} scene * @param {Window|HTMLElement} root * @param {number} viewportSize * @param {boolean} isHorizontal * @param {AbsoluteOffsetContext} absoluteOffsetContext - * @return {ScrollScene} + * @return {ScrollScene[]} */ -export function getTransformedScene (scene, root, viewportSize, isHorizontal, absoluteOffsetContext) { - const element = scene.viewSource; +export function getTransformedSceneGroup (scenes, root, viewportSize, isHorizontal, absoluteOffsetContext) { + const element = scenes[0].viewSource; const elementStyle = window.getComputedStyle(element); const isElementSticky = getIsSticky(elementStyle); const elementStickiness = isElementSticky ? getStickyData(elementStyle, isHorizontal) : undefined; @@ -341,17 +357,16 @@ export function getTransformedScene (scene, root, viewportSize, isHorizontal, ab offsetTree.reverse(); - const transformedScene = transformSceneRangesToOffsets( + const transformedScenes = scenes.map(scene => transformSceneRangesToOffsets( scene, {start: elementLayoutStart, end: elementLayoutStart + size}, viewportSize, isHorizontal, absoluteOffsetContext, offsetTree - ); - - transformedScene.isFixed = isFixed; + )); + transformedScenes.forEach(scene => {scene.isFixed = isFixed;}) - return transformedScene; + return transformedScenes; } diff --git a/test/Scroll.spec.js b/test/Scroll.spec.js index 3b2d059..784a809 100644 --- a/test/Scroll.spec.js +++ b/test/Scroll.spec.js @@ -142,6 +142,77 @@ test('start :: effect progress :: view ranges', t => { t.is(progress, 1); }); +test('start :: effect progress :: view ranges :: sceneGroup', t => { + const element = { + offsetHeight: 100, + offsetTop: 100, + offsetParent: { + offsetTop: 200, + offsetParent: { + offsetTop: 0 + } + } + }; + + let progress = [0, 0]; + + const scroll = new Scroll({ + root: window, + scenes: [ + { + effect(s, p) { + progress[0] = p; + }, + start: {name: 'entry', offset: 50}, // 275 + end: {name: 'contain', offset: 50}, // 325 + viewSource: element, + groupId: 'awesomeGroup' + }, + { + effect(s, p) { + progress[1] = p; + }, + start: {name: 'cover', offset: 0}, // 250 + end: {name: 'exit', offset: 75}, // 387.5 + viewSource: element, + groupId: 'awesomeGroup' + } + ] + }); + + scroll.start(); + + window.scrollTo(0, 250); + window.executeAnimationFrame(0); + + t.is(progress[0], 0); + t.is(progress[1], 0); + + window.scrollTo(0, 285); + window.executeAnimationFrame(1); + + t.is(progress[0], 0.2); + t.is(+progress[1].toFixed(3), 0.255); + + window.scrollTo(0, 300); + window.executeAnimationFrame(2); + + t.is(progress[0], 0.5); + t.is(+progress[1].toFixed(3), 0.364); + + window.scrollTo(0, 325); + window.executeAnimationFrame(3); + + t.is(progress[0], 1); + t.is(+progress[1].toFixed(3), 0.545); + + window.scrollTo(0, 390); + window.executeAnimationFrame(3); + + t.is(progress[0], 1); + t.is(progress[1], 1); +}); + test('start :: effect progress :: view ranges :: add absolute offsets', t => { const element = { offsetHeight: 100, diff --git a/test/view.spec.js b/test/view.spec.js index eb031dc..84ac813 100644 --- a/test/view.spec.js +++ b/test/view.spec.js @@ -1,6 +1,6 @@ import test from 'ava'; import './mocks.js'; -import { getTransformedScene } from '../src/view.js'; +import { getTransformedSceneGroup } from '../src/view.js'; const VIEWPORT_SIZE = 200; const SMALLER_VIEWPORT_SIZE = 50; @@ -28,7 +28,7 @@ test('duration :: entry', t => { duration: 'entry' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -200); t.is(result.end, -50); @@ -43,7 +43,7 @@ test('duration :: contain', t => { duration: 'contain' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -50); t.is(result.end, 0); @@ -58,7 +58,7 @@ test('duration :: exit', t => { duration: 'exit' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, 0); t.is(result.end, 150); @@ -73,7 +73,7 @@ test('duration :: entry :: larger than viewport', t => { duration: 'entry'} ); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -50); t.is(result.end, 0); @@ -88,7 +88,7 @@ test('duration :: contain :: larger than viewport', t => { duration: 'contain' }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, 0); t.is(result.end, 100); @@ -103,7 +103,7 @@ test('duration :: exit :: larger than viewport', t => { duration: 'exit' }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, 100); t.is(result.end, 150); @@ -118,7 +118,7 @@ test('duration :: cover', t => { duration: 'cover' }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -200); t.is(result.end, 150); @@ -134,7 +134,7 @@ test('start :: entry 40% & contain 60%', t => { end: {name: 'contain', offset: 60} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140); t.is(result.end, -20); @@ -150,7 +150,7 @@ test('start :: entry 40% :: end exit 60%', t => { end: {name: 'exit', offset: 60} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140); t.is(result.end, 90); @@ -166,7 +166,7 @@ test('start :: entry 40% - 50px :: end exit 60% + 50px', t => { end: {name: 'exit', offset: 60, add: '50px'} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -190); t.is(result.end, 140); @@ -182,7 +182,7 @@ test('start :: entry 40% - 20vh :: end exit 60% + 20vw', t => { end: {name: 'exit', offset: 60, add: '20vw'} }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140 + parseInt(-20 / 100 * absoluteOffsetContext.viewportHeight)); t.is(result.end, 90 + parseInt(20 / 100 * absoluteOffsetContext.viewportWidth)); @@ -198,7 +198,7 @@ test('start :: entry 40% :: duration 160px', t => { duration: 160 }); - const result = getTransformedScene(input, null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -140); t.is(result.end, 20); @@ -214,7 +214,7 @@ test('start :: entry 40% & contain 60% :: larger than viewport', t => { end: {name: 'contain', offset: 60} }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -30); t.is(result.end, 60); @@ -230,7 +230,7 @@ test('start :: entry 40% :: end exit 60% :: larger than viewport', t => { end: {name: 'exit', offset: 60} }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -30); t.is(result.end, 130); @@ -246,7 +246,7 @@ test('start :: entry 40% :: duration 160px :: larger than viewport', t => { duration: 160 }); - const result = getTransformedScene(input, null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext); + const result = getTransformedSceneGroup([input], null, SMALLER_VIEWPORT_SIZE, IS_HORIZONTAL, absoluteOffsetContext)[0]; t.is(result.start, -30); t.is(result.end, 130); diff --git a/types.d.ts b/types.d.ts index f8b0df8..d5deebb 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,4 +1,4 @@ -declare type RangeName = 'entry' | 'exit' | 'contain' | 'cover'; +declare type RangeName = 'entry' | 'exit' | 'contain' | 'cover' | 'entry-crossing' | 'exit-crossing'; declare type RangeOffset = { name?: RangeName; @@ -6,7 +6,7 @@ declare type RangeOffset = { }; declare type scrollConfig = { - scenes: ScrollScene; + scenes: ScrollScene[]; transitionActive?: boolean; transitionFriction?: number; } @@ -18,6 +18,8 @@ declare type ScrollScene = { end?: RangeOffset; disabled?: boolean; viewSource?: HTMLElement; + groupId?: string; + ready?: Promise; } declare module "fizban";