first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
@@ -0,0 +1,7 @@
import * as React from 'react';
import { ImageLoadState } from './Image.types';
import type { IImageProps } from './Image.types';
export interface IImageState {
loadState?: ImageLoadState;
}
export declare const ImageBase: React.FunctionComponent<IImageProps>;
+127
View File
@@ -0,0 +1,127 @@
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
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
import * as React from 'react';
import type { IImageProps } from './Image.types';
export declare const Image: React.FunctionComponent<IImageProps>;
+10
View File
@@ -0,0 +1,10 @@
define(["require", "exports", "../../Utilities", "./Image.base", "./Image.styles"], function (require, exports, Utilities_1, Image_base_1, Image_styles_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Image = void 0;
exports.Image = (0, Utilities_1.styled)(Image_base_1.ImageBase, Image_styles_1.getStyles, undefined, {
scope: 'Image',
}, true);
exports.Image.displayName = 'Image';
});
//# sourceMappingURL=Image.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"Image.js","sourceRoot":"../src/","sources":["components/Image/Image.tsx"],"names":[],"mappings":";;;;IAMa,QAAA,KAAK,GAAyC,IAAA,kBAAM,EAC/D,sBAAS,EACT,wBAAS,EACT,SAAS,EACT;QACE,KAAK,EAAE,OAAO;KACf,EACD,IAAI,CACL,CAAC;IACF,aAAK,CAAC,WAAW,GAAG,OAAO,CAAC","sourcesContent":["import * as React from 'react';\nimport { styled } from '../../Utilities';\nimport { ImageBase } from './Image.base';\nimport { getStyles } from './Image.styles';\nimport type { IImageProps, IImageStyleProps, IImageStyles } from './Image.types';\n\nexport const Image: React.FunctionComponent<IImageProps> = styled<IImageProps, IImageStyleProps, IImageStyles>(\n ImageBase,\n getStyles,\n undefined,\n {\n scope: 'Image',\n },\n true,\n);\nImage.displayName = 'Image';\n"]}
@@ -0,0 +1,2 @@
import type { IImageStyleProps, IImageStyles } from './Image.types';
export declare const getStyles: (props: IImageStyleProps) => IImageStyles;
+143
View File
@@ -0,0 +1,143 @@
define(["require", "exports", "../../Styling", "../../Utilities"], function (require, exports, Styling_1, Utilities_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStyles = void 0;
var GlobalClassNames = {
root: 'ms-Image',
rootMaximizeFrame: 'ms-Image--maximizeFrame',
image: 'ms-Image-image',
imageCenter: 'ms-Image-image--center',
imageContain: 'ms-Image-image--contain',
imageCover: 'ms-Image-image--cover',
imageCenterContain: 'ms-Image-image--centerContain',
imageCenterCover: 'ms-Image-image--centerCover',
imageNone: 'ms-Image-image--none',
imageLandscape: 'ms-Image-image--landscape',
imagePortrait: 'ms-Image-image--portrait',
};
var getStyles = function (props) {
var className = props.className, width = props.width, height = props.height, maximizeFrame = props.maximizeFrame, isLoaded = props.isLoaded, shouldFadeIn = props.shouldFadeIn, shouldStartVisible = props.shouldStartVisible, isLandscape = props.isLandscape, isCenter = props.isCenter, isContain = props.isContain, isCover = props.isCover, isCenterContain = props.isCenterContain, isCenterCover = props.isCenterCover, isNone = props.isNone, isError = props.isError, isNotImageFit = props.isNotImageFit, theme = props.theme;
var classNames = (0, Styling_1.getGlobalClassNames)(GlobalClassNames, theme);
var ImageFitStyles = {
position: 'absolute',
left: '50% /* @noflip */',
top: '50%',
transform: 'translate(-50%,-50%)', // @todo test RTL renders transform: translate(50%,-50%);
};
// Cut the mustard using msMaxTouchPoints to detect IE11 which does not support CSS object-fit
var window = (0, Utilities_1.getWindow)();
var supportsObjectFit = window !== undefined &&
// eslint-disable-next-line @fluentui/max-len
// cast needed as vendor prefixed `msMaxTouchPoints` api is no longer part of TS lib declaration - introduced with TS 4.4
window.navigator.msMaxTouchPoints === undefined;
var fallbackObjectFitStyles = (isContain && isLandscape) || (isCover && !isLandscape)
? { width: '100%', height: 'auto' }
: { width: 'auto', height: '100%' };
return {
root: [
classNames.root,
theme.fonts.medium,
{
overflow: 'hidden',
},
maximizeFrame && [
classNames.rootMaximizeFrame,
{
height: '100%',
width: '100%',
},
],
isLoaded && shouldFadeIn && !shouldStartVisible && Styling_1.AnimationClassNames.fadeIn400,
(isCenter || isContain || isCover || isCenterContain || isCenterCover) && {
position: 'relative',
},
className,
],
image: [
classNames.image,
{
display: 'block',
opacity: 0,
},
isLoaded && [
'is-loaded',
{
opacity: 1,
},
],
isCenter && [classNames.imageCenter, ImageFitStyles],
isContain && [
classNames.imageContain,
supportsObjectFit && {
width: '100%',
height: '100%',
objectFit: 'contain',
},
!supportsObjectFit && fallbackObjectFitStyles,
!supportsObjectFit && ImageFitStyles,
],
isCover && [
classNames.imageCover,
supportsObjectFit && {
width: '100%',
height: '100%',
objectFit: 'cover',
},
!supportsObjectFit && fallbackObjectFitStyles,
!supportsObjectFit && ImageFitStyles,
],
isCenterContain && [
classNames.imageCenterContain,
isLandscape && {
maxWidth: '100%',
},
!isLandscape && {
maxHeight: '100%',
},
ImageFitStyles,
],
isCenterCover && [
classNames.imageCenterCover,
isLandscape && {
maxHeight: '100%',
},
!isLandscape && {
maxWidth: '100%',
},
ImageFitStyles,
],
isNone && [
classNames.imageNone,
{
width: 'auto',
height: 'auto',
},
],
isNotImageFit && [
!!width &&
!height && {
height: 'auto',
width: '100%',
},
!width &&
!!height && {
height: '100%',
width: 'auto',
},
!!width &&
!!height && {
height: '100%',
width: '100%',
},
],
isLandscape && classNames.imageLandscape,
!isLandscape && classNames.imagePortrait,
!isLoaded && 'is-notLoaded',
shouldFadeIn && 'is-fadeIn',
isError && 'is-error',
],
};
};
exports.getStyles = getStyles;
});
//# sourceMappingURL=Image.styles.js.map
File diff suppressed because one or more lines are too long
+214
View File
@@ -0,0 +1,214 @@
import * as React from 'react';
import type { IStyle, ITheme } from '../../Styling';
import type { IStyleFunctionOrObject } from '../../Utilities';
/**
* {@docCategory Image}
*/
export interface IImage {
}
/**
* {@docCategory Image}
*/
export interface IImageProps extends React.ImgHTMLAttributes<HTMLImageElement>, React.RefAttributes<HTMLImageElement> {
/**
* Call to provide customized styling that will layer on top of the variant rules
*/
styles?: IStyleFunctionOrObject<IImageStyleProps, IImageStyles>;
/**
* Theme provided by HOC.
*/
theme?: ITheme;
/**
* Additional css class to apply to the Component
* @defaultvalue undefined
*/
className?: string;
/**
* If true, fades the image in when loaded.
* @defaultvalue true
*/
shouldFadeIn?: boolean;
/**
* If true, the image starts as visible and is hidden on error. Otherwise, the image is hidden until
* it is successfully loaded. This disables shouldFadeIn.
* @defaultvalue false;
*/
shouldStartVisible?: boolean;
/**
* Used to determine how the image is scaled and cropped to fit the frame.
*
* @defaultvalue If both dimensions are provided, then the image is fit using `ImageFit.scale`.
* Otherwise, the image won't be scaled or cropped.
*/
imageFit?: ImageFit;
/**
* @deprecated Not used. Use `onLoadingStateChange` and re-render the Image with a different src.
*/
errorSrc?: string;
/**
* If true, the image frame will expand to fill its parent container.
*/
maximizeFrame?: boolean;
/**
* Optional callback method for when the image load state has changed.
* The 'loadState' parameter indicates the current state of the Image.
*/
onLoadingStateChange?: (loadState: ImageLoadState) => void;
/**
* Specifies the cover style to be used for this image. If not
* specified, this will be dynamically calculated based on the
* aspect ratio for the image.
*/
coverStyle?: ImageCoverStyle;
/**
* Allows for browser-level image lazy-loading.
*/
loading?: 'lazy' | 'eager';
}
/**
* The possible methods that can be used to fit the image.
* {@docCategory Image}
*/
export declare enum ImageFit {
/**
* The image is not scaled. The image is centered and cropped within the content box.
*/
center = 0,
/**
* The image is scaled to maintain its aspect ratio while being fully contained within the frame. The image will
* be centered horizontally and vertically within the frame. The space in the top and bottom or in the sides of
* the frame will be empty depending on the difference in aspect ratio between the image and the frame.
*/
contain = 1,
/**
* The image is scaled to maintain its aspect ratio while filling the frame. Portions of the image will be cropped
* from the top and bottom, or the sides, depending on the difference in aspect ratio between the image and the frame.
*/
cover = 2,
/**
* Neither the image nor the frame are scaled. If their sizes do not match, the image will either be cropped or the
* frame will have empty space.
*/
none = 3,
/**
* The image will be centered horizontally and vertically within the frame and maintains its aspect ratio. It will
* behave as ImageFit.center if the image's natural height or width is less than the Image frame's height or width,
* but if both natural height and width are larger than the frame it will behave as ImageFit.cover.
*/
centerCover = 4,
/**
* The image will be centered horizontally and vertically within the frame and maintains its aspect ratio. It will
* behave as ImageFit.center if the image's natural height and width is less than the Image frame's height and width,
* but if either natural height or width are larger than the frame it will behave as ImageFit.contain.
*/
centerContain = 5
}
/**
* The cover style to be used on the image
* {@docCategory Image}
*/
export declare enum ImageCoverStyle {
/**
* The image will be shown at 100% height of container and the width will be scaled accordingly
*/
landscape = 0,
/**
* The image will be shown at 100% width of container and the height will be scaled accordingly
*/
portrait = 1
}
/**
* {@docCategory Image}
*/
export declare enum ImageLoadState {
/**
* The image has not yet been loaded, and there is no error yet.
*/
notLoaded = 0,
/**
* The image has been loaded successfully.
*/
loaded = 1,
/**
* An error has been encountered while loading the image.
*/
error = 2,
/**
* @deprecated Not used. Use `onLoadingStateChange` and re-render the Image with a different src.
*/
errorLoaded = 3
}
/**
* {@docCategory Image}
*/
export interface IImageStyleProps {
/**
* Accept theme prop.
*/
theme: ITheme;
/**
* Accept custom classNames
*/
className?: string;
/**
* If true, the image frame will expand to fill its parent container.
*/
maximizeFrame?: boolean;
/**
* If true, the image is loaded
*/
isLoaded?: boolean;
/**
* If true, fades the image in when loaded.
* @defaultvalue true
*/
shouldFadeIn?: boolean;
/**
* If true, the image starts as visible and is hidden on error. Otherwise, the image is hidden until
* it is successfully loaded. This disables shouldFadeIn.
* @defaultvalue false;
*/
shouldStartVisible?: boolean;
/**
* If true the image is coverStyle landscape instead of portrait
*/
isLandscape?: boolean;
/**
* ImageFit booleans for center, cover, contain, centerContain, centerCover, none
*/
isCenter?: boolean;
isContain?: boolean;
isCover?: boolean;
isCenterContain?: boolean;
isCenterCover?: boolean;
isNone?: boolean;
/**
* if true image load is in error
*/
isError?: boolean;
/**
* if true, imageFit is undefined
*/
isNotImageFit?: boolean;
/**
* Image width value
*/
width?: number | string;
/**
* Image height value
*/
height?: number | string;
}
/**
* {@docCategory Image}
*/
export interface IImageStyles {
/**
* Style set for the root div element.
*/
root: IStyle;
/**
* Style set for the img element.
*/
image: IStyle;
}
+82
View File
@@ -0,0 +1,82 @@
define(["require", "exports"], function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ImageLoadState = exports.ImageCoverStyle = exports.ImageFit = void 0;
/**
* The possible methods that can be used to fit the image.
* {@docCategory Image}
*/
var ImageFit;
(function (ImageFit) {
/**
* The image is not scaled. The image is centered and cropped within the content box.
*/
ImageFit[ImageFit["center"] = 0] = "center";
/**
* The image is scaled to maintain its aspect ratio while being fully contained within the frame. The image will
* be centered horizontally and vertically within the frame. The space in the top and bottom or in the sides of
* the frame will be empty depending on the difference in aspect ratio between the image and the frame.
*/
ImageFit[ImageFit["contain"] = 1] = "contain";
/**
* The image is scaled to maintain its aspect ratio while filling the frame. Portions of the image will be cropped
* from the top and bottom, or the sides, depending on the difference in aspect ratio between the image and the frame.
*/
ImageFit[ImageFit["cover"] = 2] = "cover";
/**
* Neither the image nor the frame are scaled. If their sizes do not match, the image will either be cropped or the
* frame will have empty space.
*/
ImageFit[ImageFit["none"] = 3] = "none";
/**
* The image will be centered horizontally and vertically within the frame and maintains its aspect ratio. It will
* behave as ImageFit.center if the image's natural height or width is less than the Image frame's height or width,
* but if both natural height and width are larger than the frame it will behave as ImageFit.cover.
*/
ImageFit[ImageFit["centerCover"] = 4] = "centerCover";
/**
* The image will be centered horizontally and vertically within the frame and maintains its aspect ratio. It will
* behave as ImageFit.center if the image's natural height and width is less than the Image frame's height and width,
* but if either natural height or width are larger than the frame it will behave as ImageFit.contain.
*/
ImageFit[ImageFit["centerContain"] = 5] = "centerContain";
})(ImageFit || (exports.ImageFit = ImageFit = {}));
/**
* The cover style to be used on the image
* {@docCategory Image}
*/
var ImageCoverStyle;
(function (ImageCoverStyle) {
/**
* The image will be shown at 100% height of container and the width will be scaled accordingly
*/
ImageCoverStyle[ImageCoverStyle["landscape"] = 0] = "landscape";
/**
* The image will be shown at 100% width of container and the height will be scaled accordingly
*/
ImageCoverStyle[ImageCoverStyle["portrait"] = 1] = "portrait";
})(ImageCoverStyle || (exports.ImageCoverStyle = ImageCoverStyle = {}));
/**
* {@docCategory Image}
*/
var ImageLoadState;
(function (ImageLoadState) {
/**
* The image has not yet been loaded, and there is no error yet.
*/
ImageLoadState[ImageLoadState["notLoaded"] = 0] = "notLoaded";
/**
* The image has been loaded successfully.
*/
ImageLoadState[ImageLoadState["loaded"] = 1] = "loaded";
/**
* An error has been encountered while loading the image.
*/
ImageLoadState[ImageLoadState["error"] = 2] = "error";
/**
* @deprecated Not used. Use `onLoadingStateChange` and re-render the Image with a different src.
*/
ImageLoadState[ImageLoadState["errorLoaded"] = 3] = "errorLoaded";
})(ImageLoadState || (exports.ImageLoadState = ImageLoadState = {}));
});
//# sourceMappingURL=Image.types.js.map
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
export * from './Image';
export * from './Image.base';
export * from './Image.types';
+8
View File
@@ -0,0 +1,8 @@
define(["require", "exports", "tslib", "./Image", "./Image.base", "./Image.types"], function (require, exports, tslib_1, Image_1, Image_base_1, Image_types_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
tslib_1.__exportStar(Image_1, exports);
tslib_1.__exportStar(Image_base_1, exports);
tslib_1.__exportStar(Image_types_1, exports);
});
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"../src/","sources":["components/Image/index.ts"],"names":[],"mappings":";;;IAAA,uCAAwB;IACxB,4CAA6B;IAC7B,6CAA8B","sourcesContent":["export * from './Image';\nexport * from './Image.base';\nexport * from './Image.types';\n"]}