@i-novus/ui-core
Version:
Базовые UI компоненты
119 lines (118 loc) • 6.15 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { cloneElement, forwardRef, useLayoutEffect, useMemo, useRef, useState } from 'react';
import EllipsisComponent from 'react-ellipsis-component';
const isEllipsisExtended = (ellipsis) => {
return typeof ellipsis === 'object' && ellipsis?.rows !== undefined;
};
// eslint-disable-next-line sonarjs/cognitive-complexity
export const Ellipsis = forwardRef((props, ref) => {
const { tag: Tag = 'article', className, ellipsis, children, ...restProps } = props;
const rowsMap = useMemo(() => {
if (isEllipsisExtended(ellipsis) && ellipsis?.rows) {
return {
["Expanded" /* ExpandState.Expanded */]: Number.MAX_SAFE_INTEGER,
["Shrinked" /* ExpandState.Shrinked */]: ellipsis.rows,
["NotVisible" /* ExpandState.NotVisible */]: ellipsis.rows,
};
}
return {
["Expanded" /* ExpandState.Expanded */]: Number.MAX_SAFE_INTEGER,
["Shrinked" /* ExpandState.Shrinked */]: 1,
["NotVisible" /* ExpandState.NotVisible */]: 1,
};
}, [ellipsis]);
const [expandState, setExpandState] = useState("NotVisible" /* ExpandState.NotVisible */);
const htmlEllipsisRef = useRef();
const htmlNodeRowHeight = useMemo(() => {
const DEFAULT_LINE_HEIGHT = 24;
if (!htmlEllipsisRef.current) {
return DEFAULT_LINE_HEIGHT;
}
const computedLineHeight = getComputedStyle(htmlEllipsisRef.current).getPropertyValue('line-height');
return computedLineHeight ? parseInt(computedLineHeight, 10) : DEFAULT_LINE_HEIGHT;
}, []);
useLayoutEffect(() => {
if (typeof children !== 'string' && isEllipsisExtended(ellipsis) && htmlEllipsisRef.current) {
const nodeHeight = htmlEllipsisRef.current.clientHeight;
const computedNodeRowHeight = ellipsis?.rowHeight || htmlNodeRowHeight;
const ellipsisContentHeight = ellipsis.rows * computedNodeRowHeight;
if (nodeHeight > ellipsisContentHeight) {
setExpandState("Shrinked" /* ExpandState.Shrinked */);
}
else {
setExpandState("NotVisible" /* ExpandState.NotVisible */);
}
}
// eslint-disable-next-line
}, [htmlNodeRowHeight]);
if (!ellipsis) {
return (
// @ts-ignore
_jsx(Tag, { ref: ref, className: className, ...restProps, children: children }));
}
// eslint-disable-next-line react/no-unstable-nested-components
const ExpandLabel = ({ expandable, expandText = 'Развернуть', shrinkText = 'Свернуть' }) => {
if (!expandable) {
return null;
}
const onExpandLabelClick = () => setExpandState("Expanded" /* ExpandState.Expanded */);
const onShrinkLabelClick = () => setExpandState("Shrinked" /* ExpandState.Shrinked */);
if (expandState === "Shrinked" /* ExpandState.Shrinked */) {
return (_jsx("i", { className: "expand-container", children: _jsx("span", { className: "expand-label", onClick: onExpandLabelClick, children: expandText }) }));
}
if (expandState === "Expanded" /* ExpandState.Expanded */) {
return (_jsx("i", { className: "expand-container", children: _jsx("span", { className: "expand-label", onClick: onShrinkLabelClick, children: shrinkText }) }));
}
return null;
};
if (typeof children !== 'string') {
if (isEllipsisExtended(ellipsis)) {
const computedNodeRowHeight = ellipsis?.rowHeight || htmlNodeRowHeight;
const ellipsisContentHeight = ellipsis.rows * computedNodeRowHeight;
return (
// @ts-ignore
_jsxs(Tag, { ref: ref, className: className, ...restProps, children: [cloneElement(children, {
ref: htmlEllipsisRef,
style: {
letterSpacing: 'normal',
textRendering: 'auto',
width: '100%',
boxSizing: 'content-box',
wordBreak: 'normal',
whiteSpace: 'pre-wrap',
minHeight: '0',
maxHeight: 'none',
display: 'block',
visibility: 'hidden',
overflow: 'hidden',
position: 'absolute',
zIndex: '-1000',
top: '-1000px',
right: '-1000px',
pointerEvents: 'none',
},
}), cloneElement(children, { style: {
height: expandState === "Shrinked" /* ExpandState.Shrinked */ ? ellipsisContentHeight : 'auto',
overflow: 'hidden',
whiteSpace: 'pre-wrap',
} }), _jsx(ExpandLabel, { ...ellipsis })] }));
}
return (
// @ts-ignore
_jsx(Tag, { ref: ref, className: className, ...restProps, children: children }));
}
if (isEllipsisExtended(ellipsis)) {
const onEllipsisCompute = (textTruncated) => {
if (textTruncated) {
setExpandState("Shrinked" /* ExpandState.Shrinked */);
}
};
return (
// @ts-ignore
_jsxs(Tag, { ref: ref, className: className, ...restProps, children: [_jsx(EllipsisComponent, { text: children, maxLine: rowsMap[expandState], ellipsis: true, dangerouslyUseInnerHTML: true, reflowOnResize: true, onReflow: onEllipsisCompute }, expandState), _jsx(ExpandLabel, { ...ellipsis })] }));
}
return (
// @ts-ignore
_jsx(Tag, { ref: ref, className: className, ...restProps, children: _jsx(EllipsisComponent, { text: children, maxLine: rowsMap[expandState], ellipsis: ellipsis, dangerouslyUseInnerHTML: true, reflowOnResize: true }, expandState) }));
});
Ellipsis.displayName = 'Ellipsis';