UNPKG

@amaui/ui-react

Version:
484 lines (483 loc) 25.9 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; 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 IconMaterialNavigateNextW100_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialNavigateNextW100")); const IconMaterialNavigateBeforeW100_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialNavigateBeforeW100")); const IconMaterialCloseW100_1 = __importDefault(require("@amaui/icons-material-rounded-react/IconMaterialCloseW100")); const Image_1 = __importDefault(require("../Image")); const Line_1 = __importDefault(require("../Line")); const IconButton_1 = __importDefault(require("../IconButton")); const Interaction_1 = __importDefault(require("../Interaction")); const Backdrop_1 = __importDefault(require("../Backdrop")); const utils_2 = require("../utils"); const useMediaQuery_1 = __importDefault(require("../useMediaQuery")); const useStyle = (0, style_react_1.style)(theme => ({ root: { position: 'relative', '&.amaui-Backdrop-root': { display: 'flex', alignItems: 'center', justifyContent: 'center', userSelect: 'none', zIndex: '14000' }, '& .amaui-Backdrop-backdrop-root': { width: '100%', height: '100%', pointerEvents: 'none' } }, version_regular: { minHeight: 'clamp(240px, 100%, 100vh)' }, pointerEventsAuto: { pointerEvents: 'auto' }, wrapper: { height: '100%' }, header: { padding: theme.methods.space.value(3, 'px'), zIndex: '1' }, main: { position: 'relative', zIndex: '14' }, main_version_modal: { height: '0', padding: theme.methods.space.value(5, 'px'), '& .amaui-Image-root': { maxHeight: '100%', // pointerEvents: 'none' } }, main_version_regular_size_small: { height: '340px' }, main_version_regular_size_regular: { height: '540px' }, main_version_regular_size_large: { height: '740px' }, noOverflow: { overflow: 'hidden' }, footer: { padding: `${theme.methods.space.value(3, 'px')} ${theme.methods.space.value(1.5, 'px')}`, zIndex: '1' }, imageWrapper: { position: 'relative', height: '0px', pointerEvents: 'none', // zIndex: 1, transition: theme.methods.transitions.make(['transform'], { duration: 100, timing_function: 'ease' }) }, image: { objectFit: 'contain', width: 'auto', height: 'auto', maxHeight: '100%', maxWidth: '100%' }, itemsWrapper: { position: 'relative', pointerEvents: 'auto', maxWidth: '100%', userSelect: 'none' }, items: { maxWidth: '1024px', overflow: 'auto hidden', '&::-webkit-scrollbar': { width: '16px', height: '16px' }, '&::-webkit-scrollbar-track, &::-webkit-scrollbar-corner': { background: 'transparent' }, '&::-webkit-scrollbar-thumb': { borderRadius: theme.methods.shape.radius.value(1, 'px'), border: '4px solid transparent', backgroundClip: 'content-box', backgroundColor: 'rgba(221, 221, 221, 0.4)', '&:hover': { backgroundColor: 'rgba(221, 221, 221, 0.7)' } } }, item: { width: '140px', height: '140px', position: 'relative', backgroundSize: 'contain', backgroundPosition: 'center', backgroundRepeat: 'no-repeat', flex: '0 0 auto', border: '2px solid transparent', cursor: 'pointer', userSelect: 'none', transition: theme.methods.transitions.make(['border', 'transform']), '&:active': { transform: 'scale(0.94)' } }, itemSelected: { border: '2px solid !important', borderColor: `${theme.methods.palette.color.value('secondary', 30)} !important` }, arrow: { flex: '0 0 auto', alignSelf: 'center', justifySelf: 'center', transition: theme.methods.transitions.make(['opacity'], { duration: 'xxs' }), '&[disabled]': { opacity: '0' } } }), { name: 'amaui-ImageGallery' }); const ImageGallery = react_1.default.forwardRef((props_, ref) => { var _a, _b, _c, _d; 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.amauiImageGallery) === null || _g === void 0 ? void 0 : _g.props) === null || _h === void 0 ? void 0 : _h.default), props_)); }, [props_]); const Line = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Line) || Line_1.default; }, [theme]); const Image = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Image) || Image_1.default; }, [theme]); const IconButton = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.IconButton) || IconButton_1.default; }, [theme]); const Interaction = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Interaction) || Interaction_1.default; }, [theme]); const Backdrop = react_1.default.useMemo(() => { var _a; return ((_a = theme === null || theme === void 0 ? void 0 : theme.elements) === null || _a === void 0 ? void 0 : _a.Backdrop) || Backdrop_1.default; }, [theme]); const { version = 'modal', size = 'regular', open: open_, onClose: onClose_, value: value_, items, minZoom: minZoom_ = 1, maxZoom: maxZoom_ = 2, incrementZoom = 0.07, overflow = true, arrows = true, startMain, endMain, startImage, endImage, startThumbnails, endThumbnails, ImageProps, ImageWrapperProps, IconButtonProps, IconStart = IconMaterialNavigateBeforeW100_1.default, IconEnd = IconMaterialNavigateNextW100_1.default, IconClose = IconMaterialCloseW100_1.default, className } = props, other = __rest(props, ["version", "size", "open", "onClose", "value", "items", "minZoom", "maxZoom", "incrementZoom", "overflow", "arrows", "startMain", "endMain", "startImage", "endImage", "startThumbnails", "endThumbnails", "ImageProps", "ImageWrapperProps", "IconButtonProps", "IconStart", "IconEnd", "IconClose", "className"]); const { classes } = useStyle(); const [loaded, setLoaded] = react_1.default.useState(false); const [open, setOpen] = react_1.default.useState(false); const [value, setValue] = react_1.default.useState(0); const [moveValue, setMoveValue] = react_1.default.useState(); const [imageRef, setImageRef] = react_1.default.useState(); const [keyDown, setKeyDown] = react_1.default.useState(); const refs = { root: react_1.default.useRef(undefined), version: react_1.default.useRef(version), more: react_1.default.useRef(undefined), image: react_1.default.useRef(), imageWrapper: react_1.default.useRef(undefined), media: react_1.default.useRef(undefined), zoom: react_1.default.useRef(undefined), incrementZoom: react_1.default.useRef(undefined), minZoom: react_1.default.useRef(undefined), maxZoom: react_1.default.useRef(undefined), mouseDown: react_1.default.useRef(undefined), mouseMovePrevious: react_1.default.useRef(undefined), keyDown: react_1.default.useRef(keyDown), useZoom: react_1.default.useRef(false) }; const touch = (0, useMediaQuery_1.default)('(pointer: coarse)', { element: refs.root.current }); const minZoom = (0, utils_1.clamp)(minZoom_, 0.1, 1); const maxZoom = (0, utils_1.clamp)(maxZoom_, 1, 100); const length = (0, utils_1.clamp)(((items === null || items === void 0 ? void 0 : items.length) || 0) - 1, 0); const media = items === null || items === void 0 ? void 0 : items[value]; refs.version.current = version; refs.media.current = !!media; refs.keyDown.current = keyDown; refs.useZoom.current = version === 'modal' || keyDown; refs.incrementZoom.current = incrementZoom; refs.minZoom.current = minZoom; refs.maxZoom.current = maxZoom; const init = react_1.default.useCallback(() => { setTimeout(() => { var _a, _b; setMoveValue({ left: (_a = refs.more.current) === null || _a === void 0 ? void 0 : _a.scrollLeft, top: (_b = refs.more.current) === null || _b === void 0 ? void 0 : _b.scrollTop }); setLoaded(true); }, 14); }, []); const cleanUp = react_1.default.useCallback(() => { refs.mouseDown.current = false; }, []); react_1.default.useEffect(() => { const onKeyDown = (event) => { setKeyDown(event.metaKey || event.ctrlKey); }; const onKeyUp = (event) => { setKeyDown(null); }; window.document.addEventListener('keydown', onKeyDown); window.document.addEventListener('keyup', onKeyUp); return () => { window.document.removeEventListener('keydown', onKeyDown); window.document.removeEventListener('keyup', onKeyUp); }; }, []); react_1.default.useEffect(() => { // init if (open) init(); else cleanUp(); }, [open]); react_1.default.useEffect(() => { if (open_ !== undefined && open !== open_) setOpen(open_); }, [open_]); react_1.default.useEffect(() => { if (value_ !== undefined && value !== value_) setValue((0, utils_1.clamp)(value_, 0, length)); }, [value_]); const onResetZoom = react_1.default.useCallback(() => { refs.zoom.current = null; if (refs.imageWrapper.current) { refs.imageWrapper.current.style.transition = 'none'; refs.imageWrapper.current.style.removeProperty('transform'); refs.imageWrapper.current.style.removeProperty('left'); refs.imageWrapper.current.style.removeProperty('top'); setTimeout(() => { refs.imageWrapper.current.style.removeProperty('transition'); }, 14); } }, []); const onValue = react_1.default.useCallback((index) => { onResetZoom(); setValue(index); }, [onResetZoom]); const onOpen = react_1.default.useCallback(() => { setOpen(true); }, []); const onClose = react_1.default.useCallback(() => { setOpen(false); setTimeout(() => { setLoaded(false); }, 140); if ((0, utils_1.is)('function', onClose_)) onClose_(); }, [onClose_]); const move = (forward_ = true) => { const forward = forward_; const rect = refs.more.current.getBoundingClientRect(); const moveValue_ = { left: refs.more.current.scrollLeft + (forward ? 1 : -1) * rect.width, behavior: 'smooth' }; refs.more.current.scrollTo(moveValue_); }; const onMouseDown = react_1.default.useCallback((event) => { refs.mouseDown.current = true; refs.mouseMovePrevious.current = { x: event.clientX, y: event.clientY }; }, []); const onMouseUp = react_1.default.useCallback(() => { refs.mouseDown.current = false; refs.mouseMovePrevious.current = null; }, []); const onWheel = react_1.default.useCallback((event) => { var _a, _b, _c; if (!refs.useZoom.current) return; event.preventDefault(); event.stopPropagation(); let scale = ((_a = refs.zoom.current) === null || _a === void 0 ? void 0 : _a.scale) !== undefined ? refs.zoom.current.scale : 1; const part = refs.incrementZoom.current; const up = event.wheelDelta > 0 || event.deltaY < 0; scale = (0, utils_1.clamp)(up ? scale + part : scale - part, refs.minZoom.current, refs.maxZoom.current); // Only allow in 100's decimal places, ie. 1.01 scale = Math.round(scale * 100) / 100; const imageBoundingRect = (_b = refs.image.current) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect(); if (imageBoundingRect.width <= window.innerWidth) { refs.imageWrapper.current.style.removeProperty('left'); } if (imageBoundingRect.height <= window.innerHeight) { refs.imageWrapper.current.style.removeProperty('top'); } if (scale !== ((_c = refs.zoom.current) === null || _c === void 0 ? void 0 : _c.scale)) { refs.zoom.current = { scale }; refs.imageWrapper.current.style.transform = `scale(${scale})`; } }, []); const onMouseMove = react_1.default.useCallback((event) => { var _a, _b, _c, _d, _e, _f, _g, _h; if (!refs.useZoom.current) return; if (!(refs.mouseDown.current && refs.image.current)) return; const x = event.x - (((_a = refs.mouseMovePrevious.current) === null || _a === void 0 ? void 0 : _a.x) || 0); const y = event.y - (((_b = refs.mouseMovePrevious.current) === null || _b === void 0 ? void 0 : _b.y) || 0); refs.mouseMovePrevious.current = { x: event.clientX, y: event.clientY }; let left = Number((_e = (_d = (_c = refs.imageWrapper.current) === null || _c === void 0 ? void 0 : _c.style) === null || _d === void 0 ? void 0 : _d.left) === null || _e === void 0 ? void 0 : _e.replace('px', '')) || 0; let top = Number((_h = (_g = (_f = refs.imageWrapper.current) === null || _f === void 0 ? void 0 : _f.style) === null || _g === void 0 ? void 0 : _g.top) === null || _h === void 0 ? void 0 : _h.replace('px', '')) || 0; const imageBoundingRect = refs.image.current.getBoundingClientRect(); if ((imageBoundingRect.left <= 0 && ((imageBoundingRect.left + x <= 0) && (imageBoundingRect.width + imageBoundingRect.left + x >= window.innerWidth)))) { left += x; refs.imageWrapper.current.style.left = `${left}px`; } if ((imageBoundingRect.top <= 0 && ((imageBoundingRect.top + y <= 0) && (imageBoundingRect.height + imageBoundingRect.top + y >= window.innerHeight)))) { top += y; refs.imageWrapper.current.style.top = `${top}px`; } }, []); react_1.default.useEffect(() => { if (refs.useZoom.current) { if (imageRef) imageRef.addEventListener('wheel', onWheel, { passive: false }); window.addEventListener('mousemove', onMouseMove); window.addEventListener('mouseup', onMouseUp); window.addEventListener('touchend', onMouseUp); } return () => { if (imageRef) imageRef.removeEventListener('wheel', onWheel); window.removeEventListener('mousemove', onMouseMove); window.removeEventListener('mouseup', onMouseUp); window.removeEventListener('touchend', onMouseUp); }; }, [imageRef, refs.useZoom.current]); const onScroll = react_1.default.useCallback((event) => { if (!refs.useZoom.current) return; if (arrows) { setMoveValue({ left: refs.more.current.scrollLeft, top: refs.more.current.scrollTop }); } }, [arrows]); const iconButtonProps = Object.assign({ version: 'filled', color: 'default', tonal: true, size: 'small' }, IconButtonProps); const arrowPre = moveValue && ((0, jsx_runtime_1.jsx)(IconButton, Object.assign({ onClick: () => move(false), disabled: !moveValue || ((_a = refs.more.current) === null || _a === void 0 ? void 0 : _a.scrollLeft) === 0 }, iconButtonProps, { className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-arrow', 'amaui-ImageGallery-arrow-start' ], iconButtonProps === null || iconButtonProps === void 0 ? void 0 : iconButtonProps.className, classes.arrow ]) }, { children: (0, jsx_runtime_1.jsx)(IconStart, {}) }))); const arrowPost = moveValue && ((0, jsx_runtime_1.jsx)(IconButton, Object.assign({ onClick: () => move(), disabled: Math.ceil(((_b = refs.more.current) === null || _b === void 0 ? void 0 : _b.clientWidth) + ((_c = refs.more.current) === null || _c === void 0 ? void 0 : _c.scrollLeft)) === ((_d = refs.more.current) === null || _d === void 0 ? void 0 : _d.scrollWidth) }, iconButtonProps, { className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-arrow', 'amaui-ImageGallery-arrow-end' ], iconButtonProps === null || iconButtonProps === void 0 ? void 0 : iconButtonProps.className, classes.arrow ]) }, { children: (0, jsx_runtime_1.jsx)(IconEnd, {}) }))); const more = !!(items === null || items === void 0 ? void 0 : items.length); const onDragStartImage = react_1.default.useCallback((event) => { event.preventDefault(); }, []); const url = (media === null || media === void 0 ? void 0 : media.url) || (media === null || media === void 0 ? void 0 : media.urlSmall) || ((0, utils_1.is)('string', media) ? media : ''); const main = (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(Line, Object.assign({ justify: 'center', align: 'center', flex: true, fullWidth: true, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-main' ], classes.main, classes[`main_version_${version}`], classes[`main_version_${version}_size_${size}`], !overflow && classes.noOverflow ]) }, { children: [startMain, (0, jsx_runtime_1.jsxs)(Line, Object.assign({ ref: refs.imageWrapper, justify: 'center', align: 'center', fullWidth: true, flex: true }, ImageWrapperProps, { className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-image-wrapper' ], ImageWrapperProps === null || ImageWrapperProps === void 0 ? void 0 : ImageWrapperProps.className, classes.imageWrapper ]), style: Object.assign({}, ImageWrapperProps === null || ImageWrapperProps === void 0 ? void 0 : ImageWrapperProps.style) }, { children: [startImage, url && ((0, jsx_runtime_1.jsx)(Image, Object.assign({ ref: (item) => { refs.image.current = item; setImageRef(item); }, src: url, alt: media === null || media === void 0 ? void 0 : media.name, onMouseDown: onMouseDown, onMouseUp: onMouseUp, onTouchStart: onMouseDown, onTouchEnd: onMouseUp, onDragStart: onDragStartImage, lazyLoad: version === 'regular' }, ImageProps, { className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-image' ], ImageProps === null || ImageProps === void 0 ? void 0 : ImageProps.className, classes.image, classes.pointerEventsAuto ]) }))), endImage] })), endMain] })), more && ((0, jsx_runtime_1.jsx)(Line, Object.assign({ align: 'center', fullWidth: true, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-footer' ], classes.footer ]) }, { children: (0, jsx_runtime_1.jsxs)(Line, Object.assign({ gap: 1.5, direction: 'row', justify: 'center', align: 'center', className: (0, style_react_1.classNames)([ classes.itemsWrapper ]) }, { children: [startThumbnails, arrows && arrowPre, (0, jsx_runtime_1.jsx)(Line, Object.assign({ ref: refs.more, gap: 1, direction: 'row', align: 'center', justify: 'flex-start', fullWidth: true, onScroll: onScroll, className: (0, style_react_1.classNames)([ classes.items ]) }, { children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(Line, Object.assign({ onClick: () => onValue(index), className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-item', value === index && 'amaui-ImageGallery-item-selected' ], classes.item, value === index && classes.itemSelected ]), style: { backgroundImage: `url('${(item === null || item === void 0 ? void 0 : item.urlSmall) || (item === null || item === void 0 ? void 0 : item.url) || item}')` } }, { children: (0, jsx_runtime_1.jsx)(Interaction, {}) })))) })), arrows && arrowPost, endThumbnails] })) })))] }); if (version === 'regular') { return ((0, jsx_runtime_1.jsx)(Line, Object.assign({ ref: item => { if (ref) { if ((0, utils_1.is)('function', ref)) ref(item); else ref.current = item; } refs.root.current = item; }, fullWidth: true, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-root', `amaui-ImageGallery-version-${version}`, `amaui-ImageGallery-size-${size}` ], className, classes.root, classes[`version_${version}`] ]) }, other, { children: main }))); } return ((0, jsx_runtime_1.jsx)(Backdrop, Object.assign({ ref: item => { if (ref) { if ((0, utils_1.is)('function', ref)) ref(item); else ref.current = item; } refs.root.current = item; }, open: open, onClose: onClose, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-root', `amaui-ImageGallery-version-${version}` ], className, classes.root, classes[`version_${version}`] ]) }, other, { children: (0, jsx_runtime_1.jsxs)(Line, Object.assign({ gap: 0, fullWidth: true, className: classes.wrapper }, { children: [(0, jsx_runtime_1.jsx)(Line, Object.assign({ direction: 'row', justify: 'flex-end', fullWidth: true, className: (0, style_react_1.classNames)([ (0, utils_2.staticClassName)('ImageGallery', theme) && [ 'amaui-ImageGallery-header' ], classes.header ]) }, { children: (0, jsx_runtime_1.jsx)(IconButton, Object.assign({ version: 'filled', color: theme.palette.light ? 'default' : 'inverted', onClick: onClose, className: (0, style_react_1.classNames)([ classes.pointerEventsAuto ]) }, { children: (0, jsx_runtime_1.jsx)(IconClose, {}) })) })), main] })) }))); }); ImageGallery.displayName = 'amaui-ImageGallery'; exports.default = ImageGallery;