amis-rpc-design/node_modules/antd/es/typography/Base/index.js

422 lines
16 KiB
JavaScript
Raw Normal View History

2023-10-07 19:42:30 +08:00
"use client";
var __rest = this && this.__rest || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
}
return t;
};
import CheckOutlined from "@ant-design/icons/es/icons/CheckOutlined";
import CopyOutlined from "@ant-design/icons/es/icons/CopyOutlined";
import EditOutlined from "@ant-design/icons/es/icons/EditOutlined";
import classNames from 'classnames';
import copy from 'copy-to-clipboard';
import ResizeObserver from 'rc-resize-observer';
import toArray from "rc-util/es/Children/toArray";
import useIsomorphicLayoutEffect from "rc-util/es/hooks/useLayoutEffect";
import useMergedState from "rc-util/es/hooks/useMergedState";
import omit from "rc-util/es/omit";
import { composeRef } from "rc-util/es/ref";
import * as React from 'react';
import { isStyleSupport } from '../../_util/styleChecker';
import TransButton from '../../_util/transButton';
import { ConfigContext } from '../../config-provider';
import useLocale from '../../locale/useLocale';
import Tooltip from '../../tooltip';
import Editable from '../Editable';
import Typography from '../Typography';
import useMergedConfig from '../hooks/useMergedConfig';
import useUpdatedEffect from '../hooks/useUpdatedEffect';
import Ellipsis from './Ellipsis';
import EllipsisTooltip from './EllipsisTooltip';
function wrapperDecorations(_ref, content) {
let {
mark,
code,
underline,
delete: del,
strong,
keyboard,
italic
} = _ref;
let currentContent = content;
function wrap(tag, needed) {
if (!needed) {
return;
}
currentContent = /*#__PURE__*/React.createElement(tag, {}, currentContent);
}
wrap('strong', strong);
wrap('u', underline);
wrap('del', del);
wrap('code', code);
wrap('mark', mark);
wrap('kbd', keyboard);
wrap('i', italic);
return currentContent;
}
function getNode(dom, defaultNode, needDom) {
if (dom === true || dom === undefined) {
return defaultNode;
}
return dom || needDom && defaultNode;
}
function toList(val) {
if (val === false) {
return [false, false];
}
return Array.isArray(val) ? val : [val];
}
const ELLIPSIS_STR = '...';
const Base = /*#__PURE__*/React.forwardRef((props, ref) => {
var _a, _b, _c;
const {
prefixCls: customizePrefixCls,
className,
style,
type,
disabled,
children,
ellipsis,
editable,
copyable,
component,
title
} = props,
restProps = __rest(props, ["prefixCls", "className", "style", "type", "disabled", "children", "ellipsis", "editable", "copyable", "component", "title"]);
const {
getPrefixCls,
direction
} = React.useContext(ConfigContext);
const [textLocale] = useLocale('Text');
const typographyRef = React.useRef(null);
const editIconRef = React.useRef(null);
// ============================ MISC ============================
const prefixCls = getPrefixCls('typography', customizePrefixCls);
const textProps = omit(restProps, ['mark', 'code', 'delete', 'underline', 'strong', 'keyboard', 'italic']);
// ========================== Editable ==========================
const [enableEdit, editConfig] = useMergedConfig(editable);
const [editing, setEditing] = useMergedState(false, {
value: editConfig.editing
});
const {
triggerType = ['icon']
} = editConfig;
const triggerEdit = edit => {
var _a;
if (edit) {
(_a = editConfig.onStart) === null || _a === void 0 ? void 0 : _a.call(editConfig);
}
setEditing(edit);
};
// Focus edit icon when back
useUpdatedEffect(() => {
var _a;
if (!editing) {
(_a = editIconRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}
}, [editing]);
const onEditClick = e => {
e === null || e === void 0 ? void 0 : e.preventDefault();
triggerEdit(true);
};
const onEditChange = value => {
var _a;
(_a = editConfig.onChange) === null || _a === void 0 ? void 0 : _a.call(editConfig, value);
triggerEdit(false);
};
const onEditCancel = () => {
var _a;
(_a = editConfig.onCancel) === null || _a === void 0 ? void 0 : _a.call(editConfig);
triggerEdit(false);
};
// ========================== Copyable ==========================
const [enableCopy, copyConfig] = useMergedConfig(copyable);
const [copied, setCopied] = React.useState(false);
const copyIdRef = React.useRef(null);
const copyOptions = {};
if (copyConfig.format) {
copyOptions.format = copyConfig.format;
}
const cleanCopyId = () => {
if (copyIdRef.current) {
clearTimeout(copyIdRef.current);
}
};
const onCopyClick = e => {
var _a;
e === null || e === void 0 ? void 0 : e.preventDefault();
e === null || e === void 0 ? void 0 : e.stopPropagation();
copy(copyConfig.text || String(children) || '', copyOptions);
setCopied(true);
// Trigger tips update
cleanCopyId();
copyIdRef.current = setTimeout(() => {
setCopied(false);
}, 3000);
(_a = copyConfig.onCopy) === null || _a === void 0 ? void 0 : _a.call(copyConfig, e);
};
React.useEffect(() => cleanCopyId, []);
// ========================== Ellipsis ==========================
const [isLineClampSupport, setIsLineClampSupport] = React.useState(false);
const [isTextOverflowSupport, setIsTextOverflowSupport] = React.useState(false);
const [expanded, setExpanded] = React.useState(false);
const [isJsEllipsis, setIsJsEllipsis] = React.useState(false);
const [isNativeEllipsis, setIsNativeEllipsis] = React.useState(false);
const [isNativeVisible, setIsNativeVisible] = React.useState(true);
const [enableEllipsis, ellipsisConfig] = useMergedConfig(ellipsis, {
expandable: false
});
const mergedEnableEllipsis = enableEllipsis && !expanded;
// Shared prop to reduce bundle size
const {
rows = 1
} = ellipsisConfig;
const needMeasureEllipsis = React.useMemo(() =>
// Disable ellipsis
!mergedEnableEllipsis ||
// Provide suffix
ellipsisConfig.suffix !== undefined || ellipsisConfig.onEllipsis ||
// Can't use css ellipsis since we need to provide the place for button
ellipsisConfig.expandable || enableEdit || enableCopy, [mergedEnableEllipsis, ellipsisConfig, enableEdit, enableCopy]);
useIsomorphicLayoutEffect(() => {
if (enableEllipsis && !needMeasureEllipsis) {
setIsLineClampSupport(isStyleSupport('webkitLineClamp'));
setIsTextOverflowSupport(isStyleSupport('textOverflow'));
}
}, [needMeasureEllipsis, enableEllipsis]);
const cssEllipsis = React.useMemo(() => {
if (needMeasureEllipsis) {
return false;
}
if (rows === 1) {
return isTextOverflowSupport;
}
return isLineClampSupport;
}, [needMeasureEllipsis, isTextOverflowSupport, isLineClampSupport]);
const isMergedEllipsis = mergedEnableEllipsis && (cssEllipsis ? isNativeEllipsis : isJsEllipsis);
const cssTextOverflow = mergedEnableEllipsis && rows === 1 && cssEllipsis;
const cssLineClamp = mergedEnableEllipsis && rows > 1 && cssEllipsis;
// >>>>> Expand
const onExpandClick = e => {
var _a;
setExpanded(true);
(_a = ellipsisConfig.onExpand) === null || _a === void 0 ? void 0 : _a.call(ellipsisConfig, e);
};
const [ellipsisWidth, setEllipsisWidth] = React.useState(0);
const [ellipsisFontSize, setEllipsisFontSize] = React.useState(0);
const onResize = (_ref2, element) => {
let {
offsetWidth
} = _ref2;
var _a;
setEllipsisWidth(offsetWidth);
setEllipsisFontSize(parseInt((_a = window.getComputedStyle) === null || _a === void 0 ? void 0 : _a.call(window, element).fontSize, 10) || 0);
};
// >>>>> JS Ellipsis
const onJsEllipsis = jsEllipsis => {
var _a;
setIsJsEllipsis(jsEllipsis);
// Trigger if changed
if (isJsEllipsis !== jsEllipsis) {
(_a = ellipsisConfig.onEllipsis) === null || _a === void 0 ? void 0 : _a.call(ellipsisConfig, jsEllipsis);
}
};
// >>>>> Native ellipsis
React.useEffect(() => {
const textEle = typographyRef.current;
if (enableEllipsis && cssEllipsis && textEle) {
const currentEllipsis = cssLineClamp ? textEle.offsetHeight < textEle.scrollHeight : textEle.offsetWidth < textEle.scrollWidth;
if (isNativeEllipsis !== currentEllipsis) {
setIsNativeEllipsis(currentEllipsis);
}
}
}, [enableEllipsis, cssEllipsis, children, cssLineClamp, isNativeVisible]);
// https://github.com/ant-design/ant-design/issues/36786
// Use IntersectionObserver to check if element is invisible
React.useEffect(() => {
const textEle = typographyRef.current;
if (typeof IntersectionObserver === 'undefined' || !textEle || !cssEllipsis || !mergedEnableEllipsis) {
return;
}
/* eslint-disable-next-line compat/compat */
const observer = new IntersectionObserver(() => {
setIsNativeVisible(!!textEle.offsetParent);
});
observer.observe(textEle);
return () => {
observer.disconnect();
};
}, [cssEllipsis, mergedEnableEllipsis]);
// ========================== Tooltip ===========================
let tooltipProps = {};
if (ellipsisConfig.tooltip === true) {
tooltipProps = {
title: (_a = editConfig.text) !== null && _a !== void 0 ? _a : children
};
} else if ( /*#__PURE__*/React.isValidElement(ellipsisConfig.tooltip)) {
tooltipProps = {
title: ellipsisConfig.tooltip
};
} else if (typeof ellipsisConfig.tooltip === 'object') {
tooltipProps = Object.assign({
title: (_b = editConfig.text) !== null && _b !== void 0 ? _b : children
}, ellipsisConfig.tooltip);
} else {
tooltipProps = {
title: ellipsisConfig.tooltip
};
}
const topAriaLabel = React.useMemo(() => {
const isValid = val => ['string', 'number'].includes(typeof val);
if (!enableEllipsis || cssEllipsis) {
return undefined;
}
if (isValid(editConfig.text)) {
return editConfig.text;
}
if (isValid(children)) {
return children;
}
if (isValid(title)) {
return title;
}
if (isValid(tooltipProps.title)) {
return tooltipProps.title;
}
return undefined;
}, [enableEllipsis, cssEllipsis, title, tooltipProps.title, isMergedEllipsis]);
// =========================== Render ===========================
// >>>>>>>>>>> Editing input
if (editing) {
return /*#__PURE__*/React.createElement(Editable, {
value: (_c = editConfig.text) !== null && _c !== void 0 ? _c : typeof children === 'string' ? children : '',
onSave: onEditChange,
onCancel: onEditCancel,
onEnd: editConfig.onEnd,
prefixCls: prefixCls,
className: className,
style: style,
direction: direction,
component: component,
maxLength: editConfig.maxLength,
autoSize: editConfig.autoSize,
enterIcon: editConfig.enterIcon
});
}
// >>>>>>>>>>> Typography
// Expand
const renderExpand = () => {
const {
expandable,
symbol
} = ellipsisConfig;
if (!expandable) return null;
let expandContent;
if (symbol) {
expandContent = symbol;
} else {
expandContent = textLocale === null || textLocale === void 0 ? void 0 : textLocale.expand;
}
return /*#__PURE__*/React.createElement("a", {
key: "expand",
className: `${prefixCls}-expand`,
onClick: onExpandClick,
"aria-label": textLocale === null || textLocale === void 0 ? void 0 : textLocale.expand
}, expandContent);
};
// Edit
const renderEdit = () => {
if (!enableEdit) return;
const {
icon,
tooltip
} = editConfig;
const editTitle = toArray(tooltip)[0] || (textLocale === null || textLocale === void 0 ? void 0 : textLocale.edit);
const ariaLabel = typeof editTitle === 'string' ? editTitle : '';
return triggerType.includes('icon') ? /*#__PURE__*/React.createElement(Tooltip, {
key: "edit",
title: tooltip === false ? '' : editTitle
}, /*#__PURE__*/React.createElement(TransButton, {
ref: editIconRef,
className: `${prefixCls}-edit`,
onClick: onEditClick,
"aria-label": ariaLabel
}, icon || /*#__PURE__*/React.createElement(EditOutlined, {
role: "button"
}))) : null;
};
// Copy
const renderCopy = () => {
if (!enableCopy) return;
const {
tooltips,
icon
} = copyConfig;
const tooltipNodes = toList(tooltips);
const iconNodes = toList(icon);
const copyTitle = copied ? getNode(tooltipNodes[1], textLocale === null || textLocale === void 0 ? void 0 : textLocale.copied) : getNode(tooltipNodes[0], textLocale === null || textLocale === void 0 ? void 0 : textLocale.copy);
const systemStr = copied ? textLocale === null || textLocale === void 0 ? void 0 : textLocale.copied : textLocale === null || textLocale === void 0 ? void 0 : textLocale.copy;
const ariaLabel = typeof copyTitle === 'string' ? copyTitle : systemStr;
return /*#__PURE__*/React.createElement(Tooltip, {
key: "copy",
title: copyTitle
}, /*#__PURE__*/React.createElement(TransButton, {
className: classNames(`${prefixCls}-copy`, copied && `${prefixCls}-copy-success`),
onClick: onCopyClick,
"aria-label": ariaLabel
}, copied ? getNode(iconNodes[1], /*#__PURE__*/React.createElement(CheckOutlined, null), true) : getNode(iconNodes[0], /*#__PURE__*/React.createElement(CopyOutlined, null), true)));
};
const renderOperations = renderExpanded => [renderExpanded && renderExpand(), renderEdit(), renderCopy()];
const renderEllipsis = needEllipsis => [needEllipsis && /*#__PURE__*/React.createElement("span", {
"aria-hidden": true,
key: "ellipsis"
}, ELLIPSIS_STR), ellipsisConfig.suffix, renderOperations(needEllipsis)];
return /*#__PURE__*/React.createElement(ResizeObserver, {
onResize: onResize,
disabled: !mergedEnableEllipsis || cssEllipsis
}, resizeRef => /*#__PURE__*/React.createElement(EllipsisTooltip, {
tooltipProps: tooltipProps,
enabledEllipsis: mergedEnableEllipsis,
isEllipsis: isMergedEllipsis
}, /*#__PURE__*/React.createElement(Typography, Object.assign({
className: classNames({
[`${prefixCls}-${type}`]: type,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-ellipsis`]: enableEllipsis,
[`${prefixCls}-single-line`]: mergedEnableEllipsis && rows === 1,
[`${prefixCls}-ellipsis-single-line`]: cssTextOverflow,
[`${prefixCls}-ellipsis-multiple-line`]: cssLineClamp
}, className),
prefixCls: customizePrefixCls,
style: Object.assign(Object.assign({}, style), {
WebkitLineClamp: cssLineClamp ? rows : undefined
}),
component: component,
ref: composeRef(resizeRef, typographyRef, ref),
direction: direction,
onClick: triggerType.includes('text') ? onEditClick : undefined,
"aria-label": topAriaLabel === null || topAriaLabel === void 0 ? void 0 : topAriaLabel.toString(),
title: title
}, textProps), /*#__PURE__*/React.createElement(Ellipsis, {
enabledMeasure: mergedEnableEllipsis && !cssEllipsis,
text: children,
rows: rows,
width: ellipsisWidth,
fontSize: ellipsisFontSize,
onEllipsis: onJsEllipsis
}, (node, needEllipsis) => {
let renderNode = node;
if (node.length && needEllipsis && topAriaLabel) {
renderNode = /*#__PURE__*/React.createElement("span", {
key: "show-content",
"aria-hidden": true
}, renderNode);
}
const wrappedContext = wrapperDecorations(props, /*#__PURE__*/React.createElement(React.Fragment, null, renderNode, renderEllipsis(needEllipsis)));
return wrappedContext;
}))));
});
export default Base;