@onesy/ui-react
Version:
UI for React
274 lines (271 loc) • 9.22 kB
JavaScript
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(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import React from 'react';
import { is } from '@onesy/utils';
import { classNames, style as styleMethod, useOnesyTheme } from '@onesy/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: {
'&.onesy-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: 'onesy-Image'
});
const Image = /*#__PURE__*/React.forwardRef((props_, ref) => {
const theme = useOnesyTheme();
const props = React.useMemo(() => _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.onesyImage?.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,
otherProps = _objectWithoutProperties(props, _excluded);
const other = otherProps;
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) && ['onesy-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) && ['onesy-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) && ['onesy-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) && ['onesy-Image-root', noImage && 'onesy-Image-no-image', picture && !description && `onesy-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 = 'onesy-Image';
export default Image;