@geneui/components
Version:
The Gene UI components library designed for BI tools
220 lines (214 loc) • 18.6 kB
JavaScript
import { _ as __rest } from '../tslib.es6-f211516f.js';
import React__default, { forwardRef, useRef, useState, useImperativeHandle, useCallback, useEffect } from 'react';
import Portal from '../Portal/index.js';
import { c as classnames } from '../index-031ff73c.js';
import { f as fileSizeDisplay, n as noop } from '../index-a0e4e333.js';
import '../configs-00612ce0.js';
import useImgDownload from '../hooks/useImgDownload.js';
import { u as useEllipsisDetection } from '../useEllipsisDetection-4d997d5d.js';
import Icon from '../Icon/index.js';
import Switcher from '../Switcher/index.js';
import { T as Tooltip } from '../index-6d7e99cd.js';
import { s as styleInject } from '../style-inject.es-746bb8ed.js';
import 'react-dom';
import 'prop-types';
import '../GeneUIProvider/index.js';
import '../dateValidation-67caec66.js';
import '../_commonjsHelpers-24198af3.js';
import '../hooks/useDebounce.js';
import '../_rollupPluginBabelHelpers-e8fb2e5c.js';
import '../hooks/useKeyDown.js';
import '../checkboxRadioSwitcher-5b69d7bd.js';
import '../guid-8ddf77b3.js';
import '../hooks/useDeviceType.js';
import '../hooks/useWindowSize.js';
const bufferSize = 40;
const borderWidth = 2;
const Magnifier = forwardRef(({ imgUrl, className, name = '', withRotation = false, withMagnifier = false, showMagnifier = false, zoom = 1.5, magnifierAppearance = 'square' }, ref) => {
const imgRef = useRef(null);
const glassRef = useRef(null);
const [rotationDeg, setRotationDeg] = useState(0);
const [isCursorInScopeOfImage, setIsCursorInScopeOfImage] = useState(false);
const [glassPositionStyles, setGlassPositionStyles] = useState({});
const rotate = (deg = 90) => {
if (!withRotation)
return;
const newDeg = rotationDeg + deg;
setRotationDeg(Math.abs(newDeg) >= 360 ? 0 : newDeg);
};
useImperativeHandle(ref, () => ({
rotate
}));
const onMouseMoveHandler = useCallback((e) => {
var _a, _b;
// Prevent any calculation in case of magnifier is turned off
if (!withMagnifier || !imgRef.current || !glassRef.current)
return;
e.preventDefault();
const img = imgRef.current;
const cnt = img.offsetParent;
if (!cnt)
return;
const glassWidth = ((_a = glassRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) / 2;
const glassHeight = ((_b = glassRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) / 2;
// Positive value of rotation deg
const absRotationDeg = Math.abs(rotationDeg);
const { clientX, clientY } = e;
const stylesProps = {};
// @TODO need move to useMemo hooks for better performance
const { bottom, height, left, right, top, width } = cnt.getBoundingClientRect();
let x = clientX - left - glassWidth;
let y = clientY - top - glassHeight;
// Calculate horizontal thresholds for img
if (clientX < left + bufferSize)
x = -glassWidth + bufferSize;
if (clientX > right - bufferSize)
x = width - bufferSize - glassWidth;
// Calculate vertical thresholds for img
if (clientY < top + bufferSize)
y = -glassHeight + bufferSize;
if (clientY > bottom - bufferSize)
y = height - glassHeight - bufferSize;
// Handle vertical rotation cases
if (rotationDeg === 0 || absRotationDeg === 180) {
if (rotationDeg === 0) {
// Adoption coordinates values to img sides
stylesProps.left = `${x}px`;
stylesProps.top = `${y}px`;
// Calculate zoomed image positions
const glassX = x * zoom + bufferSize * zoom + borderWidth * 2;
const glassY = y * zoom + bufferSize * zoom + borderWidth * 2;
stylesProps.backgroundPosition = `-${glassX}px -${glassY}px`;
}
if (absRotationDeg === 180) {
// Adoption coordinates values to img sides
stylesProps.right = `${x}px`;
stylesProps.bottom = `${y}px`;
// Calculate zoomed image positions
const glassX = width * zoom - glassWidth - 40 * zoom - (x * zoom + 40 * zoom);
const glassY = height * zoom - glassHeight - 40 * zoom - (y * zoom + 40 * zoom);
stylesProps.backgroundPosition = `-${glassX}px -${glassY}px`;
}
}
// Handle horizontal rotation cases
if (absRotationDeg === 90 || absRotationDeg === 270) {
if (rotationDeg === 90 || rotationDeg === -270) {
// Adoption coordinates values to img sides
stylesProps.bottom = `${x}px`; // x
stylesProps.left = `${y}px`; // y
// Calculate zoomed image positions
const glassX = img.height * zoom - glassHeight - 40 * zoom - (x * zoom + 40 * zoom);
const glassY = y * zoom + 40 * zoom;
stylesProps.backgroundPosition = `-${glassY}px -${glassX}px`;
}
if (rotationDeg === 270 || rotationDeg === -90) {
// Adoption coordinates values to img sides
stylesProps.top = `${x}px`; // x
stylesProps.right = `${y}px`; // y
// Calculate zoomed image positions
const glassX = x * zoom + 40 * zoom;
const glassY = img.width * zoom - glassWidth - 40 * zoom - (y * zoom + 40 * zoom);
stylesProps.backgroundPosition = `-${glassY}px -${glassX}px`;
}
}
setGlassPositionStyles(stylesProps);
}, [rotationDeg]);
const onMouseEnterHandler = () => showMagnifier && setIsCursorInScopeOfImage(true);
const onMouseLeaveHandler = (e) => {
if (e.relatedTarget !== glassRef.current) {
setIsCursorInScopeOfImage(false);
}
};
return (React__default.createElement(React__default.Fragment, null,
React__default.createElement("div", { className: "imgMagnifier", style: {
transform: `rotateZ(${rotationDeg}deg)`
} },
withMagnifier && showMagnifier && isCursorInScopeOfImage && (React__default.createElement("div", { ref: glassRef, className: "imgMagnifier__glass", style: Object.assign({ borderRadius: `${magnifierAppearance === 'circle' ? 50 : 0}%`, backgroundImage: `url(${imgUrl})`, backgroundRepeat: 'no-repeat', backgroundSize: imgRef.current
? `${imgRef.current.clientWidth * zoom}px ${imgRef.current.clientHeight * zoom}px`
: `0 0` }, glassPositionStyles), onMouseLeave: onMouseLeaveHandler, onMouseMove: onMouseMoveHandler })),
React__default.createElement("img", { ref: imgRef, src: imgUrl, alt: name, onMouseEnter: onMouseEnterHandler, onMouseMove: (e) => showMagnifier && onMouseMoveHandler(e), className: `imgMagnifier__img ${className}` }))));
});
var css_248z = "[data-gene-ui-version=\"2.16.5\"] .imagePreview{display:flex;flex-direction:column;max-height:100%;max-width:100%;min-width:320px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__close{display:flex}[data-gene-ui-version=\"2.16.5\"] .imagePreview.mobile-view .imagePreview__close{margin-left:auto}[data-gene-ui-version=\"2.16.5\"] [dir=rtl] .imagePreview.mobile-view .imagePreview__close{margin-left:0;margin-right:auto}[data-gene-ui-version=\"2.16.5\"] .imagePreview__header{align-items:center;display:flex;justify-content:space-between;padding:16px;width:100%}[data-gene-ui-version=\"2.16.5\"] .imagePreview.mobile-view .imagePreview__header{align-items:flex-start;flex-direction:column-reverse;padding:8px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__infoWrapper{align-items:center;align-self:stretch;display:flex;max-width:calc(100% - 250px)}[data-gene-ui-version=\"2.16.5\"] .imagePreview.mobile-view .imagePreview__infoWrapper{max-width:100%}[data-gene-ui-version=\"2.16.5\"] .imagePreview__info{display:flex;flex-direction:column;font-size:14px;font-weight:600;height:100%;justify-content:center;max-width:calc(100% - 28px);padding:4px 0}[data-gene-ui-version=\"2.16.5\"] .imagePreview__info-center{justify-content:center}[data-gene-ui-version=\"2.16.5\"] .imagePreview__imgIcon{opacity:.8}[data-gene-ui-version=\"2.16.5\"] .imagePreview__sizes{display:flex}[data-gene-ui-version=\"2.16.5\"] .imagePreview__weight{opacity:.8;padding-right:8px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__resolution{opacity:.8;padding-left:8px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__resolution--divider{opacity:.8;padding-left:0}[data-gene-ui-version=\"2.16.5\"] .imagePreview__resolution--separate{margin:0 5px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__options{align-items:center;display:flex}[data-gene-ui-version=\"2.16.5\"] .imagePreview.mobile-view .imagePreview__options{width:100%}[data-gene-ui-version=\"2.16.5\"] .imagePreview__magnifier{min-width:-webkit-fit-content;min-width:-moz-fit-content;min-width:fit-content;padding-right:8px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__rotate{display:flex}[data-gene-ui-version=\"2.16.5\"] .imagePreview__divider,[data-gene-ui-version=\"2.16.5\"] .imagePreview__divider-small{position:relative}[data-gene-ui-version=\"2.16.5\"] .imagePreview__divider-small:after{background:rgba(var(--background-sc-rgb),.3);content:\"\";height:12px;position:absolute;right:0;top:50%;transform:translateY(-50%);width:1px}[data-gene-ui-version=\"2.16.5\"] [dir=rtl] .imagePreview__divider-small{margin:0 5px}[data-gene-ui-version=\"2.16.5\"] .imagePreview.mobile-view .imagePreview__divider{margin-right:6px}[data-gene-ui-version=\"2.16.5\"] .imagePreview__icon{cursor:pointer;font-size:28px;font-weight:100;margin:6px}[data-gene-ui-version=\"2.16.5\"] .imagePreview.mobile-view .imagePreview__icon{margin-left:0}[data-gene-ui-version=\"2.16.5\"] .imagePreview__content{align-items:center;aspect-ratio:1;display:flex;justify-content:center}[data-gene-ui-version=\"2.16.5\"] .imagePreview__img{max-height:100%;max-width:100%}[data-gene-ui-version=\"2.16.5\"] [dir=rtl] .imagePreview__name{padding-right:8px}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view{height:100%;left:0;position:fixed;top:0;width:100%;z-index:500}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__header{background:#000}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__infoWrapper,[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__name{color:#fff}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__sizes{color:#fff9}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__options{color:#fff}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__magnifier .switcher-element{background:#ffffff61}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__magnifier .switcher-element.active{background:var(--hero)}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__divider:after{background:#ffffff4d;content:\"\";height:24px;position:absolute;right:0;top:50%;transform:translateY(-50%);width:1px}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__divider-small:after{background:#ffffff4d}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__content{height:100%;transform:translateZ(0);width:100%}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__background{background-color:#000c;height:100%;position:absolute;width:100%}[data-gene-ui-version=\"2.16.5\"] .imagePreview.modal-view .imagePreview__img{margin:0 auto;max-height:calc(100vh - 10rem);max-width:calc(100vh - 10rem)}[data-gene-ui-version=\"2.16.5\"] .imgMagnifier{position:relative}[data-gene-ui-version=\"2.16.5\"] .imgMagnifier__glass{border:2px solid #000;cursor:none;height:150px;position:absolute;width:150px;z-index:999999}[data-gene-ui-version=\"2.16.5\"] .imgMagnifier__img{width:100%}";
styleInject(css_248z);
const ImagePreview = (_a) => {
var { name, path, onClose = noop, showSize = true, isMobile = false, withModal = true, showRotate = true, showDownload = true, customHeaders, showDimensions = true, withMagnifier = false, magnifierDefaultValue = true } = _a, rest = __rest(_a, ["name", "path", "onClose", "showSize", "isMobile", "withModal", "showRotate", "showDownload", "customHeaders", "showDimensions", "withMagnifier", "magnifierDefaultValue"]);
const [isMagnifierOn, setIsMagnifierOn] = useState(magnifierDefaultValue);
const [imageData, setImageData] = useState('');
const [meta, setMeta] = useState({
size: 0,
width: 0,
height: 0
});
const nameRef = useRef(null);
const magnifierRef = useRef(null);
const isTruncated = useEllipsisDetection(nameRef);
const downloadImg = useImgDownload();
useEffect(() => {
!!path &&
fetch(path, { headers: Object.assign({}, customHeaders) })
.then((r) => r.arrayBuffer())
.then((buffer) => {
const img = new Image();
const blob = new Blob([buffer], { type: 'image/jpeg' });
img.src = URL.createObjectURL(blob);
img.onload = () => setMeta((val) => (Object.assign(Object.assign({}, val), { width: img.naturalWidth, height: img.naturalHeight })));
setMeta((val) => (Object.assign(Object.assign({}, val), { size: buffer.byteLength })));
setImageData(img.src);
});
}, [path]);
const MagnifierWrapper = imageData && (React__default.createElement(Magnifier, { ref: magnifierRef, imgUrl: imageData, name: name, zoom: 2, showMagnifier: isMagnifierOn, className: "imagePreview__img", withRotation: true, withMagnifier: true }));
return (React__default.createElement("div", Object.assign({ className: classnames('imagePreview', { 'modal-view': withModal, 'mobile-view': isMobile }) }, rest),
React__default.createElement("div", { className: "imagePreview__header" },
React__default.createElement("div", { className: "imagePreview__infoWrapper" },
React__default.createElement(Icon, { type: "bc-icon-Image", className: "imagePreview__icon imagePreview__imgIcon" }),
React__default.createElement("div", { className: classnames('imagePreview__info', {
'imagePreview__info-center': !showSize && !showDimensions
}) },
name && (React__default.createElement(Tooltip, { text: name, isVisible: isTruncated },
React__default.createElement("span", { className: "imagePreview__name ellipsis-text", ref: nameRef }, name))),
React__default.createElement("div", { className: "imagePreview__sizes" },
showSize && React__default.createElement("span", { className: "imagePreview__weight" }, fileSizeDisplay(meta.size)),
showSize && showDimensions && React__default.createElement("div", { className: "imagePreview__divider-small" }),
showDimensions && (React__default.createElement("span", { className: classnames('imagePreview__resolution', {
'imagePreview__resolution--divider': !showSize
}) },
React__default.createElement("span", null, meta.width),
React__default.createElement("span", { className: "imagePreview__resolution--separate" }, "x"),
React__default.createElement("span", null, meta.height)))))),
React__default.createElement("div", { className: "imagePreview__options" },
withMagnifier && (React__default.createElement("div", { className: "imagePreview__magnifier" },
React__default.createElement(Switcher
/*@ts-ignore*/
, {
/*@ts-ignore*/
defaultChecked: magnifierDefaultValue, value: isMagnifierOn, onChange: (e) => setIsMagnifierOn(e.currentTarget.checked), labelPosition: "left", label: "Magnifier", className: "imagePreview__switcher" }))),
showRotate && (React__default.createElement("div", { className: "imagePreview__rotate" },
React__default.createElement(Icon, { type: "bc-icon-rotate-left", className: "imagePreview__icon", onClick: () => {
var _a;
if (!((_a = magnifierRef.current) === null || _a === void 0 ? void 0 : _a.rotate))
return;
magnifierRef.current.rotate(-90);
} }),
React__default.createElement(Icon, { type: "bc-icon-rotate-right", className: "imagePreview__icon", onClick: () => {
var _a;
if (!((_a = magnifierRef.current) === null || _a === void 0 ? void 0 : _a.rotate))
return;
magnifierRef.current.rotate(90);
} }))),
showDownload && (React__default.createElement("div", { className: "imagePreview__download" },
React__default.createElement(Icon, { type: "bc-icon-download", className: "imagePreview__icon", onClick: () => downloadImg(path, name, customHeaders) }))),
withModal && (React__default.createElement("div", { className: "imagePreview__close" },
React__default.createElement("div", { className: "imagePreview__divider" }),
React__default.createElement(Icon, { type: "bc-icon-close", className: "imagePreview__icon", onClick: onClose }))))),
React__default.createElement("div", { className: "imagePreview__content" }, withModal ? (React__default.createElement(React__default.Fragment, null,
React__default.createElement("div", { className: "imagePreview__background", onClick: onClose }),
MagnifierWrapper)) : (MagnifierWrapper))));
};
const ImagePreviewHOC = (_a) => {
var { withModal } = _a, restProps = __rest(_a, ["withModal"]);
return withModal ? (
// @ts-ignore
React__default.createElement(Portal, { isOpen: true },
React__default.createElement(ImagePreview, Object.assign({}, restProps, { withModal: withModal })))) : (React__default.createElement(ImagePreview, Object.assign({}, restProps, { withModal: withModal })));
};
export { ImagePreviewHOC as default };