@vimeo/iris
Version:
Vimeo Design System
212 lines (209 loc) • 10.9 kB
JavaScript
import { b as __rest, c as __assign, _ as __read } from '../../../tslib.es6-7f0e734f.js';
import React__default, { forwardRef, useRef, useReducer, useCallback, useLayoutEffect, useEffect } from 'react';
import { reducer, initialState } from './Slider.state.esm.js';
import { Background, ActiveRange, SliderContainer, Label } from './Slider.style.esm.js';
import { Handle } from './Handle.esm.js';
import { end, home, arrowRight, arrowUp, arrowLeft, arrowDown } from '../../../utils/events/KeyCodes.esm.js';
import { SliderEditableInput } from './SliderEditableInput.esm.js';
import { useOutsideClick } from '../../../utils/hooks/useOutsideClick.esm.js';
import { geometry } from '../../../utils/DOM/geometry.esm.js';
import 'styled-components';
import 'polished';
import './SliderInputArrow.esm.js';
import '../../../color/colors.esm.js';
import '../../../tokens/core.esm.js';
import '../../../tokens/color/index.esm.js';
import '../../../tokens/color/background/background.esm.js';
import '../../../tokens/util/readToken.esm.js';
import '../../../tokens/util/clamp.esm.js';
import '../../../tokens/color/format/format.esm.js';
import '../../../tokens/color/format/primary.esm.js';
import '../../../tokens/color/format/secondary.esm.js';
import '../../../tokens/color/format/tertiary.esm.js';
import '../../../tokens/color/rainbow/rainbow.esm.js';
import '../../../tokens/color/rainbow/conic/index.esm.js';
import '../../../tokens/color/rainbow/conic/sm.esm.js';
import '../../../tokens/color/rainbow/conic/xl.esm.js';
import '../../../tokens/color/rainbow/linear/index.esm.js';
import '../../../tokens/color/rainbow/linear/sm.esm.js';
import '../../../tokens/color/rainbow/linear/xl.esm.js';
import '../../../tokens/color/livestream/livestream.esm.js';
import '../../../tokens/color/status/status.esm.js';
import '../../../tokens/color/status/caution.esm.js';
import '../../../tokens/color/status/negative.esm.js';
import '../../../tokens/color/status/positive.esm.js';
import '../../../tokens/color/stroke/stroke.esm.js';
import '../../../tokens/color/surface/surface.esm.js';
import '../../../tokens/color/text/text.esm.js';
import '../../../tokens/util/round.esm.js';
import '../../../tokens/color/upsell/upsell.esm.js';
import '../../../tokens/color/upsell/sm.esm.js';
import '../../../tokens/color/upsell/xl.esm.js';
import '../../../tokens/color/upsell/new.esm.js';
import '../../../tokens/edge/edge.esm.js';
import '../../../tokens/space/space.esm.js';
import '../../../tokens/typography/index.esm.js';
import '../../../tokens/typography/size/size.esm.js';
import '../../../utils/css.esm.js';
function Slider(_a) {
var disabled = _a.disabled, editableLabel = _a.editableLabel, _b = _a.formatter, formatter = _b === void 0 ? function (value) { return value; } : _b, _c = _a.initialValues, initialValues = _c === void 0 ? [0, 100] : _c, _d = _a.max, max = _d === void 0 ? 100 : _d, _e = _a.min, min = _e === void 0 ? 0 : _e, onChange = _a.onChange, onDragEnd = _a.onDragEnd, range = _a.range, props = __rest(_a, ["disabled", "editableLabel", "formatter", "initialValues", "max", "min", "onChange", "onDragEnd", "range"]);
var isFirstRender = useRef(true);
var trackRef = useRef(null);
var startHandleRef = useRef(null);
var endHandleRef = useRef(null);
useOutsideClick([trackRef], function () {
setFocus(null);
});
var _f = __read(useReducer(reducer, initialState(initialValues)), 2), state = _f[0], dispatch = _f[1];
var values = state.values, trackRect = state.trackRect, focused = state.focused, dragging = state.dragging;
var dispatchChangeEvent = useCallback(function (callback) {
var _a;
var currentInput = focused === 'startHandle' || focused === 'startInput'
? startHandleRef
: endHandleRef;
if (!currentInput.current)
currentInput = startHandleRef;
var event = new Event('change', { bubbles: true });
(_a = currentInput.current) === null || _a === void 0 ? void 0 : _a.dispatchEvent(event);
callback && callback(event);
}, [focused]);
function setDragging(payload) {
if (payload)
setFocus(payload);
return dispatch({ type: 'SET_DRAGGING', payload: payload });
}
function setValue(payload) {
return dispatch({ type: 'SET_VALUES', payload: payload });
}
function setFocus(payload) {
return dispatch({ type: 'SET_FOCUS', payload: payload });
}
function setStartValue(value) {
var newValue = constrain(min, range ? values[1] - 1 : max)(value);
setValue([newValue, values[1]]);
}
function setEndValue(value) {
var newValue = constrain(values[0] + 1, max)(value);
setValue([values[0], newValue]);
}
function handleArrowClick(direction, handle) {
var action = handle === 'startInput' ? setStartValue : setEndValue;
var currentValue = handle === 'startInput' ? values[0] : values[1];
if (direction === 'up')
action(currentValue + 1);
else
action(currentValue - 1);
}
useLayoutEffect(function () {
var _a = geometry(trackRef.current), left = _a.left, width = _a.width;
dispatch({ type: 'SET_TRACK_RECT', payload: { left: left, width: width } });
}, [dragging]);
useEffect(function () {
if (!isFirstRender.current) {
dispatchChangeEvent(onChange);
}
else {
isFirstRender.current = false;
}
// dispatchChangeEvent is updated on focus change and we want this flow to fire only on values / onChange updates
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [onChange, values]);
useEffect(function () {
var mouseup = function () {
if (dragging) {
setDragging(false);
dispatchChangeEvent(onDragEnd);
}
};
var keydown = function (event) {
if (!focused || !isHandleFocused(focused))
return;
var action = focused === 'startHandle' ? setStartValue : setEndValue;
var currentValue = focused === 'startHandle' ? values[0] : values[1];
switch (event.keyCode) {
case arrowDown:
case arrowLeft:
action(currentValue - 1);
break;
case arrowUp:
case arrowRight:
action(currentValue + 1);
break;
case home:
action(min);
break;
case end:
action(max);
break;
}
};
document && document.addEventListener('mouseup', mouseup);
document && document.addEventListener('keydown', keydown);
return function () {
document && document.removeEventListener('mouseup', mouseup);
document && document.removeEventListener('keydown', keydown);
};
});
useEffect(function () {
function mousemove(event) {
if (dragging) {
var pos = constrainedPosition(event, trackRect, min, max);
if (dragging === 'startHandle')
setStartValue(pos);
if (dragging === 'endHandle')
setEndValue(pos);
}
}
document && document.addEventListener('mousemove', mousemove);
return function () {
return document &&
document.removeEventListener('mousemove', mousemove);
};
});
return (React__default.createElement(SliderContainer, __assign({}, props, { range: range, "aria-label": "slider", role: "slider", "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": dragging === 'startHandle' ? values[0] : values[1] }),
range && (React__default.createElement(Label, { focused: focused === 'startInput' }, editableLabel ? (React__default.createElement(SliderEditableInput, { value: values[0], disabled: disabled, onFocus: function () { return setFocus('startInput'); }, onChange: function (e) {
return !e.button && setStartValue(parseInt(e.target.value));
}, role: "start-input", onArrowUpClick: function () {
return handleArrowClick('up', range ? 'endInput' : 'startInput');
}, onArrowDownClick: function () {
return handleArrowClick('down', range ? 'endInput' : 'startInput');
} })) : (formatter(values[0])))),
React__default.createElement(Track, { ref: trackRef, values: values, id: "track-1", max: max, range: range, "aria-label": "track" },
React__default.createElement(Handle, { disabled: disabled, handle: "startHandle", min: min, max: max, setFocus: setFocus, setDragging: setDragging, value: values[0], ref: startHandleRef }),
range && (React__default.createElement(Handle, { disabled: disabled, handle: "endHandle", min: min, max: max, setFocus: setFocus, setDragging: setDragging, value: values[1], ref: endHandleRef }))),
React__default.createElement(Label, { focused: focused === (range ? 'endInput' : 'startInput') }, editableLabel ? (React__default.createElement(SliderEditableInput, { disabled: disabled, value: range ? values[1] : values[0], onFocus: function () {
return setFocus(range ? 'endInput' : 'startInput');
}, onChange: function (e) {
range
? setEndValue(parseInt(e.target.value))
: setStartValue(parseInt(e.target.value));
}, role: range ? 'end-input' : 'start-input', onArrowUpClick: function () {
return handleArrowClick('up', range ? 'endInput' : 'startInput');
}, onArrowDownClick: function () {
return handleArrowClick('down', range ? 'endInput' : 'startInput');
} })) : (formatter(range ? values[1] : values[0])))));
}
var Track = forwardRef(function (_a, ref) {
var children = _a.children, values = _a.values, max = _a.max, range = _a.range, props = __rest(_a, ["children", "values", "max", "range"]);
return (React__default.createElement(Background, __assign({ ref: ref }, props),
children,
React__default.createElement(ActiveRange, { values: values, max: max, range: range })));
});
function isHandleFocused(focusedElement) {
return focusedElement.includes('Handle');
}
function constrainedPosition(event, element, min, max) {
var left = event.clientX - element.left;
var pos = Math.round((left / element.width) * max);
return constrain(min, max)(pos);
}
function constrain(min, max) {
return function (val) {
if (val > max)
return max;
if (val < min)
return min;
return val;
};
}
export { Slider };