react95-native
Version:
Refreshed Windows 95 style UI components for your React Native app
258 lines (229 loc) • 8.48 kB
JavaScript
"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