Skip to content

Commit

Permalink
[utils] Centralize clamp implementation in utils (#40267)
Browse files Browse the repository at this point in the history
Co-authored-by: Ragim Musakaev <ragim@panoramik.ru>
Co-authored-by: ZeeshanTamboli <zeeshan.tamboli@gmail.com>
  • Loading branch information
3 people committed Jan 17, 2024
1 parent 022de25 commit d3cf1c9
Show file tree
Hide file tree
Showing 12 changed files with 57 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {
StepDirection,
} from './useNumberInput.types';
import { NumberInputActionTypes } from './numberInputAction.types';
import { clamp, isNumber } from './utils';
import { clampStepwise, isNumber } from './utils';

// extracted from handleValueChange
function getClampedValues(rawValue: number | undefined, context: NumberInputActionContext) {
const { min, max, step } = context;

const clampedValue = rawValue === undefined ? '' : clamp(rawValue, min, max, step);
const clampedValue = rawValue === undefined ? '' : clampStepwise(rawValue, min, max, step);

const newInputValue = clampedValue === undefined ? '' : String(clampedValue);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
UseNumberInputReturnValue,
StepDirection,
} from './useNumberInput.types';
import { clamp, isNumber } from './utils';
import { clampStepwise, isNumber } from './utils';

const STEP_KEYS = ['ArrowUp', 'ArrowDown', 'PageUp', 'PageDown'];

Expand Down Expand Up @@ -132,7 +132,7 @@ export function useNumberInput(parameters: UseNumberInputParameters): UseNumberI
newValue = val;
setDirtyValue('');
} else {
newValue = clamp(val, min, max, step);
newValue = clampStepwise(val, min, max, step);
setDirtyValue(String(newValue));
}

Expand Down
32 changes: 16 additions & 16 deletions packages/mui-base/src/unstable_useNumberInput/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { expect } from 'chai';
import { clamp, isNumber } from './utils';
import { clampStepwise, isNumber } from './utils';

