UNPKG

@amaui/ui-react

Version:
273 lines (270 loc) 9.34 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; const _excluded = ["tonal", "color", "src", "url", "urlSmall", "sources", "alt", "description", "alignDescription", "width", "height", "align", "responsive", "lazyLoad", "fullWidth", "maxWidth", "loading", "RootProps", "NoImageProps", "DescriptionProps", "UseVisibleProps", "className", "style", "children"]; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } import React from 'react'; import { is } from '@amaui/utils'; import { classNames, style as styleMethod, useAmauiTheme } from '@amaui/style-react'; import TypeElement from '../Type'; import SurfaceElement from '../Surface'; import LineElement from '../Line'; import useVisible from '../useVisible/useVisible'; import { staticClassName } from '../utils'; const useStyle = styleMethod(theme => ({ root: { position: 'relative', display: 'inline-block', lineHeight: '0' }, root_figure: { '& img': { height: 'auto', width: '100%' } }, root_picture: { '& img': { height: 'auto', width: '100%' } }, picture: { position: 'relative', display: 'inline-block' }, figcaption: { '&.amaui-Type-root': { padding: `${theme.methods.space.value(1.5, 'px')} ${theme.methods.space.value(2, 'px')}` } }, align_description_start: { textAlign: 'start' }, align_description_left: { textAlign: 'left' }, align_description_center: { textAlign: 'center' }, align_description_right: { textAlign: 'right' }, align_description_end: { textAlign: 'end' }, align_start: { marginInlineEnd: 'auto' }, align_left: { marginLeft: 'auto' }, align_center: { marginInline: 'auto' }, align_right: { marginRight: 'auto' }, align_end: { marginInlineStart: 'auto' }, align_unset: { marginInline: 'unset' }, responsive: { height: 'auto', maxWidth: '100%' }, // maxWidth maxWidth_xxs: { maxWidth: '320px' }, maxWidth_xs: { maxWidth: '400px' }, maxWidth_sm: { maxWidth: '600px' }, maxWidth_rg: { maxWidth: '960px' }, maxWidth_lg: { maxWidth: '1240px' }, maxWidth_xl: { maxWidth: '1920px' }, maxWidth_unset: { maxWidth: 'unset' }, fullWidth: { display: 'block', width: '100%' }, noImage: { width: '100%', maxWidth: '540px', aspectRatio: '4 / 3', backgroundColor: theme.palette.color.neutral[100], backgroundImage: `linear-gradient(${theme.palette.light ? '130deg' : '330deg'}, ${theme.methods.palette.color.colorToRgb(theme.palette.color.primary.main, 0.14)} 0%, ${theme.methods.palette.color.colorToRgb(theme.palette.color.secondary.main, 0.14)} 40%, ${theme.methods.palette.color.colorToRgb(theme.palette.color.quaternary.main, 0.14)} 100%)`, cursor: 'default', userSelect: 'none' } }), { name: 'amaui-Image' }); const Image = /*#__PURE__*/React.forwardRef((props_, ref) => { const theme = useAmauiTheme(); const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.amauiImage?.props?.default), props_), [props_]); const Line = React.useMemo(() => theme?.elements?.Line || LineElement, [theme]); const Type = React.useMemo(() => theme?.elements?.Type || TypeElement, [theme]); const Surface = React.useMemo(() => theme?.elements?.Surface || SurfaceElement, [theme]); const { tonal = true, color = 'primary', src, url, urlSmall, sources, alt, description, alignDescription = 'start', width, height, align, responsive = true, lazyLoad = true, fullWidth, maxWidth, loading, RootProps, NoImageProps, DescriptionProps, UseVisibleProps, className, style, children: children_ } = props, other = _objectWithoutProperties(props, _excluded); const { classes } = useStyle(); let Component = 'img'; const [root, setRoot] = React.useState(); const [loaded, setLoaded] = React.useState(false); const [source, setSource] = React.useState(''); const visiblity = lazyLoad ? useVisible(_objectSpread({ element: root }, UseVisibleProps)) : { visible: true }; const refs = { root: React.useRef(undefined), loaded: React.useRef(loaded) }; refs.loaded.current = loaded; const imageLoad = React.useCallback(value => new Promise((resolve, reject) => { const image = window.document.createElement('img'); let imageLoaded = false; const check = () => { if (image.complete && image.naturalWidth !== 0) imageLoaded = true; if (imageLoaded) return resolve(true); setTimeout(check, 40); }; const onLoad = event => { check(); }; const onError = () => { resolve(false); }; image.onload = onLoad; image.onerror = onError; image.src = value; if (image.complete) return resolve(true); }), []); const init = React.useCallback(async () => { const URL = src || url || urlSmall; const isLoaded = await imageLoad(URL); setSource(isLoaded ? URL : ''); setLoaded(true); }, [src, url, urlSmall, loaded]); React.useEffect(() => { if (visiblity?.visible && !refs.loaded.current) { init(); } }, [visiblity?.visible]); React.useEffect(() => { if (loaded) init(); }, [src]); const noImage = loaded && !source; const children = React.Children.toArray(children_); // picture // with sources let isPicture = false; const picture = !!children.length || !!sources?.length; if (picture && !description) { Component = 'picture'; isPicture = true; } // description if (description) Component = 'figure'; const rootIsImage = !picture && !description; // surface if (picture || description) { other.tonal = tonal; other.color = color; other.Component = Component; Component = Surface; } else if (rootIsImage && !noImage) { other.src = source; other.atl = alt; other.width = width; other.height = height; other.loading = loading; other.style = style; } const Wrapper = picture && description ? 'picture' : React.Fragment; const WrapperProps = picture && description ? { className: classNames([staticClassName('Image', theme) && ['amaui-Image-picture'], classes.picture]) } : {}; if (!rootIsImage && !noImage) { const imgElement = /*#__PURE__*/React.createElement("img", { src: src, alt: alt || '', width: width, height: height, loading: loading, className: classNames([staticClassName('Image', theme) && ['amaui-Image-img'], className, classes.img]), style: style }); other.children = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Wrapper, WrapperProps, sources?.length && sources.map((item, index) => /*#__PURE__*/React.createElement("source", _extends({ key: index }, item))), children, imgElement), description && /*#__PURE__*/React.createElement(Type, _extends({ Component: "figcaption", version: "b3" }, DescriptionProps, { className: classNames([staticClassName('Image', theme) && ['amaui-Image-figcaption'], DescriptionProps?.className, className, classes.figcaption, classes[`align_description_${alignDescription}`]]) }), description)); } if (noImage) { Component = Line; other.fullWidth = true; other.children = children; other.style = style; delete other.Component; } return /*#__PURE__*/React.createElement(Component, _extends({ ref: item => { if (ref) { if (is('function', ref)) ref(item);else ref.current = item; } setRoot(item); refs.root.current = item; } }, RootProps, { className: classNames([staticClassName('Image', theme) && ['amaui-Image-root', noImage && 'amaui-Image-no-image', picture && !description && `amaui-Image-picture`], RootProps?.className, className, classes.root, classes[`align_${align}`], noImage && classes.noImage, responsive && classes.responsive, maxWidth && classes[`maxWidth_${maxWidth}`], fullWidth && classes.fullWidth, rootIsImage && classes.root_img, picture && !description && classes.root_picture, description && classes.root_figure]) }, other)); }); Image.displayName = 'amaui-Image'; export default Image;