UNPKG

@amaui/ui-react

Version:
350 lines (349 loc) 17.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = __importDefault(require("react")); const utils_1 = require("@amaui/utils"); const style_react_1 = require("@amaui/style-react"); const __1 = require(".."); const other = { pointerEvents: 'none', borderRadius: 'inherit', position: 'absolute', inset: '0', width: '100%', height: '100%' }; const useStyle = (0, style_react_1.style)(theme => ({ '@keyframes pulse': { '0%': { transform: 'scale(0.77)' }, '50%': { transform: 'scale(0.7)' }, '100%': { transform: 'scale(0.77)' } }, root: Object.assign(Object.assign({}, other), { overflow: 'hidden', // Bug fix for overflow in mobile Safari zIndex: '0' }), background: Object.assign(Object.assign({}, 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: Object.assign(Object.assign({}, other), { opacity: '0', boxShadow: 'inset 0 0 0 2px currentColor' }), wave: Object.assign(Object.assign({}, 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.default.opacity.quaternary, transform: 'scale(1)', }, '&.entered': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, transform: 'scale(1)', }, '&.exit': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, transform: 'scale(1)', }, '&.exiting': { opacity: '0', transform: 'scale(1)', }, '&.exited': { opacity: '0', transform: 'scale(1)', } }), pulse: { '&.entering': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, transform: 'scale(0.77)', }, '&.entered': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, transform: 'scale(0.77)', animation: `$pulse 2400ms ${theme.transitions.timing_function.emphasized} 240ms infinite`, }, '&.exit': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, transform: 'scale(0.7)' }, '&.exiting': { opacity: '0', transform: 'scale(0.7)' }, '&.exited': { opacity: '0', transform: 'scale(0.7)' } }, waveSimple: Object.assign(Object.assign({}, other), { opacity: '0.1', backgroundColor: 'currentcolor', transition: theme.methods.transitions.make(['opacity'], { duration: 'complex', timing_function: 'standard' }), '&.entering': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, }, '&.entered': { opacity: theme.palette.visual_contrast.default.opacity.quaternary, }, '&.exit': { opacity: theme.palette.visual_contrast.default.opacity.quaternary }, '&.exiting': { opacity: '0', }, '&.exited': { opacity: '0', } }) }), { name: 'amaui-Interaction' }); const Interaction = react_1.default.forwardRef((props_, ref) => { const theme = (0, style_react_1.useAmauiTheme)(); const props = react_1.default.useMemo(() => { var _a, _b, _c, _d, _e, _f, _g, _h; return (Object.assign(Object.assign(Object.assign({}, (_d = (_c = (_b = (_a = theme === null || theme === void 0 ? void 0 : theme.ui) === null || _a === void 0 ? void 0 : _a.elements) === null || _b === void 0 ? void 0 : _b.all) === null || _c === void 0 ? void 0 : _c.props) === null || _d === void 0 ? void 0 : _d.default), (_h = (_g = (_f = (_e = theme === null || theme === void 0 ? void 0 : theme.ui) === null || _e === void 0 ? void 0 : _e.elements) === null || _f === void 0 ? void 0 : _f.amauiInteraction) === null || _g === void 0 ? void 0 : _g.props) === null || _h === void 0 ? void 0 : _h.default), props_)); }, [props_]); const { wave = true, background = true, border: border_, pulse, origin: origin_, preselected, selected, dragged, wave_version, subscription, clear, disabled, className } = props; const { classes } = useStyle(); const [init, setInit] = react_1.default.useState(false); const [interactions, setInteractions] = react_1.default.useState([]); const [border, setBorder] = react_1.default.useState(false); const [waves, setWaves] = react_1.default.useState([]); const refs = { root: react_1.default.useRef(undefined), mouse: react_1.default.useRef({ down: 0, up: 0, press: 0 }), wave: react_1.default.useRef(undefined), pulse: react_1.default.useRef(undefined), touch: react_1.default.useRef(undefined), interactions: react_1.default.useRef(undefined), props: react_1.default.useRef(undefined) }; const touch = (0, __1.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; react_1.default.useEffect(() => { var _a; const parent = refs.root.current.parentNode; const onMouseIn = (event) => { if (refs.touch.current) return; add('mouse-in'); removeWaves(); }; const onMouseOut = (event) => { 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_1.debounce)(() => setBorder(false), theme.transitions.duration.sm); const onMouseUp = () => { 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; setInteractions(items => { if (items.indexOf('mouse-down') > -1) { // Border setBorder(true); updateBorder(); } return items; }); remove('mouse-down'); removeWaves(); }; const rootDocument = (0, utils_1.isEnvironment)('browser') ? (((_a = refs.root.current) === null || _a === void 0 ? void 0 : _a.ownerDocument) || window.document) : undefined; if (parent) { parent.addEventListener('mousedown', onMouseDown); parent.addEventListener('touchstart', onMouseDown, { passive: true }); parent.addEventListener('mouseup', onMouseUp); rootDocument.addEventListener('mouseup', onMouseUp); parent.addEventListener('touchend', onMouseUp, { passive: true }); rootDocument.addEventListener('touchend', onMouseUp, { passive: true }); parent.addEventListener('mouseenter', onMouseIn); // parent.addEventListener('touchstart', onMouseIn, { passive: true }); parent.addEventListener('mouseleave', onMouseOut); // parent.addEventListener('touchend', onMouseOut, { passive: true }); } setInit(true); return () => { if (parent) { parent.removeEventListener('mousedown', onMouseDown); parent.removeEventListener('touchstart', onMouseDown); parent.removeEventListener('mouseup', onMouseUp); rootDocument.removeEventListener('mouseup', onMouseUp); parent.removeEventListener('touchend', onMouseUp); rootDocument.removeEventListener('touchend', onMouseUp); parent.removeEventListener('mouseenter', onMouseIn); parent.removeEventListener('touchstart', onMouseIn); parent.removeEventListener('mouseleave', onMouseOut); parent.removeEventListener('touchend', onMouseOut); } }; }, []); react_1.default.useEffect(() => { if (init) { setInteractions([]); removeWaves(); } }, [clear]); react_1.default.useEffect(() => { if (pulse) { if (!refs.props.current.pulseOnMouseDown && has('mouse-down')) return; addWavePulse(); } else removeWaves(); }, [pulse]); const methods = react_1.default.useCallback((version) => { if (version === 'add') addWave(undefined, { origin: 'center' }); else if (version === 'pulse') addWavePulse(); else if (version === 'remove') removeWaves(); }, []); react_1.default.useEffect(() => { let subscribed; if (subscription === null || subscription === void 0 ? void 0 : subscription.subscribe) subscribed = subscription.subscribe(methods); // Clean up return () => { if (subscribed === null || subscribed === void 0 ? void 0 : subscribed.unsubscribe) subscribed.unsubscribe(); }; }, [subscription]); react_1.default.useEffect(() => { if (disabled) setInteractions([]); }, [disabled]); const addWave = react_1.default.useCallback((event, overrides = {}) => { var _a, _b; const origin = overrides.origin !== undefined ? overrides.origin : origin_; if (refs.wave.current && !refs.props.current.disabled) { let top = 0; let left = 0; let width = '100%'; if (wave_version !== 'simple') { const rect = (_a = event === null || event === void 0 ? void 0 : event.currentTarget) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect(); const root = (_b = (((event === null || event === void 0 ? void 0 : event.currentTarget) || refs.root.current.parentNode))) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect(); // Mouse or touch event const valuesEvent = (!(event === null || event === void 0 ? void 0 : event.touches) ? event : event.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) ? w / 2 : rect ? values.x - rect.left : values.offsetX; const y = (origin === 'center' || !event) ? 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, ((0, jsx_runtime_1.jsx)(__1.Transition, Object.assign({ duration: 'complex', enterOnAdd: true, className: true }, { children: (0, jsx_runtime_1.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_1.getID)())) ]); } }, []); const addWavePulse = react_1.default.useCallback(() => { if (refs.pulse.current && !refs.props.current.disabled) { // Remove previous wave // if there is one if (waves.length) removeWaves(); const root = refs.root.current.parentNode.getBoundingClientRect(); const w = root.width; const h = root.height; const x = w / 2; const y = h / 2; const width = Math.round(Math.sqrt(x ** 2 + y ** 2) * 2); const top = y - width / 2; const left = x - width / 2; setWaves(items => [ ...items, ((0, jsx_runtime_1.jsx)(__1.Transition, Object.assign({ duration: 'complex', enterOnAdd: true, className: true }, { children: (0, jsx_runtime_1.jsx)("span", { className: (0, style_react_1.classNames)([classes.wave, classes.pulse]), style: { top: `${top}px`, left: `${left}px`, width: `${width}px`, height: `${width}px` } }) }), (0, utils_1.getID)())) ]); } }, []); const removeWaves = react_1.default.useCallback(() => setWaves([]), []); const add = react_1.default.useCallback((value) => { if (!refs.props.current.disabled) { setInteractions(items => { const newItems = [...items]; if (newItems.indexOf(value) === -1) newItems.push(value); return newItems; }); } }, []); const has = react_1.default.useCallback((value) => refs.interactions.current.includes(value), []); const remove = react_1.default.useCallback((value) => setInteractions(items => [...items].filter(item => item !== value)), []); return ((0, jsx_runtime_1.jsxs)("span", Object.assign({ ref: item => { if (ref) { if ((0, utils_1.is)('function', ref)) ref(item); else ref.current = item; } refs.root.current = item; }, className: (0, style_react_1.classNames)([ (0, __1.staticClassName)('Interaction', theme) && [ 'amaui-Interaction-root', disabled && `amaui-Interaction-disabled` ], className, classes.root ]) }, { children: [background && ((0, jsx_runtime_1.jsx)("span", { className: (0, style_react_1.classNames)([ (0, __1.staticClassName)('Interaction', theme) && [ 'amaui-Interaction-background' ], classes.background, (preselected || has('mouse-in')) && classes.hovered, selected && classes.selected, dragged && classes.dragged ]) })), (0, jsx_runtime_1.jsx)(__1.Transitions, Object.assign({ 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 })), border_ && ((0, jsx_runtime_1.jsx)(__1.Transition, Object.assign({ in: border }, { children: (status) => ((0, jsx_runtime_1.jsx)("span", { className: (0, style_react_1.classNames)([ (0, __1.staticClassName)('Interaction', theme) && [ 'amaui-Interaction-border' ], classes.border ]), style: { opacity: (status === null || status === void 0 ? void 0 : status.indexOf('enter')) > -1 ? theme.palette.visual_contrast.default.opacity.quaternary : 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 = 'amaui-Interaction'; exports.default = Interaction;