@fluentui/react
Version:
Reusable React components for building web experiences.
127 lines • 7.83 kB
JavaScript
define(["require", "exports", "tslib", "react", "../../Utilities", "./Image.types", "@fluentui/react-hooks"], function (require, exports, tslib_1, React, Utilities_1, Image_types_1, react_hooks_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImageBase = void 0;
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