import {clamp} from './clamp';
export type ScrollState = {
offset: number,
length: number,
};
function clampOffset(state: ScrollState, containerLength: number): ScrollState {
return {
offset: clamp(-(state.length - containerLength), 0, state.offset),
length: state.length,
};
}
function clampLength({
state,
minContentLength,
maxContentLength,
containerLength,
}: {
state: ScrollState,
minContentLength: number,
maxContentLength: number,
containerLength: number,
}): ScrollState {
return {
offset: state.offset,
length: clamp(
Math.max(minContentLength, containerLength),
Math.max(containerLength, maxContentLength),
state.length,
),
};
}
export function clampState({
state,
minContentLength,
maxContentLength,
containerLength,
}: {
state: ScrollState,
minContentLength: number,
maxContentLength: number,
containerLength: number,
}): ScrollState {
return clampOffset(
clampLength({
state,
minContentLength,
maxContentLength,
containerLength,
}),
containerLength,
);
}
export function translateState({
state,
delta,
containerLength,
}: {
state: ScrollState,
delta: number,
containerLength: number,
}): ScrollState {
return clampOffset(
{
offset: state.offset + delta,
length: state.length,
},
containerLength,
);
}
export function zoomState({
state,
multiplier,
fixedPoint,
minContentLength,
maxContentLength,
containerLength,
}: {
state: ScrollState,
multiplier: number,
fixedPoint: number,
minContentLength: number,
maxContentLength: number,
containerLength: number,
}): ScrollState {
const zoomedState = clampLength({
state: {
offset: state.offset,
length: state.length * multiplier,
},
minContentLength,
maxContentLength,
containerLength,
});
const fixedPointFromContainer = fixedPoint + state.offset;
const scaledFixedPoint = fixedPoint * (zoomedState.length / state.length);
const offsetAdjustedState = clampOffset(
{
offset: fixedPointFromContainer - scaledFixedPoint,
length: zoomedState.length,
},
containerLength,
);
return offsetAdjustedState;
}
export function moveStateToRange({
state,
rangeStart,
rangeEnd,
contentLength,
minContentLength,
maxContentLength,
containerLength,
}: {
state: ScrollState,
rangeStart: number,
rangeEnd: number,
contentLength: number,
minContentLength: number,
maxContentLength: number,
containerLength: number,
}): ScrollState {
const lengthClampedState = clampLength({
state: {
offset: state.offset,
length: contentLength * (containerLength / (rangeEnd - rangeStart)),
},
minContentLength,
maxContentLength,
containerLength,
});
const offsetAdjustedState = clampOffset(
{
offset: -rangeStart * (lengthClampedState.length / contentLength),
length: lengthClampedState.length,
},
containerLength,
);
return offsetAdjustedState;
}
export function areScrollStatesEqual(
state1: ScrollState,
state2: ScrollState,
): boolean {
return state1.offset === state2.offset && state1.length === state2.length;
}