@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
197 lines (196 loc) • 5.82 kB
JavaScript
"use client";
import React from 'react';
import { pickFormElementProps } from "../../shared/helpers/filterValidProps.js";
import { isTrue, makeUniqueId, dispatchCustomElementEvent, getStatusState, extendPropsWithContext } from "../../shared/component-helper.js";
import Context from "../../shared/Context.js";
import { closestIndex, getFormattedNumber, getUpdatedValues, roundValue } from "./SliderHelpers.js";
import { convertSnakeCaseProps } from "../../shared/helpers/withSnakeCaseProps.js";
const defaultProps = {
statusState: 'error',
min: 0,
max: 100,
value: -1,
multiThumbBehavior: 'swap'
};
export const SliderContext = React.createContext(null);
export function SliderProvider(localProps) {
const context = React.useContext(Context);
const allProps = convertSnakeCaseProps(extendPropsWithContext(localProps, defaultProps, {
skeleton: context?.skeleton
}, context?.getTranslation(localProps).Slider, pickFormElementProps(context?.FormRow, {
vertical: null
}), pickFormElementProps(context?.formElement, {
vertical: null
}), context?.Slider));
const [_id] = React.useState(makeUniqueId);
if (!allProps.id) {
allProps.id = _id;
}
const {
step,
label,
labelDirection,
labelSrOnly,
status,
statusState,
statusProps,
statusNoAnimation,
globalStatus,
stretch,
suffix,
thumbTitle: title,
subtractTitle,
addTitle,
hideButtons,
multiThumbBehavior,
numberFormat,
tooltip,
alwaysShowTooltip,
skeleton,
max,
min,
extensions,
disabled,
className,
id,
onChange,
onDragStart,
onDragEnd,
vertical: _vertical,
reverse: _reverse,
value: _value,
children: _children,
...attributes
} = allProps;
const [value, setValue] = React.useState(_value);
const [externValue, updateExternValue] = React.useState(_value);
const realtimeValue = React.useRef(_value);
const [thumbState, setThumbState] = React.useState('initial');
const thumbIndex = React.useRef(-1);
const [shouldAnimate, updateAnimateState] = React.useState(false);
const [isVertical] = React.useState(isTrue(_vertical));
const [isReverse] = React.useState(isVertical ? !isTrue(_reverse) : isTrue(_reverse));
const isMulti = Array.isArray(value);
const setThumbIndex = index => {
if (!isNaN(index)) {
thumbIndex.current = index;
}
};
const getAndUpdateCurrentIndex = currentValue => {
let currentIndex = null;
if (thumbIndex.current > -1) {
currentIndex = thumbIndex.current;
} else {
currentIndex = closestIndex(currentValue, value);
setThumbIndex(currentIndex);
}
return currentIndex;
};
const updateValue = value => {
setValue(value);
realtimeValue.current = value;
};
const emitChange = (event, rawValue) => {
if (disabled || isTrue(skeleton)) {
return;
}
let numberValue = roundValue(rawValue, {
step,
min,
max
});
let multiValues = numberValue;
if (numberValue >= min) {
if (isMulti) {
const currentIndex = getAndUpdateCurrentIndex(numberValue);
const lower = realtimeValue.current[currentIndex - 1];
const upper = realtimeValue.current[currentIndex + 1];
if (multiThumbBehavior === 'omit') {
if (numberValue < lower) {
numberValue = lower;
}
if (numberValue > upper) {
numberValue = upper;
}
}
multiValues = getUpdatedValues(multiThumbBehavior === 'push' ? realtimeValue.current : value, currentIndex, numberValue);
if (multiThumbBehavior === 'push') {
if (typeof lower !== 'undefined' && numberValue < lower) {
multiValues[currentIndex - 1] = numberValue;
}
if (typeof upper !== 'undefined' && numberValue >= upper) {
multiValues[currentIndex + 1] = numberValue;
}
}
if (numberValue === realtimeValue.current[currentIndex]) {
return;
}
} else if (numberValue === realtimeValue.current) {
return;
}
if (typeof onChange === 'function') {
const obj = {
value: multiValues,
rawValue,
event,
number: null
};
if (numberFormat) {
obj.number = getFormattedNumber(numberValue, numberFormat).number;
}
dispatchCustomElementEvent(allProps, 'onChange', obj);
}
updateValue(multiValues);
}
};
React.useEffect(() => {
if (isMulti) {
const hasChanged = _value.some((val, i) => {
return val !== externValue[i];
});
if (hasChanged) {
updateValue(_value);
updateExternValue(_value);
}
} else if (_value !== externValue) {
updateValue(_value);
updateExternValue(_value);
}
}, [_value, isMulti]);
const trackRef = React.useRef();
const animationTimeout = React.useRef();
const setShouldAnimate = state => {
updateAnimateState(state);
clearTimeout(animationTimeout.current);
if (state) {
animationTimeout.current = setTimeout(() => updateAnimateState(false), 250);
}
};
const showStatus = getStatusState(status);
const showButtons = !isMulti && !isTrue(hideButtons);
const values = isMulti ? value : [value];
return React.createElement(SliderContext.Provider, {
value: {
isMulti,
isReverse,
isVertical,
shouldAnimate,
value,
values,
setValue,
attributes,
showStatus,
showButtons,
thumbState,
setThumbState,
thumbIndex,
setThumbIndex,
emitChange,
allProps,
trackRef,
setShouldAnimate,
animationTimeout
}
}, localProps.children);
}
//# sourceMappingURL=SliderProvider.js.map