@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
164 lines (163 loc) • 5.35 kB
JavaScript
"use client";
import FlexBasic_default from "../Flex/FlexBasic.mjs";
import SkeletonAvatar from "../Skeleton/SkeletonAvatar.mjs";
import { usePreviewGroupContext } from "./PreviewGroup.mjs";
import { FALLBACK_DARK, FALLBACK_LIGHT, styles, variants } from "./style.mjs";
import { openPreview } from "./viewer/registry.mjs";
import PreviewOutlet from "./viewer/PreviewOutlet.mjs";
import { memo, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
import { cx, useThemeMode } from "antd-style";
//#region src/Image/Image.tsx
const resolvePreview = (groupPreview, imagePreview) => {
if (imagePreview === false) return false;
if (imagePreview === void 0 && groupPreview === false) return false;
const groupOptions = typeof groupPreview === "object" ? groupPreview : void 0;
const imageOptions = typeof imagePreview === "object" ? imagePreview : void 0;
return {
...groupOptions,
...imageOptions
};
};
const Image = memo(({ ref, style, preview, isLoading, maxHeight = "100%", maxWidth = "100%", minHeight, minWidth, actions, className, alwaysShowActions, variant = "filled", objectFit = "cover", classNames, styles: customStyles, onClick, onError, onPointerDown, width, height, size, src, alt, loading = "lazy", ...rest }) => {
const { isDarkMode } = useThemeMode();
const [hasError, setHasError] = useState(false);
const lastSrcRef = useRef(src);
const imgRef = useRef(null);
const preOpenFocusRef = useRef(null);
const id = useId();
const group = usePreviewGroupContext();
if (lastSrcRef.current !== src) {
lastSrcRef.current = src;
if (hasError) setHasError(false);
}
const resolvedWidth = width ?? size;
const resolvedHeight = height ?? size;
const resolvedPreview = resolvePreview(group?.preview, preview);
const previewEnabled = resolvedPreview !== false;
const resolvedOptions = useMemo(() => previewEnabled ? {
autoZoomThreshold: 2,
defaultZoom: "auto",
maxScale: 8,
...resolvedPreview
} : void 0, [previewEnabled, resolvedPreview]);
const previewSrc = resolvedOptions?.src;
useEffect(() => {
if (!group) return;
return group.register({
getElement: () => imgRef.current,
id,
options: resolvedOptions,
previewSrc,
src: src ?? ""
});
}, [
group,
id,
src,
previewSrc,
resolvedOptions
]);
const handleError = useCallback((event) => {
setHasError(true);
onError?.(event);
}, [onError]);
const handlePointerDown = useCallback((event) => {
onPointerDown?.(event);
const active = document.activeElement;
preOpenFocusRef.current = active instanceof HTMLElement && active !== document.body && active !== document.documentElement ? active : null;
}, [onPointerDown]);
const handleClick = useCallback((event) => {
onClick?.(event);
if (!previewEnabled || !imgRef.current || !resolvedOptions) return;
const clickedEntry = {
element: imgRef.current,
options: resolvedOptions,
previewSrc,
src: imgRef.current.currentSrc || imgRef.current.src
};
const openerFocusElement = preOpenFocusRef.current;
if (!group) {
openPreview(clickedEntry, void 0, 0, openerFocusElement);
return;
}
const galleryEntries = [];
let clickedIndex = -1;
for (const groupEntry of group.getEntries()) {
const element = groupEntry.getElement();
if (!element || !groupEntry.options) continue;
if (element === imgRef.current) clickedIndex = galleryEntries.length;
galleryEntries.push({
element,
options: groupEntry.options,
previewSrc: groupEntry.previewSrc,
src: element.currentSrc || element.src
});
}
openPreview(clickedEntry, galleryEntries, clickedIndex >= 0 ? clickedIndex : 0, openerFocusElement);
}, [
onClick,
previewEnabled,
resolvedOptions,
previewSrc,
group
]);
const actionsClassName = alwaysShowActions ? styles.actionsVisible : styles.actionsHidden;
if (isLoading) return /* @__PURE__ */ jsx("div", {
onClick,
children: /* @__PURE__ */ jsx(SkeletonAvatar, {
active: true,
height: resolvedHeight,
style: {
maxHeight,
maxWidth,
minHeight,
minWidth
},
width: resolvedWidth
})
});
return /* @__PURE__ */ jsxs(FlexBasic_default, {
className: cx(variants({ variant }), className),
ref,
style,
children: [
actions && /* @__PURE__ */ jsx("div", {
className: cx(actionsClassName, alwaysShowActions ? "" : "actions-hidden"),
children: actions
}),
/* @__PURE__ */ jsx("div", {
className: cx(styles.wrapper, classNames?.wrapper),
style: customStyles?.wrapper,
children: /* @__PURE__ */ jsx("img", {
alt,
className: cx(styles.image, previewEnabled && styles.previewable, classNames?.image),
height: resolvedHeight,
loading,
ref: imgRef,
src: hasError ? isDarkMode ? FALLBACK_DARK : FALLBACK_LIGHT : src,
width: resolvedWidth,
style: {
height: resolvedHeight,
maxHeight,
maxWidth,
minHeight,
minWidth,
objectFit,
width: resolvedWidth,
...customStyles?.image
},
onClick: handleClick,
onError: handleError,
onPointerDown: handlePointerDown,
...rest
})
}),
previewEnabled && /* @__PURE__ */ jsx(PreviewOutlet, { elementRef: imgRef })
]
});
});
Image.displayName = "Image";
//#endregion
export { Image as default };
//# sourceMappingURL=Image.mjs.map