@onesy/ui-react
Version:
UI for React
438 lines (435 loc) • 17 kB
JavaScript
"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;