Skip to content

Commit

Permalink
Handle CSSUnitValue inset and update range measurements on source and…
Browse files Browse the repository at this point in the history
… subject resize
  • Loading branch information
johannesodland committed Dec 18, 2023
1 parent 11301ef commit db7d14b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 46 deletions.
101 changes: 64 additions & 37 deletions src/scroll-timeline-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,23 +564,29 @@ export function calculateRange(phase, container, target, axis, optionsInset) {
const rtl = style.direction == 'rtl' || style.writingMode == 'vertical-rl';
let viewSize = undefined;
let viewPos = undefined;
let containerSize = undefined;
let sizes = {
fontSize: getComputedStyle(target).fontSize
};
if (axis == 'x' ||
(axis == 'inline' && horizontalWritingMode) ||
(axis == 'block' && !horizontalWritingMode)) {
viewSize = target.offsetWidth;
viewPos = left;
if (rtl)
sizes.scrollPadding = [style.scrollPaddingLeft, style.scrollPaddingRight];
if (rtl) {
viewPos += container.scrollWidth - container.clientWidth;
containerSize = container.clientWidth;
sizes.scrollPadding = [style.scrollPaddingRight, style.scrollPaddingLeft];
}
sizes.containerSize = container.clientWidth;
} else {
// TODO: support sideways-lr
viewSize = target.offsetHeight;
viewPos = top;
containerSize = container.clientHeight;
sizes.scrollPadding = [style.scrollPaddingTop, style.scrollPaddingBottom];
sizes.containerSize = container.clientHeight;
}

const inset = parseInset(optionsInset, containerSize);
const inset = parseInset(optionsInset, sizes);

// Cover:
// 0% progress represents the position at which the start border edge of the
Expand All @@ -589,7 +595,7 @@ export function calculateRange(phase, container, target, axis, optionsInset) {
// 100% progress represents the position at which the end border edge of the
// element’s principal box coincides with the start edge of its view progress
// visibility range.
const coverStartOffset = viewPos - containerSize + inset.end;
const coverStartOffset = viewPos - sizes.containerSize + inset.end;
const coverEndOffset = viewPos + viewSize - inset.start;

// Contain:
Expand All @@ -612,7 +618,7 @@ export function calculateRange(phase, container, target, axis, optionsInset) {

let startOffset = undefined;
let endOffset = undefined;
const targetIsTallerThanContainer = viewSize > containerSize ? true : false;
const targetIsTallerThanContainer = viewSize > sizes.containerSize ? true : false;

switch(phase) {
case 'cover':
Expand Down Expand Up @@ -649,39 +655,52 @@ export function calculateRange(phase, container, target, axis, optionsInset) {
return { start: startOffset, end: endOffset };
}

function parseInset(value, containerSize) {
const inset = { start: 0, end: 0 };

if(!value)
return inset;

const parts = value.split(' ');
const insetParts = [];
parts.forEach(part => {
// TODO: Add support for relative lengths (e.g. em)
if(part.endsWith("%"))
insetParts.push(containerSize / 100 * parseFloat(part));
else if(part.endsWith("px"))
insetParts.push(parseFloat(part));
else if(part === "auto")
insetParts.push(0);
else
throw TypeError("Unsupported inset. Only % and px values are supported (for now).");
});

if (insetParts.length > 2) {
throw TypeError("Invalid inset");
function parseInset(value, sizes) {
const inset = {start: 0, end: 0};

if (!value) return inset;

let parts = value;
// Parse string parts to
if (typeof value === 'string') {
parts = value.split(' ').map(part => {
if (part.endsWith('%')) {
return CSS.percent(parseFloat(part));
} else if (part.endsWith('px')) {
return CSS.px(parseFloat(part));
} else if (part.endsWith('em')) {
return CSS.em(parseFloat(part));
} else if (part === 'auto') {
return part;
} else {
throw TypeError('Unsupported inset. Only %, px, em and auto values are supported (for now).');
}
});
}

if(insetParts.length == 1) {
inset.start = insetParts[0];
inset.end = insetParts[0];
} else if(insetParts.length == 2) {
inset.start = insetParts[0];
inset.end = insetParts[1];
if (parts.length === 0 || parts.length > 2) {
throw TypeError('Invalid inset');
}

return inset;
const startPart = parts[0];
const endPart = parts[1] ?? parts[0];

const [start, end] = [startPart, endPart].map((part, i) => {
if (part === 'auto') {
return sizes.scrollPadding[i] === 'auto' ? 0 : parseFloat(sizes.scrollPadding[i]);
}

const simplifiedUnit = simplifyCalculation(part, {
percentageReference: CSS.px(sizes.containerSize),
fontSize: CSS.px(parseFloat(sizes.fontSize))
});
if (simplifiedUnit instanceof CSSUnitValue && simplifiedUnit.unit === 'px') {
return simplifiedUnit.value;
} else {
throw TypeError('Unsupported inset. Only %, px, em and auto values are supported (for now).');
}
});

return {start, end};
}

// Calculate the fractional offset of a (phase, percent) pair relative to the
Expand Down Expand Up @@ -773,4 +792,12 @@ export class ViewTimeline extends ScrollTimeline {
return CSS.percent(100 * progress);
}

get startOffset() {
return CSS.px(scrollTimelineOptions.get(this).ranges['cover'].start);
}

get endOffset() {
return CSS.px(scrollTimelineOptions.get(this).ranges['cover'].end);
}

}
6 changes: 4 additions & 2 deletions src/simplify-calculation.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {isCanonical} from "./utils";

/**
* @typedef {{percentageReference: CSSUnitValue}} Info
* @typedef {{percentageReference: CSSUnitValue, fontSize?: CSSUnitValue}} Info
*/

/**
Expand Down Expand Up @@ -81,7 +81,9 @@ export function simplifyCalculation(root, info) {
root = sum.values[0];
}
// TODO: handle relative lengths

if (root instanceof CSSUnitValue && root.unit === 'em' && info.fontSize) {
root = new CSSUnitValue(root.value * info.fontSize.value, info.fontSize.unit)
}
// 3. If root is a <calc-constant>, return its numeric value.
// 4. Otherwise, return root.
return root;
Expand Down
14 changes: 7 additions & 7 deletions test/expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -933,17 +933,17 @@ FAIL /scroll-animations/view-timelines/timeline-offset-in-keyframe.html Timeline
FAIL /scroll-animations/view-timelines/unattached-subject-inset.html Creating a view timeline with a subject that is not attached to the document works as expected
FAIL /scroll-animations/view-timelines/view-timeline-get-current-time-range-name.html View timeline current time for named range
FAIL /scroll-animations/view-timelines/view-timeline-get-set-range.html Getting and setting the animation range
FAIL /scroll-animations/view-timelines/view-timeline-inset.html View timeline with px based inset.
FAIL /scroll-animations/view-timelines/view-timeline-inset.html View timeline with percent based inset.
FAIL /scroll-animations/view-timelines/view-timeline-inset.html view timeline with inset auto.
FAIL /scroll-animations/view-timelines/view-timeline-inset.html view timeline with font relative inset.
PASS /scroll-animations/view-timelines/view-timeline-inset.html View timeline with px based inset.
PASS /scroll-animations/view-timelines/view-timeline-inset.html View timeline with percent based inset.
PASS /scroll-animations/view-timelines/view-timeline-inset.html view timeline with inset auto.
PASS /scroll-animations/view-timelines/view-timeline-inset.html view timeline with font relative inset.
FAIL /scroll-animations/view-timelines/view-timeline-inset.html view timeline with viewport relative insets.
FAIL /scroll-animations/view-timelines/view-timeline-inset.html view timeline inset as string
PASS /scroll-animations/view-timelines/view-timeline-inset.html view timeline inset as string
PASS /scroll-animations/view-timelines/view-timeline-inset.html view timeline with invalid inset
PASS /scroll-animations/view-timelines/view-timeline-missing-subject.html ViewTimeline with missing subject
PASS /scroll-animations/view-timelines/view-timeline-on-display-none-element.html element with display: none should have inactive viewtimeline
PASS /scroll-animations/view-timelines/view-timeline-range-large-subject.html View timeline with range set via delays.
FAIL /scroll-animations/view-timelines/view-timeline-range.html View timeline with range as <name> <percent> pair.
PASS /scroll-animations/view-timelines/view-timeline-range.html View timeline with range as <name> <percent> pair.
PASS /scroll-animations/view-timelines/view-timeline-range.html View timeline with range and inferred name or offset.
PASS /scroll-animations/view-timelines/view-timeline-range.html View timeline with range as <name> <px> pair.
PASS /scroll-animations/view-timelines/view-timeline-range.html View timeline with range as <name> <percent+px> pair.
Expand All @@ -957,4 +957,4 @@ FAIL /scroll-animations/view-timelines/view-timeline-sticky-block.html View time
FAIL /scroll-animations/view-timelines/view-timeline-sticky-inline.html View timeline with sticky target, block axis.
FAIL /scroll-animations/view-timelines/view-timeline-subject-size-changes.html View timeline with subject size change after the creation of the animation
FAIL /scroll-animations/view-timelines/zero-intrinsic-iteration-duration.tentative.html Intrinsic iteration duration is non-negative
Passed 394 of 959 tests.
Passed 400 of 959 tests.

0 comments on commit db7d14b

Please sign in to comment.