describe('utils', () => {
it('clamp: clamps a value based on min and max', () => {
expect(clamp(1, 2, 4)).to.equal(2);
expect(clamp(5, 2, 4)).to.equal(4);
expect(clamp(-5, -1, 5)).to.equal(-1);
it('clampStepwise: clamps a value based on min and max', () => {
expect(clampStepwise(1, 2, 4)).to.equal(2);
expect(clampStepwise(5, 2, 4)).to.equal(4);
expect(clampStepwise(-5, -1, 5)).to.equal(-1);
});

it('clamp: clamps a value between min and max and on a valid step', () => {
expect(clamp(2, -15, 15, 3)).to.equal(3);
expect(clamp(-1, -15, 15, 3)).to.equal(0);
expect(clamp(5, -15, 15, 3)).to.equal(6);
expect(clamp(-5, -15, 15, 3)).to.equal(-6);
expect(clamp(-55, -15, 15, 3)).to.equal(-15);
expect(clamp(57, -15, 15, 3)).to.equal(15);
expect(clamp(3, -20, 20, 5)).to.equal(5);
expect(clamp(2, -20, 20, 5)).to.equal(0);
expect(clamp(8, -20, 20, 5)).to.equal(10);
expect(clamp(-7, -20, 20, 5)).to.equal(-5);
it('clampStepwise: clamps a value between min and max and on a valid step', () => {
expect(clampStepwise(2, -15, 15, 3)).to.equal(3);
expect(clampStepwise(-1, -15, 15, 3)).to.equal(0);
expect(clampStepwise(5, -15, 15, 3)).to.equal(6);
expect(clampStepwise(-5, -15, 15, 3)).to.equal(-6);
expect(clampStepwise(-55, -15, 15, 3)).to.equal(-15);
expect(clampStepwise(57, -15, 15, 3)).to.equal(15);
expect(clampStepwise(3, -20, 20, 5)).to.equal(5);
expect(clampStepwise(2, -20, 20, 5)).to.equal(0);
expect(clampStepwise(8, -20, 20, 5)).to.equal(10);
expect(clampStepwise(-7, -20, 20, 5)).to.equal(-5);
});

it('isNumber: rejects NaN', () => {
Expand Down
16 changes: 5 additions & 11 deletions packages/mui-base/src/unstable_useNumberInput/utils.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
function simpleClamp(
val: number,
min: number = Number.MIN_SAFE_INTEGER,
max: number = Number.MAX_SAFE_INTEGER,
): number {
return Math.max(min, Math.min(val, max));
}
import { clamp } from '@mui/utils';

export function clamp(
export function clampStepwise(
val: number,
min: number = Number.MIN_SAFE_INTEGER,
max: number = Number.MAX_SAFE_INTEGER,
stepProp: number = NaN,
): number {
if (Number.isNaN(stepProp)) {
return simpleClamp(val, min, max);
return clamp(val, min, max);
}

const step = stepProp || 1;
Expand All @@ -23,10 +17,10 @@ export function clamp(
const positivity = Math.sign(remainder);

if (Math.abs(remainder) > step / 2) {
return simpleClamp(val + positivity * (step - Math.abs(remainder)), min, max);
return clamp(val + positivity * (step - Math.abs(remainder)), min, max);
}

return simpleClamp(val - positivity * Math.abs(remainder), min, max);
return clamp(val - positivity * Math.abs(remainder), min, max);
}

export function isNumber(val: unknown): val is number {
Expand Down
11 changes: 3 additions & 8 deletions packages/mui-base/src/useSlider/useSlider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
unstable_useForkRef as useForkRef,
unstable_useIsFocusVisible as useIsFocusVisible,
visuallyHidden,
clamp,
} from '@mui/utils';
import {
Mark,
Expand All @@ -25,13 +26,6 @@ function asc(a: number, b: number) {
return a - b;
}

function clamp(value: number, min: number, max: number) {
if (value == null) {
return min;
}
return Math.min(Math.max(min, value), max);
}

function findClosest(values: number[], currentValue: number) {
const { index: closestIndex } =
values.reduce<{ distance: number; index: number } | null>(
Expand Down Expand Up @@ -259,7 +253,8 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue

const range = Array.isArray(valueDerived);
let values = range ? valueDerived.slice().sort(asc) : [valueDerived];
values = values.map((value) => clamp(value, min, max));
values = values.map((value) => (value == null ? min : clamp(value, min, max)));

const marks =
marksProp === true && step !== null
? [...Array(Math.floor((max - min) / step) + 1)].map((_, index) => ({
Expand Down
12 changes: 1 addition & 11 deletions packages/mui-material/src/Rating/Rating.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { chainPropTypes, visuallyHidden } from '@mui/utils';
import { chainPropTypes, visuallyHidden, clamp } from '@mui/utils';
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
import useTheme from '../styles/useTheme';
import {
Expand All @@ -18,16 +18,6 @@ import useThemeProps from '../styles/useThemeProps';
import styled, { slotShouldForwardProp } from '../styles/styled';
import ratingClasses, { getRatingUtilityClass } from './ratingClasses';

function clamp(value, min, max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}

function getDecimalPrecision(num) {
const decimalPart = num.toString().split('.')[1];
return decimalPart ? decimalPart.length : 0;
Expand Down
11 changes: 1 addition & 10 deletions packages/mui-material/src/SpeedDial/SpeedDial.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { isFragment } from 'react-is';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
import { clamp } from '@mui/utils';
import styled from '../styles/styled';
import useThemeProps from '../styles/useThemeProps';
import useTheme from '../styles/useTheme';
Expand Down Expand Up @@ -37,16 +38,6 @@ function getOrientation(direction) {
return undefined;
}

function clamp(value, min, max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}

const dialRadius = 32;
const spacingActions = 16;

Expand Down
11 changes: 6 additions & 5 deletions packages/mui-system/src/colorManipulator.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { clamp } from '@mui/utils';
import MuiError from '@mui-internal/babel-macros/MuiError.macro';

/**
Expand All @@ -8,14 +9,14 @@ import MuiError from '@mui-internal/babel-macros/MuiError.macro';
* @param {number} max The upper boundary of the output range
* @returns {number} A number in the range [min, max]
*/
function clamp(value, min = 0, max = 1) {
function clampWrapper(value, min = 0, max = 1) {
if (process.env.NODE_ENV !== 'production') {
if (value < min || value > max) {
console.error(`MUI: The value provided ${value} is out of range [${min}, ${max}].`);
}
}

return Math.min(Math.max(min, value), max);
return clamp(value, min, max);
}

/**
Expand Down Expand Up @@ -238,7 +239,7 @@ export function getContrastRatio(foreground, background) {
*/
export function alpha(color, value) {
color = decomposeColor(color);
value = clamp(value);
value = clampWrapper(value);

if (color.type === 'rgb' || color.type === 'hsl') {
color.type += 'a';
Expand Down Expand Up @@ -270,7 +271,7 @@ export function private_safeAlpha(color, value, warning) {
*/
export function darken(color, coefficient) {
color = decomposeColor(color);
coefficient = clamp(coefficient);
coefficient = clampWrapper(coefficient);

if (color.type.indexOf('hsl') !== -1) {
color.values[2] *= 1 - coefficient;
Expand Down Expand Up @@ -300,7 +301,7 @@ export function private_safeDarken(color, coefficient, warning) {
*/
export function lighten(color, coefficient) {
color = decomposeColor(color);
coefficient = clamp(coefficient);
coefficient = clampWrapper(coefficient);

if (color.type.indexOf('hsl') !== -1) {
color.values[2] += (100 - color.values[2]) * coefficient;
Expand Down
10 changes: 10 additions & 0 deletions packages/mui-utils/src/clamp/clamp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { expect } from 'chai';
import clamp from './clamp';

describe('clamp', () => {
it('clamps a value based on min and max', () => {
expect(clamp(1, 2, 4)).to.equal(2);
expect(clamp(5, 2, 4)).to.equal(4);
expect(clamp(-5, -1, 5)).to.equal(-1);
});
});
9 changes: 9 additions & 0 deletions packages/mui-utils/src/clamp/clamp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function clamp(
val: number,
min: number = Number.MIN_SAFE_INTEGER,
max: number = Number.MAX_SAFE_INTEGER,
): number {
return Math.max(min, Math.min(val, max));
}

export default clamp;
1 change: 1 addition & 0 deletions packages/mui-utils/src/clamp/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './clamp';
1 change: 1 addition & 0 deletions packages/mui-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ export { isGlobalState as unstable_isGlobalState } from './generateUtilityClass'
export * from './generateUtilityClass';
export { default as unstable_generateUtilityClasses } from './generateUtilityClasses';
export { default as unstable_ClassNameGenerator } from './ClassNameGenerator';
export { default as clamp } from './clamp';

0 comments on commit d3cf1c9

Please sign in to comment.