130 lines
7.2 KiB
JavaScript
130 lines
7.2 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.ImageBase = void 0;
|
|
var tslib_1 = require("tslib");
|
|
var React = require("react");
|
|
var Utilities_1 = require("../../Utilities");
|
|
var Image_types_1 = require("./Image.types");
|
|
var react_hooks_1 = require("@fluentui/react-hooks");
|
|
var getClassNames = (0, Utilities_1.classNamesFunction)();
|
|
var SVG_REGEX = /\.svg$/i;
|
|
var KEY_PREFIX = 'fabricImage';
|
|
function useLoadState(props, imageElement) {
|
|
var onLoadingStateChange = props.onLoadingStateChange, onLoad = props.onLoad, onError = props.onError, src = props.src;
|
|
var _a = React.useState(Image_types_1.ImageLoadState.notLoaded), loadState = _a[0], setLoadState = _a[1];
|
|
(0, react_hooks_1.useIsomorphicLayoutEffect)(function () {
|
|
// If the src property changes, reset the load state
|
|
// (does nothing if the load state is already notLoaded)
|
|
setLoadState(Image_types_1.ImageLoadState.notLoaded);
|
|
}, [src]);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- intended to run every render
|
|
React.useEffect(function () {
|
|
if (loadState === Image_types_1.ImageLoadState.notLoaded) {
|
|
// testing if naturalWidth and naturalHeight are greater than zero is better than checking
|
|
// .complete, because .complete will also be set to true if the image breaks. However,
|
|
// for some browsers, SVG images do not have a naturalWidth or naturalHeight, so fall back
|
|
// to checking .complete for these images.
|
|
var isLoaded = imageElement.current
|
|
? (src && imageElement.current.naturalWidth > 0 && imageElement.current.naturalHeight > 0) ||
|
|
(imageElement.current.complete && SVG_REGEX.test(src))
|
|
: false;
|
|
if (isLoaded) {
|
|
setLoadState(Image_types_1.ImageLoadState.loaded);
|
|
}
|
|
}
|
|
});
|
|
React.useEffect(function () {
|
|
onLoadingStateChange === null || onLoadingStateChange === void 0 ? void 0 : onLoadingStateChange(loadState);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- should only run when loadState changes
|
|
}, [loadState]);
|
|
var onImageLoaded = React.useCallback(function (ev) {
|
|
onLoad === null || onLoad === void 0 ? void 0 : onLoad(ev);
|
|
if (src) {
|
|
setLoadState(Image_types_1.ImageLoadState.loaded);
|
|
}
|
|
}, [src, onLoad]);
|
|
var onImageError = React.useCallback(function (ev) {
|
|
onError === null || onError === void 0 ? void 0 : onError(ev);
|
|
setLoadState(Image_types_1.ImageLoadState.error);
|
|
}, [onError]);
|
|
return [loadState, onImageLoaded, onImageError];
|
|
}
|
|
exports.ImageBase = React.forwardRef(function (props, forwardedRef) {
|
|
var frameElement = React.useRef(undefined);
|
|
var imageElement = React.useRef(undefined);
|
|
var _a = useLoadState(props, imageElement), loadState = _a[0], onImageLoaded = _a[1], onImageError = _a[2];
|
|
var imageProps = (0, Utilities_1.getNativeProps)(props, Utilities_1.imgProperties, [
|
|
'width',
|
|
'height',
|
|
]);
|
|
var src = props.src, alt = props.alt, width = props.width, height = props.height, _b = props.shouldFadeIn, shouldFadeIn = _b === void 0 ? true : _b, shouldStartVisible = props.shouldStartVisible, className = props.className, imageFit = props.imageFit, role = props.role, maximizeFrame = props.maximizeFrame, styles = props.styles, theme = props.theme, loading = props.loading;
|
|
var coverStyle = useCoverStyle(props, loadState, imageElement, frameElement);
|
|
var classNames = getClassNames(styles, {
|
|
theme: theme,
|
|
className: className,
|
|
width: width,
|
|
height: height,
|
|
maximizeFrame: maximizeFrame,
|
|
shouldFadeIn: shouldFadeIn,
|
|
shouldStartVisible: shouldStartVisible,
|
|
isLoaded: loadState === Image_types_1.ImageLoadState.loaded || (loadState === Image_types_1.ImageLoadState.notLoaded && props.shouldStartVisible),
|
|
isLandscape: coverStyle === Image_types_1.ImageCoverStyle.landscape,
|
|
isCenter: imageFit === Image_types_1.ImageFit.center,
|
|
isCenterContain: imageFit === Image_types_1.ImageFit.centerContain,
|
|
isCenterCover: imageFit === Image_types_1.ImageFit.centerCover,
|
|
isContain: imageFit === Image_types_1.ImageFit.contain,
|
|
isCover: imageFit === Image_types_1.ImageFit.cover,
|
|
isNone: imageFit === Image_types_1.ImageFit.none,
|
|
isError: loadState === Image_types_1.ImageLoadState.error,
|
|
isNotImageFit: imageFit === undefined,
|
|
});
|
|
// If image dimensions aren't specified, the natural size of the image is used.
|
|
return (React.createElement("div", { className: classNames.root, style: { width: width, height: height }, ref: frameElement },
|
|
React.createElement("img", tslib_1.__assign({}, imageProps, { onLoad: onImageLoaded, onError: onImageError, key: KEY_PREFIX + props.src || '', className: classNames.image, ref: (0, react_hooks_1.useMergedRefs)(imageElement, forwardedRef), src: src, alt: alt, role: role, loading: loading }))));
|
|
});
|
|
exports.ImageBase.displayName = 'ImageBase';
|
|
function useCoverStyle(props, loadState, imageElement, frameElement) {
|
|
var previousLoadState = React.useRef(loadState);
|
|
var coverStyle = React.useRef(undefined);
|
|
if (coverStyle === undefined ||
|
|
(previousLoadState.current === Image_types_1.ImageLoadState.notLoaded && loadState === Image_types_1.ImageLoadState.loaded)) {
|
|
coverStyle.current = computeCoverStyle(props, loadState, imageElement, frameElement);
|
|
}
|
|
previousLoadState.current = loadState;
|
|
return coverStyle.current;
|
|
}
|
|
function computeCoverStyle(props, loadState, imageElement, frameElement) {
|
|
var imageFit = props.imageFit, width = props.width, height = props.height;
|
|
// Do not compute cover style if it was already specified in props
|
|
if (props.coverStyle !== undefined) {
|
|
return props.coverStyle;
|
|
}
|
|
else if (loadState === Image_types_1.ImageLoadState.loaded &&
|
|
(imageFit === Image_types_1.ImageFit.cover ||
|
|
imageFit === Image_types_1.ImageFit.contain ||
|
|
imageFit === Image_types_1.ImageFit.centerContain ||
|
|
imageFit === Image_types_1.ImageFit.centerCover) &&
|
|
imageElement.current &&
|
|
frameElement.current) {
|
|
// Determine the desired ratio using the width and height props.
|
|
// If those props aren't available, measure measure the frame.
|
|
var desiredRatio = void 0;
|
|
if (typeof width === 'number' &&
|
|
typeof height === 'number' &&
|
|
imageFit !== Image_types_1.ImageFit.centerContain &&
|
|
imageFit !== Image_types_1.ImageFit.centerCover) {
|
|
desiredRatio = width / height;
|
|
}
|
|
else {
|
|
desiredRatio = frameElement.current.clientWidth / frameElement.current.clientHeight;
|
|
}
|
|
// Examine the source image to determine its original ratio.
|
|
var naturalRatio = imageElement.current.naturalWidth / imageElement.current.naturalHeight;
|
|
// Should we crop from the top or the sides?
|
|
if (naturalRatio > desiredRatio) {
|
|
return Image_types_1.ImageCoverStyle.landscape;
|
|
}
|
|
}
|
|
return Image_types_1.ImageCoverStyle.portrait;
|
|
}
|
|
//# sourceMappingURL=Image.base.js.map
|