| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
- import _extends from "@babel/runtime/helpers/esm/extends";
- import { Fragment as _Fragment, resolveDirective as _resolveDirective, createVNode as _createVNode } from "vue";
- 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 LocaleReceiver from '../locale-provider/LocaleReceiver';
- import warning from '../_util/warning';
- import TransButton from '../_util/transButton';
- import raf from '../_util/raf';
- import { isStyleSupport } from '../_util/styleChecker';
- import Editable from './Editable';
- import measure from './util';
- import Typography from './Typography';
- import ResizeObserver from '../vc-resize-observer';
- import Tooltip from '../tooltip';
- import copy from '../_util/copy-to-clipboard';
- import CheckOutlined from "@ant-design/icons-vue/es/icons/CheckOutlined";
- import CopyOutlined from "@ant-design/icons-vue/es/icons/CopyOutlined";
- import EditOutlined from "@ant-design/icons-vue/es/icons/EditOutlined";
- import { defineComponent, reactive, ref, onMounted, onBeforeUnmount, watch, watchEffect, nextTick, computed, toRaw } from 'vue';
- import useConfigInject from '../config-provider/hooks/useConfigInject';
- import omit from '../_util/omit';
- import useMergedState from '../_util/hooks/useMergedState';
- import { findDOMNode } from '../_util/props-util';
- const isLineClampSupport = isStyleSupport('webkitLineClamp');
- const isTextOverflowSupport = isStyleSupport('textOverflow');
- const ELLIPSIS_STR = '...';
- export const baseProps = () => ({
- editable: {
- type: [Boolean, Object],
- default: undefined
- },
- copyable: {
- type: [Boolean, Object],
- default: undefined
- },
- prefixCls: String,
- component: String,
- type: String,
- disabled: {
- type: Boolean,
- default: undefined
- },
- ellipsis: {
- type: [Boolean, Object],
- default: undefined
- },
- code: {
- type: Boolean,
- default: undefined
- },
- mark: {
- type: Boolean,
- default: undefined
- },
- underline: {
- type: Boolean,
- default: undefined
- },
- delete: {
- type: Boolean,
- default: undefined
- },
- strong: {
- type: Boolean,
- default: undefined
- },
- keyboard: {
- type: Boolean,
- default: undefined
- },
- content: String,
- 'onUpdate:content': Function
- });
- const Base = defineComponent({
- compatConfig: {
- MODE: 3
- },
- name: 'TypographyBase',
- inheritAttrs: false,
- props: baseProps(),
- // emits: ['update:content'],
- setup(props, _ref) {
- let {
- slots,
- attrs,
- emit
- } = _ref;
- const {
- prefixCls,
- direction
- } = useConfigInject('typography', props);
- const state = reactive({
- copied: false,
- ellipsisText: '',
- ellipsisContent: null,
- isEllipsis: false,
- expanded: false,
- clientRendered: false,
- //locale
- expandStr: '',
- copyStr: '',
- copiedStr: '',
- editStr: '',
- copyId: undefined,
- rafId: undefined,
- prevProps: undefined,
- originContent: ''
- });
- const contentRef = ref();
- const editIcon = ref();
- const ellipsis = computed(() => {
- const ellipsis = props.ellipsis;
- if (!ellipsis) return {};
- return _extends({
- rows: 1,
- expandable: false
- }, typeof ellipsis === 'object' ? ellipsis : null);
- });
- onMounted(() => {
- state.clientRendered = true;
- syncEllipsis();
- });
- onBeforeUnmount(() => {
- clearTimeout(state.copyId);
- raf.cancel(state.rafId);
- });
- watch([() => ellipsis.value.rows, () => props.content], () => {
- nextTick(() => {
- resizeOnNextFrame();
- });
- }, {
- flush: 'post',
- deep: true
- });
- watchEffect(() => {
- if (props.content === undefined) {
- warning(!props.editable, 'Typography', 'When `editable` is enabled, please use `content` instead of children');
- warning(!props.ellipsis, 'Typography', 'When `ellipsis` is enabled, please use `content` instead of children');
- }
- });
- function getChildrenText() {
- var _a;
- return props.ellipsis || props.editable ? props.content : (_a = findDOMNode(contentRef.value)) === null || _a === void 0 ? void 0 : _a.innerText;
- }
- // =============== Expand ===============
- function onExpandClick(e) {
- const {
- onExpand
- } = ellipsis.value;
- state.expanded = true;
- onExpand === null || onExpand === void 0 ? void 0 : onExpand(e);
- }
- // ================ Edit ================
- function onEditClick(e) {
- e.preventDefault();
- state.originContent = props.content;
- triggerEdit(true);
- }
- function onEditChange(value) {
- onContentChange(value);
- triggerEdit(false);
- }
- function onContentChange(value) {
- const {
- onChange
- } = editable.value;
- if (value !== props.content) {
- emit('update:content', value);
- onChange === null || onChange === void 0 ? void 0 : onChange(value);
- }
- }
- function onEditCancel() {
- var _a, _b;
- (_b = (_a = editable.value).onCancel) === null || _b === void 0 ? void 0 : _b.call(_a);
- triggerEdit(false);
- }
- // ================ Copy ================
- function onCopyClick(e) {
- e.preventDefault();
- e.stopPropagation();
- const {
- copyable
- } = props;
- const copyConfig = _extends({}, typeof copyable === 'object' ? copyable : null);
- if (copyConfig.text === undefined) {
- copyConfig.text = getChildrenText();
- }
- copy(copyConfig.text || '');
- state.copied = true;
- nextTick(() => {
- if (copyConfig.onCopy) {
- copyConfig.onCopy(e);
- }
- state.copyId = setTimeout(() => {
- state.copied = false;
- }, 3000);
- });
- }
- const editable = computed(() => {
- const editable = props.editable;
- if (!editable) return {
- editing: false
- };
- return _extends({}, typeof editable === 'object' ? editable : null);
- });
- const [editing, setEditing] = useMergedState(false, {
- value: computed(() => {
- return editable.value.editing;
- })
- });
- function triggerEdit(edit) {
- const {
- onStart
- } = editable.value;
- if (edit && onStart) {
- onStart();
- }
- setEditing(edit);
- }
- watch(editing, val => {
- var _a;
- if (!val) {
- (_a = editIcon.value) === null || _a === void 0 ? void 0 : _a.focus();
- }
- }, {
- flush: 'post'
- });
- // ============== Ellipsis ==============
- function resizeOnNextFrame(sizeInfo) {
- if (sizeInfo) {
- const {
- width,
- height
- } = sizeInfo;
- if (!width || !height) return;
- }
- raf.cancel(state.rafId);
- state.rafId = raf(() => {
- // Do not bind `syncEllipsis`. It need for test usage on prototype
- syncEllipsis();
- });
- }
- const canUseCSSEllipsis = computed(() => {
- const {
- rows,
- expandable,
- suffix,
- onEllipsis,
- tooltip
- } = ellipsis.value;
- if (suffix || tooltip) return false;
- // Can't use css ellipsis since we need to provide the place for button
- if (props.editable || props.copyable || expandable || onEllipsis) {
- return false;
- }
- if (rows === 1) {
- return isTextOverflowSupport;
- }
- return isLineClampSupport;
- });
- const syncEllipsis = () => {
- const {
- ellipsisText,
- isEllipsis
- } = state;
- const {
- rows,
- suffix,
- onEllipsis
- } = ellipsis.value;
- if (!rows || rows < 0 || !findDOMNode(contentRef.value) || state.expanded || props.content === undefined) return;
- // Do not measure if css already support ellipsis
- if (canUseCSSEllipsis.value) return;
- const {
- content,
- text,
- ellipsis: ell
- } = measure(findDOMNode(contentRef.value), {
- rows,
- suffix
- }, props.content, renderOperations(true), ELLIPSIS_STR);
- if (ellipsisText !== text || state.isEllipsis !== ell) {
- state.ellipsisText = text;
- state.ellipsisContent = content;
- state.isEllipsis = ell;
- if (isEllipsis !== ell && onEllipsis) {
- onEllipsis(ell);
- }
- }
- };
- function wrapperDecorations(_ref2, content) {
- let {
- mark,
- code,
- underline,
- delete: del,
- strong,
- keyboard
- } = _ref2;
- let currentContent = content;
- function wrap(needed, Tag) {
- if (!needed) return;
- const _currentContent = function () {
- return currentContent;
- }();
- currentContent = _createVNode(Tag, null, {
- default: () => [_currentContent]
- });
- }
- wrap(strong, 'strong');
- wrap(underline, 'u');
- wrap(del, 'del');
- wrap(code, 'code');
- wrap(mark, 'mark');
- wrap(keyboard, 'kbd');
- return currentContent;
- }
- function renderExpand(forceRender) {
- const {
- expandable,
- symbol
- } = ellipsis.value;
- if (!expandable) return null;
- // force render expand icon for measure usage or it will cause dead loop
- if (!forceRender && (state.expanded || !state.isEllipsis)) return null;
- const expandContent = (slots.ellipsisSymbol ? slots.ellipsisSymbol() : symbol) || state.expandStr;
- return _createVNode("a", {
- "key": "expand",
- "class": `${prefixCls.value}-expand`,
- "onClick": onExpandClick,
- "aria-label": state.expandStr
- }, [expandContent]);
- }
- function renderEdit() {
- if (!props.editable) return;
- const {
- tooltip,
- triggerType = ['icon']
- } = props.editable;
- const icon = slots.editableIcon ? slots.editableIcon() : _createVNode(EditOutlined, {
- "role": "button"
- }, null);
- const title = slots.editableTooltip ? slots.editableTooltip() : state.editStr;
- const ariaLabel = typeof title === 'string' ? title : '';
- return triggerType.indexOf('icon') !== -1 ? _createVNode(Tooltip, {
- "key": "edit",
- "title": tooltip === false ? '' : title
- }, {
- default: () => [_createVNode(TransButton, {
- "ref": editIcon,
- "class": `${prefixCls.value}-edit`,
- "onClick": onEditClick,
- "aria-label": ariaLabel
- }, {
- default: () => [icon]
- })]
- }) : null;
- }
- function renderCopy() {
- if (!props.copyable) return;
- const {
- tooltip
- } = props.copyable;
- const defaultTitle = state.copied ? state.copiedStr : state.copyStr;
- const title = slots.copyableTooltip ? slots.copyableTooltip({
- copied: state.copied
- }) : defaultTitle;
- const ariaLabel = typeof title === 'string' ? title : '';
- const defaultIcon = state.copied ? _createVNode(CheckOutlined, null, null) : _createVNode(CopyOutlined, null, null);
- const icon = slots.copyableIcon ? slots.copyableIcon({
- copied: !!state.copied
- }) : defaultIcon;
- return _createVNode(Tooltip, {
- "key": "copy",
- "title": tooltip === false ? '' : title
- }, {
- default: () => [_createVNode(TransButton, {
- "class": [`${prefixCls.value}-copy`, {
- [`${prefixCls.value}-copy-success`]: state.copied
- }],
- "onClick": onCopyClick,
- "aria-label": ariaLabel
- }, {
- default: () => [icon]
- })]
- });
- }
- function renderEditInput() {
- const {
- class: className,
- style
- } = attrs;
- const {
- maxlength,
- autoSize,
- onEnd
- } = editable.value;
- return _createVNode(Editable, {
- "class": className,
- "style": style,
- "prefixCls": prefixCls.value,
- "value": props.content,
- "originContent": state.originContent,
- "maxlength": maxlength,
- "autoSize": autoSize,
- "onSave": onEditChange,
- "onChange": onContentChange,
- "onCancel": onEditCancel,
- "onEnd": onEnd,
- "direction": direction.value,
- "component": props.component
- }, {
- enterIcon: slots.editableEnterIcon
- });
- }
- function renderOperations(forceRenderExpanded) {
- return [renderExpand(forceRenderExpanded), renderEdit(), renderCopy()].filter(node => node);
- }
- return () => {
- var _a;
- const {
- triggerType = ['icon']
- } = editable.value;
- const children = props.ellipsis || props.editable ? props.content !== undefined ? props.content : (_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots) : slots.default ? slots.default() : props.content;
- if (editing.value) {
- return renderEditInput();
- }
- return _createVNode(LocaleReceiver, {
- "componentName": "Text",
- "children": locale => {
- const _a = _extends(_extends({}, props), attrs),
- {
- type,
- disabled,
- content,
- class: className,
- style
- } = _a,
- restProps = __rest(_a, ["type", "disabled", "content", "class", "style"]);
- const {
- rows,
- suffix,
- tooltip
- } = ellipsis.value;
- const {
- edit,
- copy: copyStr,
- copied,
- expand
- } = locale;
- state.editStr = edit;
- state.copyStr = copyStr;
- state.copiedStr = copied;
- state.expandStr = expand;
- const textProps = omit(restProps, ['prefixCls', 'editable', 'copyable', 'ellipsis', 'mark', 'code', 'delete', 'underline', 'strong', 'keyboard', 'onUpdate:content']);
- const cssEllipsis = canUseCSSEllipsis.value;
- const cssTextOverflow = rows === 1 && cssEllipsis;
- const cssLineClamp = rows && rows > 1 && cssEllipsis;
- let textNode = children;
- let ariaLabel;
- // Only use js ellipsis when css ellipsis not support
- if (rows && state.isEllipsis && !state.expanded && !cssEllipsis) {
- const {
- title
- } = restProps;
- let restContent = title || '';
- if (!title && (typeof children === 'string' || typeof children === 'number')) {
- restContent = String(children);
- }
- // show rest content as title on symbol
- restContent = restContent === null || restContent === void 0 ? void 0 : restContent.slice(String(state.ellipsisContent || '').length);
- // We move full content to outer element to avoid repeat read the content by accessibility
- textNode = _createVNode(_Fragment, null, [toRaw(state.ellipsisContent), _createVNode("span", {
- "title": restContent,
- "aria-hidden": "true"
- }, [ELLIPSIS_STR]), suffix]);
- } else {
- textNode = _createVNode(_Fragment, null, [children, suffix]);
- }
- textNode = wrapperDecorations(props, textNode);
- const showTooltip = tooltip && rows && state.isEllipsis && !state.expanded && !cssEllipsis;
- const title = slots.ellipsisTooltip ? slots.ellipsisTooltip() : tooltip;
- return _createVNode(ResizeObserver, {
- "onResize": resizeOnNextFrame,
- "disabled": !rows
- }, {
- default: () => [_createVNode(Typography, _objectSpread({
- "ref": contentRef,
- "class": [{
- [`${prefixCls.value}-${type}`]: type,
- [`${prefixCls.value}-disabled`]: disabled,
- [`${prefixCls.value}-ellipsis`]: rows,
- [`${prefixCls.value}-single-line`]: rows === 1 && !state.isEllipsis,
- [`${prefixCls.value}-ellipsis-single-line`]: cssTextOverflow,
- [`${prefixCls.value}-ellipsis-multiple-line`]: cssLineClamp
- }, className],
- "style": _extends(_extends({}, style), {
- WebkitLineClamp: cssLineClamp ? rows : undefined
- }),
- "aria-label": ariaLabel,
- "direction": direction.value,
- "onClick": triggerType.indexOf('text') !== -1 ? onEditClick : () => {}
- }, textProps), {
- default: () => [showTooltip ? _createVNode(Tooltip, {
- "title": tooltip === true ? children : title
- }, {
- default: () => [_createVNode("span", null, [textNode])]
- }) : textNode, renderOperations()]
- })]
- });
- }
- }, null);
- };
- }
- });
- export default Base;
|