UNPKG

react95-native

Version:

Refreshed Windows 95 style UI components for your React Native app

258 lines (229 loc) 8.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _useAsyncReference = _interopRequireDefault(require("../../hooks/useAsyncReference")); var _theming = require("../../core/theming"); var _styles = require("../../styles/styles"); var _styleElements = require("../../styles/styleElements"); var _utils = require("../../utils"); var _2 = require("../.."); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function percentToValue(percent, min, max) { return (max - min) * percent + min; } const Slider = ({ disabled = false, marks: marksProp, max = 100, min = 0, onChange, onChangeCommitted, step = 1, style, theme, value = 0, ...rest }) => { const [isUsed, setIsUsed] = (0, _react.useState)(false); let marks; // if marks is set to true, we only show ticks at specified steps if (marksProp === true && step !== null) { marks = [...Array(Math.round((max - min) / step) + 1)].map((_, index) => ({ value: min + step * index })); // otherwise we display ticks and optional labels specified by the developer } else if (Array.isArray(marksProp)) { marks = marksProp; // otherwise don't display any marks or labels } else { marks = []; } const [sliderSize, setSliderSize] = (0, _useAsyncReference.default)(0); const handleLayout = e => { setSliderSize(e.nativeEvent.layout.width); }; const getNewValue = e => { const percent = (0, _utils.clamp)(e.nativeEvent.locationX / sliderSize.current, 0, 1); let newValue = percentToValue(percent, min, max); if (step) { newValue = (0, _utils.roundValueToStep)(newValue, step, min); } else { const marksValues = marks.map(mark => mark.value); const closestIndex = (0, _utils.findClosest)(marksValues, newValue); newValue = marksValues[closestIndex]; } newValue = (0, _utils.clamp)(newValue, min, max); return newValue; }; // TODO: is this a good approach? const valueRef = (0, _react.useRef)(value); (0, _react.useEffect)(() => { valueRef.current = value; }, [value]); const handleChange = newValue => { if (valueRef.current !== newValue) { onChange === null || onChange === void 0 ? void 0 : onChange(newValue); } }; const panResponder = (0, _react.useRef)(_reactNative.PanResponder.create({ onStartShouldSetPanResponder: () => true, onStartShouldSetPanResponderCapture: () => true, onMoveShouldSetPanResponder: () => true, onMoveShouldSetPanResponderCapture: () => true, onPanResponderStart: e => { setIsUsed(true); const newValue = getNewValue(e); handleChange(newValue); }, onPanResponderMove: e => { const newValue = getNewValue(e); handleChange(newValue); }, onPanResponderEnd: e => { setIsUsed(false); const newValue = getNewValue(e); onChangeCommitted === null || onChangeCommitted === void 0 ? void 0 : onChangeCommitted(newValue); }, onPanResponderTerminationRequest: () => true })).current; const borderStyles = (0, _styles.buildBorderStyles)(theme); return /*#__PURE__*/_react.default.createElement(_reactNative.View, _extends({ style: [styles.wrapper, style] }, rest, { accessibilityRole: "adjustable", accessibilityState: { disabled }, accessibilityValue: { min, max, now: value } }), /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.inner, isUsed ? borderStyles.focusOutline : { borderWidth: 2, borderColor: 'transparent' }] }, /*#__PURE__*/_react.default.createElement(_reactNative.View, _extends({ pointerEvents: disabled ? 'none' : 'auto', style: [styles.track], onLayout: handleLayout }, panResponder.panHandlers), /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.trackInner] }, /*#__PURE__*/_react.default.createElement(_styleElements.Border, { theme: theme, variant: "cutout" }), /*#__PURE__*/_react.default.createElement(_2.Panel, { theme: theme, pointerEvents: "none", style: [styles.thumb, { left: "".concat(100 * (value - min) / (max - min), "%") }] }, disabled && /*#__PURE__*/_react.default.createElement(_reactNative.ImageBackground, { style: { flex: 1 }, imageStyle: { resizeMode: 'repeat' }, source: { // TODO: create util function for generating checkered background uri: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAIUlEQVQoU2P8////fwYkwMjIyIjCp4MCZPtAbAwraa8AAEGrH/nfAIhgAAAAAElFTkSuQmCC' } }), isUsed && /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: styles.tooltipWrapper }, /*#__PURE__*/_react.default.createElement(_2.Label, { elevation: 4, style: styles.tooltip }, value))))), marks && /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: styles.marksWrapper }, marks.map((m, index) => /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.mark, { position: index === 0 ? 'relative' : 'absolute', left: "".concat((m.value - min) / (max - min) * 100, "%") }], key: m.value / (max - min) * 100 }, /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.tick, { backgroundColor: disabled ? theme.materialTextDisabled : theme.materialText, // TODO: util function to create disabled shadows shadowColor: disabled ? theme.materialTextDisabledShadow : 'transparent', shadowOffset: { width: 1, height: 1 }, shadowOpacity: 1, shadowRadius: 0 }] }), m.label ? /*#__PURE__*/_react.default.createElement(_2.Text, { style: styles.markText, disabled: disabled }, m.label) : null))))); }; const thumbWidth = 18; const thumbHeight = 32; const tickSize = 6; const styles = _reactNative.StyleSheet.create({ wrapper: { paddingVertical: 4 }, inner: { position: 'relative', paddingHorizontal: 16 }, track: { paddingVertical: thumbHeight / 2 }, trackInner: { height: 8, width: '100%', alignItems: 'center', justifyContent: 'center' }, thumb: { position: 'absolute', width: thumbWidth, height: thumbHeight, transform: [{ translateX: -thumbWidth / 2 }] }, tooltipWrapper: { position: 'absolute', top: -44, left: thumbWidth / 2, alignItems: 'center' }, tooltip: { position: 'absolute', alignItems: 'center', justifyContent: 'center' }, marksWrapper: { position: 'relative' }, mark: { transform: [{ translateX: -1 }] }, tick: { height: tickSize, marginBottom: 2, width: 2 }, markText: { fontSize: 14, // TODO: is there a way to translate by 0.5 of a character width? // tick should centered above transform: [{ translateX: -2 }] } }); var _default = (0, _theming.withTheme)(Slider); exports.default = _default; //# sourceMappingURL=Slider.js.map