@storybook/addon-ondevice-controls
Version:
Display storybook controls on your device.
218 lines (217 loc) • 9.52 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HoloColorPicker = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const slider_1 = __importDefault(require("@react-native-community/slider"));
const react_1 = require("react");
const react_native_1 = require("react-native");
const tinycolor2_1 = __importDefault(require("tinycolor2"));
const utils_1 = require("./utils");
class HoloColorPicker extends react_1.PureComponent {
_layout;
_pageX;
_pageY;
_isRTL;
_pickerResponder;
pickerContainer = (0, react_1.createRef)();
constructor(props) {
super(props);
const state = {
color: { h: 0, s: 1, v: 1 },
pickerSize: null,
};
if (props.oldColor) {
state.color = (0, tinycolor2_1.default)(props.oldColor).toHsv();
}
if (props.defaultColor) {
state.color = (0, tinycolor2_1.default)(props.defaultColor).toHsv();
}
this.state = state;
this._layout = { width: 0, height: 0, x: 0, y: 0 };
this._pageX = 0;
this._pageY = 0;
this._isRTL = react_native_1.I18nManager.isRTL;
this._pickerResponder = (0, utils_1.createPanResponder)({
onStart: this._handleColorChange,
onMove: this._handleColorChange,
});
}
getColor() {
return (0, tinycolor2_1.default)(this._getColor()).toHexString();
}
_handleColorChange = ({ x, y }) => {
const { s, v } = this._getColor();
const marginLeft = (this._layout.width - (this.state.pickerSize ?? 0)) / 2;
const marginTop = (this._layout.height - (this.state.pickerSize ?? 0)) / 2;
const relativeX = x - this._pageX - marginLeft;
const relativeY = y - this._pageY - marginTop;
const h = this._computeHValue(relativeX, relativeY);
this._onColorChange({ h, s, v });
};
_onSValueChange = (s) => {
const { h, v } = this._getColor();
this._onColorChange({ h, s, v });
};
_onVValueChange = (v) => {
const { h, s } = this._getColor();
this._onColorChange({ h, s, v });
};
_onColorChange = (color) => {
this.setState({ color });
if (this.props.onColorChange) {
this.props.onColorChange(color);
}
};
_onLayout = (l) => {
this._layout = l.nativeEvent.layout;
const { width, height } = this._layout;
const pickerSize = Math.min(width, height);
if (this.state.pickerSize !== pickerSize) {
this.setState({ pickerSize });
}
react_native_1.InteractionManager.runAfterInteractions(() => {
if (this.pickerContainer.current) {
this.pickerContainer.current.measure((_x, _y, _width, _height, pageX, pageY) => {
this._pageX = pageX;
this._pageY = pageY;
});
}
});
};
_getColor() {
const passedColor = typeof this.props.color === 'string' ? (0, tinycolor2_1.default)(this.props.color).toHsv() : this.props.color;
return passedColor || this.state.color;
}
_onColorSelected = () => {
const { onColorSelected } = this.props;
const color = (0, tinycolor2_1.default)(this._getColor()).toHexString();
if (onColorSelected) {
onColorSelected(color);
}
};
_onOldColorSelected = () => {
const { oldColor, onOldColorSelected } = this.props;
const color = (0, tinycolor2_1.default)(oldColor);
this.setState({ color: color.toHsv() });
if (onOldColorSelected) {
onOldColorSelected(color.toHexString());
}
};
_computeHValue(x, y) {
const mx = (this.state.pickerSize ?? 0) / 2;
const my = (this.state.pickerSize ?? 0) / 2;
const dx = x - mx;
const dy = y - my;
const rad = Math.atan2(dx, dy) + Math.PI + Math.PI / 2;
return ((rad * 180) / Math.PI) % 360;
}
_hValueToRad(deg) {
const rad = (deg * Math.PI) / 180;
return rad - Math.PI - Math.PI / 2;
}
render() {
const { pickerSize } = this.state;
const { oldColor, style } = this.props;
const color = this._getColor();
const { h, s, v } = color;
const angle = this._hValueToRad(h);
const selectedColor = (0, tinycolor2_1.default)(color).toHexString();
const indicatorColor = (0, tinycolor2_1.default)({ h, s: 1, v: 1 }).toHexString();
const computed = makeComputedStyles({
pickerSize: pickerSize ?? 0,
selectedColor,
indicatorColor,
oldColor,
angle,
isRTL: this._isRTL,
});
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: style, children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { onLayout: this._onLayout, ref: this.pickerContainer, style: styles.pickerContainer, children: !pickerSize ? null : ((0, jsx_runtime_1.jsxs)(react_native_1.View, { children: [(0, jsx_runtime_1.jsxs)(react_native_1.View, { ...this._pickerResponder.panHandlers, style: [computed.picker], collapsable: false, children: [(0, jsx_runtime_1.jsx)(react_native_1.Image, { source: require('./resources/color-circle.png'), resizeMode: "contain", style: [styles.pickerImage] }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [styles.pickerIndicator, computed.pickerIndicator] })] }), oldColor && ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.selectedPreview, computed.selectedPreview], onPress: this._onColorSelected, activeOpacity: 0.7 })), oldColor && ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.originalPreview, computed.originalPreview], onPress: this._onOldColorSelected, activeOpacity: 0.7 })), !oldColor && ((0, jsx_runtime_1.jsx)(react_native_1.TouchableOpacity, { style: [styles.selectedFullPreview, computed.selectedFullPreview], onPress: this._onColorSelected, activeOpacity: 0.7 }))] })) }), this.props.hideSliders ? null : ((0, jsx_runtime_1.jsxs)(react_native_1.View, { children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { paddingStart: 4, color: '#859499', fontSize: 12 }, children: "Saturation" }), (0, jsx_runtime_1.jsx)(slider_1.default, { value: s, onValueChange: this._onSValueChange }), (0, jsx_runtime_1.jsx)(react_native_1.Text, { style: { paddingStart: 4, color: '#859499', fontSize: 12 }, children: "Lightness" }), (0, jsx_runtime_1.jsx)(slider_1.default, { value: v, onValueChange: this._onVValueChange })] }))] }));
}
}
exports.HoloColorPicker = HoloColorPicker;
const makeComputedStyles = ({ indicatorColor, selectedColor, oldColor, angle, pickerSize, isRTL, }) => {
const summarySize = 0.5 * pickerSize;
const indicatorPickerRatio = 42 / 510;
const indicatorSize = indicatorPickerRatio * pickerSize;
const pickerPadding = indicatorSize / 3;
const indicatorRadius = pickerSize / 2 - indicatorSize / 2 - pickerPadding;
const mx = pickerSize / 2;
const my = pickerSize / 2;
const dx = Math.cos(angle) * indicatorRadius;
const dy = Math.sin(angle) * indicatorRadius;
return {
picker: {
padding: pickerPadding,
width: pickerSize,
height: pickerSize,
},
pickerIndicator: {
top: mx + dx - indicatorSize / 2,
[isRTL ? 'right' : 'left']: my + dy - indicatorSize / 2,
width: indicatorSize,
height: indicatorSize,
borderRadius: indicatorSize / 2,
backgroundColor: indicatorColor,
},
selectedPreview: {
width: summarySize / 2,
height: summarySize,
top: pickerSize / 2 - summarySize / 2,
left: Math.floor(pickerSize / 2),
borderTopRightRadius: summarySize / 2,
borderBottomRightRadius: summarySize / 2,
backgroundColor: selectedColor,
},
originalPreview: {
width: Math.ceil(summarySize / 2),
height: summarySize,
top: pickerSize / 2 - summarySize / 2,
left: pickerSize / 2 - summarySize / 2,
borderTopLeftRadius: summarySize / 2,
borderBottomLeftRadius: summarySize / 2,
backgroundColor: oldColor,
},
selectedFullPreview: {
width: summarySize,
height: summarySize,
top: pickerSize / 2 - summarySize / 2,
left: pickerSize / 2 - summarySize / 2,
borderRadius: summarySize / 2,
backgroundColor: selectedColor,
},
};
};
const styles = react_native_1.StyleSheet.create({
pickerContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
pickerImage: {
flex: 1,
width: undefined,
height: undefined,
},
pickerIndicator: {
position: 'absolute',
boxShadow: '3px 3px 4px 0px rgba(0, 0, 0, 0.3)',
elevation: 5,
},
selectedPreview: {
position: 'absolute',
borderLeftWidth: 0,
},
originalPreview: {
position: 'absolute',
borderRightWidth: 0,
},
selectedFullPreview: {
position: 'absolute',
},
pickerAlignment: {
alignItems: 'center',
},
});