@base-ui-components/react
Version:
Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.
134 lines (133 loc) • 5.22 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.resolveThumbCollision = resolveThumbCollision;
var _clamp = require("../../utils/clamp");
var _getPushedThumbValues = require("./getPushedThumbValues");
function resolveThumbCollision({
behavior,
values,
currentValues,
initialValues,
pressedIndex,
nextValue,
min,
max,
step,
minStepsBetweenValues
}) {
const activeValues = currentValues ?? values;
const baselineValues = initialValues ?? values;
const range = activeValues.length > 1;
if (!range) {
return {
value: nextValue,
thumbIndex: 0,
didSwap: false
};
}
const minValueDifference = step * minStepsBetweenValues;
switch (behavior) {
case 'swap':
{
const pressedInitialValue = activeValues[pressedIndex];
const epsilon = 1e-7;
const candidateValues = activeValues.slice();
const previousNeighbor = candidateValues[pressedIndex - 1];
const nextNeighbor = candidateValues[pressedIndex + 1];
const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
const constrainedValue = (0, _clamp.clamp)(nextValue, lowerBound, upperBound);
const pressedValueAfterClamp = Number(constrainedValue.toFixed(12));
candidateValues[pressedIndex] = pressedValueAfterClamp;
const movingForward = nextValue > pressedInitialValue;
const movingBackward = nextValue < pressedInitialValue;
const shouldSwapForward = movingForward && nextNeighbor != null && nextValue >= nextNeighbor - epsilon;
const shouldSwapBackward = movingBackward && previousNeighbor != null && nextValue <= previousNeighbor + epsilon;
if (!shouldSwapForward && !shouldSwapBackward) {
return {
value: candidateValues,
thumbIndex: pressedIndex,
didSwap: false
};
}
const targetIndex = shouldSwapForward ? pressedIndex + 1 : pressedIndex - 1;
const initialValuesForPush = candidateValues.map((_, index) => {
if (index === pressedIndex) {
return pressedValueAfterClamp;
}
const baseline = baselineValues[index];
if (baseline != null) {
return baseline;
}
return activeValues[index];
});
let nextValueForTarget = nextValue;
if (shouldSwapForward) {
nextValueForTarget = Math.max(nextValue, candidateValues[targetIndex]);
} else {
nextValueForTarget = Math.min(nextValue, candidateValues[targetIndex]);
}
const adjustedValues = (0, _getPushedThumbValues.getPushedThumbValues)({
values: candidateValues,
index: targetIndex,
nextValue: nextValueForTarget,
min,
max,
step,
minStepsBetweenValues,
initialValues: initialValuesForPush
});
const neighborIndex = shouldSwapForward ? targetIndex - 1 : targetIndex + 1;
if (neighborIndex >= 0 && neighborIndex < adjustedValues.length) {
const previousValue = adjustedValues[neighborIndex - 1];
const nextValueAfter = adjustedValues[neighborIndex + 1];
let neighborLowerBound = previousValue != null ? previousValue + minValueDifference : min;
neighborLowerBound = Math.max(neighborLowerBound, min + neighborIndex * minValueDifference);
let neighborUpperBound = nextValueAfter != null ? nextValueAfter - minValueDifference : max;
neighborUpperBound = Math.min(neighborUpperBound, max - (adjustedValues.length - 1 - neighborIndex) * minValueDifference);
const restoredValue = (0, _clamp.clamp)(pressedValueAfterClamp, neighborLowerBound, neighborUpperBound);
adjustedValues[neighborIndex] = Number(restoredValue.toFixed(12));
}
return {
value: adjustedValues,
thumbIndex: targetIndex,
didSwap: true
};
}
case 'push':
{
const nextValues = (0, _getPushedThumbValues.getPushedThumbValues)({
values: activeValues,
index: pressedIndex,
nextValue,
min,
max,
step,
minStepsBetweenValues
});
return {
value: nextValues,
thumbIndex: pressedIndex,
didSwap: false
};
}
case 'none':
default:
{
const candidateValues = activeValues.slice();
const previousNeighbor = candidateValues[pressedIndex - 1];
const nextNeighbor = candidateValues[pressedIndex + 1];
const lowerBound = previousNeighbor != null ? previousNeighbor + minValueDifference : min;
const upperBound = nextNeighbor != null ? nextNeighbor - minValueDifference : max;
const constrainedValue = (0, _clamp.clamp)(nextValue, lowerBound, upperBound);
candidateValues[pressedIndex] = Number(constrainedValue.toFixed(12));
return {
value: candidateValues,
thumbIndex: pressedIndex,
didSwap: false
};
}
}
}