UNPKG

@onesy/ui-react

Version:
438 lines (435 loc) 17 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _utils = require("@onesy/utils"); var _styleReact = require("@onesy/style-react"); var _ = require(".."); var _jsxRuntime = require("react/jsx-runtime"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const other = { pointerEvents: 'none', borderRadius: 'inherit', position: 'absolute', inset: '0', width: '100%', height: '100%' }; const useStyle = (0, _styleReact.style)(theme => ({ '@keyframes pulse': { '0%': { transform: 'scale(0.77)' }, '50%': { transform: 'scale(0.7)' }, '100%': { transform: 'scale(0.77)' } }, root: _objectSpread(_objectSpread({}, other), {}, { overflow: 'hidden', // Bug fix for overflow in mobile Safari zIndex: '0' }), background: _objectSpread(_objectSpread({}, other), {}, { opacity: theme.palette.visual_contrast.default.opacity.hover, transition: theme.methods.transitions.make(['opacity', 'background'], { duration: 'rg', timing_function: 'standard' }) }), hovered: { background: 'currentColor' }, selected: { opacity: theme.palette.visual_contrast.default.opacity.selected, background: 'currentColor' }, dragged: { opacity: theme.palette.visual_contrast.default.opacity.drag, background: 'currentColor' }, border: _objectSpread(_objectSpread({}, other), {}, { opacity: '0', boxShadow: 'inset 0 0 0 2px currentColor' }), wave: _objectSpread(_objectSpread({}, other), {}, { inset: 'unset', opacity: '0.1', transform: 'scale(0)', backgroundColor: 'currentColor', transition: theme.methods.transitions.make(['opacity', 'transform'], { duration: 'complex', timing_function: 'standard' }), borderRadius: theme.methods.shape.radius.value(4e4, 'px'), '&.entering': { opacity: theme.palette.visual_contrast.low.opacity.press, transform: 'scale(1)' }, '&.entered': { opacity: theme.palette.visual_contrast.low.opacity.press, transform: 'scale(1)' }, '&.exit': { opacity: theme.palette.visual_contrast.low.opacity.press, transform: 'scale(1)' }, '&.exiting': { opacity: '0', transform: 'scale(1)' }, '&.exited': { opacity: '0', transform: 'scale(1)' } }), pulse: { '&.entering': { opacity: theme.palette.visual_contrast.low.opacity.press, transform: 'scale(0.77)' }, '&.entered': { opacity: theme.palette.visual_contrast.low.opacity.press, transform: 'scale(0.77)', animation: `$pulse 2400ms ${theme.transitions.timing_function.emphasized} 240ms infinite` }, '&.exit': { opacity: theme.palette.visual_contrast.low.opacity.press, transform: 'scale(0.7)' }, '&.exiting': { opacity: '0', transform: 'scale(0.7)' }, '&.exited': { opacity: '0', transform: 'scale(0.7)' } }, waveSimple: _objectSpread(_objectSpread({}, other), {}, { opacity: '0.1', backgroundColor: 'currentcolor', transition: theme.methods.transitions.make(['opacity'], { duration: 'complex', timing_function: 'standard' }), '&.entering': { opacity: theme.palette.visual_contrast.low.opacity.press }, '&.entered': { opacity: theme.palette.visual_contrast.low.opacity.press }, '&.exit': { opacity: theme.palette.visual_contrast.low.opacity.press }, '&.exiting': { opacity: '0' }, '&.exited': { opacity: '0' } }) }), { name: 'onesy-Interaction' }); const Interaction = props_ => { var _theme$ui, _theme$ui2; const theme = (0, _styleReact.useOnesyTheme)(); const props = _objectSpread(_objectSpread(_objectSpread({}, theme === null || theme === void 0 || (_theme$ui = theme.ui) === null || _theme$ui === void 0 || (_theme$ui = _theme$ui.elements) === null || _theme$ui === void 0 || (_theme$ui = _theme$ui.all) === null || _theme$ui === void 0 || (_theme$ui = _theme$ui.props) === null || _theme$ui === void 0 ? void 0 : _theme$ui.default), theme === null || theme === void 0 || (_theme$ui2 = theme.ui) === null || _theme$ui2 === void 0 || (_theme$ui2 = _theme$ui2.elements) === null || _theme$ui2 === void 0 || (_theme$ui2 = _theme$ui2.onesyInteraction) === null || _theme$ui2 === void 0 || (_theme$ui2 = _theme$ui2.props) === null || _theme$ui2 === void 0 ? void 0 : _theme$ui2.default), props_); const { ref, wave = true, background = true, border: hasBorder, pulse, origin: originProps, preselected, selected, dragged, wave_version, subscription, clear, disabled, mobileDelay = 150, className } = props; const { classes } = useStyle(); const [interactions, setInteractions] = _react.default.useState([]); const [border, setBorder] = _react.default.useState(false); const [waves, setWaves] = _react.default.useState([]); const refs = { root: _react.default.useRef(undefined), mouse: _react.default.useRef({ down: 0, up: 0, press: 0 }), wave: _react.default.useRef(undefined), pulse: _react.default.useRef(undefined), touch: _react.default.useRef(undefined), interactions: _react.default.useRef(undefined), border: _react.default.useRef(border), props: _react.default.useRef(undefined), init: _react.default.useRef(false), waves: _react.default.useRef(waves), origin: _react.default.useRef(originProps), hasBorder: _react.default.useRef(hasBorder) }; const touch = (0, _.useMediaQuery)('(pointer: coarse)', { element: refs.root.current }); refs.props.current = props; refs.wave.current = wave; refs.pulse.current = pulse; refs.touch.current = touch; refs.interactions.current = interactions; refs.border.current = border; refs.waves.current = waves; refs.origin.current = originProps; refs.hasBorder.current = hasBorder; _react.default.useEffect(() => { var _refs$root$current; const parent = refs.root.current.parentNode; const onMouseIn = () => { if (refs.touch.current) return; add('mouse-in'); removeWaves(); }; const onMouseOut = () => { if (refs.touch.current) return; refs.mouse.current.up = new Date().getTime(); refs.mouse.current.press = refs.mouse.current.down ? Math.round(refs.mouse.current.up - refs.mouse.current.down) : 0; remove('mouse-in'); removeWaves(); }; const onMouseDown = event => { refs.mouse.current.down = new Date().getTime(); refs.mouse.current.up = 0; refs.mouse.current.press = 0; add('mouse-down'); addWave(event); }; const updateBorder = (0, _utils.debounce)(() => { if (refs.border.current) setBorder(false); }, theme.transitions.duration.sm); const onMouseUp = () => { if (!(has('mouse-down') || refs.waves.current.length)) return; refs.mouse.current.up = new Date().getTime(); refs.mouse.current.press = refs.mouse.current.down ? Math.round(refs.mouse.current.up - refs.mouse.current.down) : 0; if (refs.hasBorder.current && has('mouse-down')) { setBorder(true); updateBorder(); } remove('mouse-down'); removeWaves(); }; const onTouchStart = event_0 => { onMouseDown(event_0); onMouseIn(); }; const onTouchUp = () => { setTimeout(() => { onMouseUp(); onMouseOut(); }, mobileDelay); }; const onTouchCancel = () => { setTimeout(() => { onMouseUp(); onMouseOut(); }, mobileDelay); }; const rootDocument = (0, _utils.isEnvironment)('browser') ? ((_refs$root$current = refs.root.current) === null || _refs$root$current === void 0 ? void 0 : _refs$root$current.ownerDocument) || window.document : undefined; if (parent) { if (touch) { parent.addEventListener('touchstart', onTouchStart, { passive: true }); rootDocument.addEventListener('touchend', onTouchUp, { passive: true }); rootDocument.addEventListener('touchcancel', onTouchCancel, { passive: true }); } else { parent.addEventListener('mousedown', onMouseDown); parent.addEventListener('mouseup', onMouseUp); rootDocument.addEventListener('mouseup', onMouseUp); parent.addEventListener('mouseenter', onMouseIn); parent.addEventListener('mouseleave', onMouseOut); } } refs.init.current = true; return () => { if (parent) { parent.removeEventListener('touchstart', onTouchStart); rootDocument.removeEventListener('touchend', onTouchUp); rootDocument.removeEventListener('touchcancel', onTouchCancel); parent.removeEventListener('mousedown', onMouseDown); parent.removeEventListener('mouseup', onMouseUp); rootDocument.removeEventListener('mouseup', onMouseUp); parent.removeEventListener('mouseenter', onMouseIn); parent.removeEventListener('mouseleave', onMouseOut); } }; }, [mobileDelay, touch]); _react.default.useEffect(() => { if (refs.init.current) { if (refs.interactions.current.length) setInteractions([]); removeWaves(); } }, [clear]); _react.default.useEffect(() => { if (pulse) { if (!refs.props.current.pulseOnMouseDown && has('mouse-down')) return; addWavePulse(); } else removeWaves(); }, [pulse]); const methods = version => { if (version === 'add') addWave(undefined, { origin: 'center' });else if (version === 'pulse') addWavePulse();else if (version === 'remove') removeWaves(); }; _react.default.useEffect(() => { let subscribed; if (subscription !== null && subscription !== void 0 && subscription.subscribe) subscribed = subscription.subscribe(methods); // Clean up return () => { var _subscribed; if ((_subscribed = subscribed) !== null && _subscribed !== void 0 && _subscribed.unsubscribe) subscribed.unsubscribe(); }; }, [subscription]); _react.default.useEffect(() => { if (disabled && refs.interactions.current.length) setInteractions([]); }, [disabled]); const addWave = (event_1, overrides = {}) => { const origin = overrides.origin !== undefined ? overrides.origin : refs.origin.current; if (refs.wave.current && !refs.props.current.disabled) { let top = 0; let left = 0; let width = '100%'; if (wave_version !== 'simple') { var _event_1$currentTarge, _ref; const rect = event_1 === null || event_1 === void 0 || (_event_1$currentTarge = event_1.currentTarget) === null || _event_1$currentTarge === void 0 ? void 0 : _event_1$currentTarge.getBoundingClientRect(); const root = (_ref = (event_1 === null || event_1 === void 0 ? void 0 : event_1.currentTarget) || refs.root.current.parentNode) === null || _ref === void 0 ? void 0 : _ref.getBoundingClientRect(); // Mouse or touch event const valuesEvent = !(event_1 !== null && event_1 !== void 0 && event_1.touches) ? event_1 : event_1.touches[0]; const values = { x: valuesEvent.x !== undefined ? valuesEvent.x : valuesEvent.clientX, y: valuesEvent.y !== undefined ? valuesEvent.y : valuesEvent.clientY }; values.offsetX = valuesEvent.offsetX !== undefined ? valuesEvent.offsetX : values.x - rect.x; values.offsetY = valuesEvent.offsetY !== undefined ? valuesEvent.offsetY : values.y - rect.y; const w = root.width; const h = root.height; const x = origin === 'center' || !event_1 ? w / 2 : rect ? values.x - rect.left : values.offsetX; const y = origin === 'center' || !event_1 ? h / 2 : rect ? values.y - rect.top : values.offsetY; width = Math.round(Math.sqrt( // Largest sub rectangle in value Math.max(x ** 2 + y ** 2, Math.abs(w - x) ** 2 + y ** 2, x ** 2 + Math.abs(h - y) ** 2, Math.abs(w - x) ** 2 + Math.abs(h - y) ** 2)) * 2); top = y - width / 2; left = x - width / 2; } setWaves(items => [...items, /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Transition, { duration: "complex", enterOnAdd: true, className: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: wave_version === 'simple' ? classes.waveSimple : classes.wave, style: { top: `${top}px`, left: `${left}px`, width: `${width}px`, height: `${width}px` } }) }, (0, _utils.getID)())]); } }; const addWavePulse = () => { if (refs.pulse.current && !refs.props.current.disabled) { // Remove previous wave // if there is one if (refs.waves.current.length) removeWaves(); const root_0 = refs.root.current.parentNode.getBoundingClientRect(); const w_0 = root_0.width; const h_0 = root_0.height; const x_0 = w_0 / 2; const y_0 = h_0 / 2; const width_0 = Math.round(Math.sqrt(x_0 ** 2 + y_0 ** 2) * 2); const top_0 = y_0 - width_0 / 2; const left_0 = x_0 - width_0 / 2; setWaves(items_0 => [...items_0, /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Transition, { duration: "complex", enterOnAdd: true, className: true, children: /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _styleReact.classNames)([classes.wave, classes.pulse]), style: { top: `${top_0}px`, left: `${left_0}px`, width: `${width_0}px`, height: `${width_0}px` } }) }, (0, _utils.getID)())]); } }; const removeWaves = () => { if (refs.waves.current.length) setWaves([]); }; const add = value => { if (!refs.props.current.disabled && !has(value)) setInteractions(items_1 => [...items_1, value]); }; const has = value_0 => refs.interactions.current.includes(value_0); const remove = value_1 => { if (has(value_1)) setInteractions(items_2 => [...items_2].filter(item => item !== value_1)); }; return /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { ref: item_0 => { if (ref) { if ((0, _utils.is)('function', ref)) ref(item_0);else ref.current = item_0; } refs.root.current = item_0; }, className: (0, _styleReact.classNames)([(0, _.staticClassName)('Interaction', theme) && ['onesy-Interaction-root', disabled && `onesy-Interaction-disabled`], className, classes.root]), children: [background && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _styleReact.classNames)([(0, _.staticClassName)('Interaction', theme) && ['onesy-Interaction-background'], classes.background, (preselected || has('mouse-in')) && classes.hovered, selected && classes.selected, dragged && classes.dragged]) }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Transitions, { TransitionProps: { noAbruption: true, duration: { enter: 'complex', exit: refs.mouse.current.press < 500 ? 350 : 500 }, style: { transitionDuration: refs.mouse.current.press < 500 ? 340 : 500 } }, children: waves }), hasBorder && /*#__PURE__*/(0, _jsxRuntime.jsx)(_.Transition, { in: border, children: status => /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: (0, _styleReact.classNames)([(0, _.staticClassName)('Interaction', theme) && ['onesy-Interaction-border'], classes.border]), style: { opacity: (status === null || status === void 0 ? void 0 : status.indexOf('enter')) > -1 ? theme.palette.visual_contrast.low.opacity.press : 0, transition: (status === null || status === void 0 ? void 0 : status.indexOf('exit')) > -1 ? theme.methods.transitions.make('opacity', { duration: 'complex', timing_function: 'standard' }) : undefined } }) })] }); }; Interaction.displayName = 'onesy-Interaction'; var _default = exports.default = Interaction;