Base.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = exports.baseProps = void 0;
  7. var _vue = require("vue");
  8. var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
  9. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  10. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  11. var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
  12. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  13. var _LocaleReceiver = _interopRequireDefault(require("../locale-provider/LocaleReceiver"));
  14. var _warning = _interopRequireDefault(require("../_util/warning"));
  15. var _transButton = _interopRequireDefault(require("../_util/transButton"));
  16. var _raf = _interopRequireDefault(require("../_util/raf"));
  17. var _styleChecker = require("../_util/styleChecker");
  18. var _Editable = _interopRequireDefault(require("./Editable"));
  19. var _util = _interopRequireDefault(require("./util"));
  20. var _Typography = _interopRequireDefault(require("./Typography"));
  21. var _vcResizeObserver = _interopRequireDefault(require("../vc-resize-observer"));
  22. var _tooltip = _interopRequireDefault(require("../tooltip"));
  23. var _copyToClipboard = _interopRequireDefault(require("../_util/copy-to-clipboard"));
  24. var _CheckOutlined = _interopRequireDefault(require("@ant-design/icons-vue/lib/icons/CheckOutlined"));
  25. var _CopyOutlined = _interopRequireDefault(require("@ant-design/icons-vue/lib/icons/CopyOutlined"));
  26. var _EditOutlined = _interopRequireDefault(require("@ant-design/icons-vue/lib/icons/EditOutlined"));
  27. var _useConfigInject2 = _interopRequireDefault(require("../_util/hooks/useConfigInject"));
  28. var _omit = _interopRequireDefault(require("../_util/omit"));
  29. var _useMergedState3 = _interopRequireDefault(require("../_util/hooks/useMergedState"));
  30. var _excluded = ["type", "disabled", "content", "class", "style"];
  31. var isLineClampSupport = (0, _styleChecker.isStyleSupport)('webkitLineClamp');
  32. var isTextOverflowSupport = (0, _styleChecker.isStyleSupport)('textOverflow');
  33. var ELLIPSIS_STR = '...';
  34. var baseProps = function baseProps() {
  35. return {
  36. editable: {
  37. type: [Boolean, Object],
  38. default: undefined
  39. },
  40. copyable: {
  41. type: [Boolean, Object],
  42. default: undefined
  43. },
  44. prefixCls: String,
  45. component: String,
  46. type: String,
  47. disabled: {
  48. type: Boolean,
  49. default: undefined
  50. },
  51. ellipsis: {
  52. type: [Boolean, Object],
  53. default: undefined
  54. },
  55. code: {
  56. type: Boolean,
  57. default: undefined
  58. },
  59. mark: {
  60. type: Boolean,
  61. default: undefined
  62. },
  63. underline: {
  64. type: Boolean,
  65. default: undefined
  66. },
  67. delete: {
  68. type: Boolean,
  69. default: undefined
  70. },
  71. strong: {
  72. type: Boolean,
  73. default: undefined
  74. },
  75. keyboard: {
  76. type: Boolean,
  77. default: undefined
  78. },
  79. content: String,
  80. 'onUpdate:content': Function
  81. };
  82. };
  83. exports.baseProps = baseProps;
  84. var Base = (0, _vue.defineComponent)({
  85. compatConfig: {
  86. MODE: 3
  87. },
  88. name: 'Base',
  89. inheritAttrs: false,
  90. props: baseProps(),
  91. // emits: ['update:content'],
  92. setup: function setup(props, _ref) {
  93. var slots = _ref.slots,
  94. attrs = _ref.attrs,
  95. emit = _ref.emit;
  96. var _useConfigInject = (0, _useConfigInject2.default)('typography', props),
  97. prefixCls = _useConfigInject.prefixCls,
  98. direction = _useConfigInject.direction;
  99. var state = (0, _vue.reactive)({
  100. copied: false,
  101. ellipsisText: '',
  102. ellipsisContent: null,
  103. isEllipsis: false,
  104. expanded: false,
  105. clientRendered: false,
  106. //locale
  107. expandStr: '',
  108. copyStr: '',
  109. copiedStr: '',
  110. editStr: '',
  111. copyId: undefined,
  112. rafId: undefined,
  113. prevProps: undefined,
  114. originContent: ''
  115. });
  116. var contentRef = (0, _vue.ref)();
  117. var editIcon = (0, _vue.ref)();
  118. var ellipsis = (0, _vue.computed)(function () {
  119. var ellipsis = props.ellipsis;
  120. if (!ellipsis) return {};
  121. return (0, _objectSpread2.default)({
  122. rows: 1,
  123. expandable: false
  124. }, (0, _typeof2.default)(ellipsis) === 'object' ? ellipsis : null);
  125. });
  126. (0, _vue.onMounted)(function () {
  127. state.clientRendered = true;
  128. });
  129. (0, _vue.onBeforeUnmount)(function () {
  130. clearTimeout(state.copyId);
  131. _raf.default.cancel(state.rafId);
  132. });
  133. (0, _vue.watch)([function () {
  134. return ellipsis.value.rows;
  135. }, function () {
  136. return props.content;
  137. }], function () {
  138. (0, _vue.nextTick)(function () {
  139. resizeOnNextFrame();
  140. });
  141. }, {
  142. flush: 'post',
  143. deep: true,
  144. immediate: true
  145. });
  146. (0, _vue.watchEffect)(function () {
  147. if (props.content === undefined) {
  148. (0, _warning.default)(!props.editable, 'Typography', 'When `editable` is enabled, please use `content` instead of children');
  149. (0, _warning.default)(!props.ellipsis, 'Typography', 'When `ellipsis` is enabled, please use `content` instead of children');
  150. }
  151. });
  152. function getChildrenText() {
  153. var _contentRef$value, _contentRef$value$$el;
  154. return props.ellipsis || props.editable ? props.content : (_contentRef$value = contentRef.value) === null || _contentRef$value === void 0 ? void 0 : (_contentRef$value$$el = _contentRef$value.$el) === null || _contentRef$value$$el === void 0 ? void 0 : _contentRef$value$$el.innerText;
  155. }
  156. // =============== Expand ===============
  157. function onExpandClick(e) {
  158. var onExpand = ellipsis.value.onExpand;
  159. state.expanded = true;
  160. onExpand === null || onExpand === void 0 ? void 0 : onExpand(e);
  161. }
  162. // ================ Edit ================
  163. function onEditClick(e) {
  164. e.preventDefault();
  165. state.originContent = props.content;
  166. triggerEdit(true);
  167. }
  168. function onEditChange(value) {
  169. onContentChange(value);
  170. triggerEdit(false);
  171. }
  172. function onContentChange(value) {
  173. var onChange = editable.value.onChange;
  174. if (value !== props.content) {
  175. emit('update:content', value);
  176. onChange === null || onChange === void 0 ? void 0 : onChange(value);
  177. }
  178. }
  179. function onEditCancel() {
  180. var _editable$value$onCan, _editable$value;
  181. (_editable$value$onCan = (_editable$value = editable.value).onCancel) === null || _editable$value$onCan === void 0 ? void 0 : _editable$value$onCan.call(_editable$value);
  182. triggerEdit(false);
  183. }
  184. // ================ Copy ================
  185. function onCopyClick(e) {
  186. e.preventDefault();
  187. e.stopPropagation();
  188. var copyable = props.copyable;
  189. var copyConfig = (0, _objectSpread2.default)({}, (0, _typeof2.default)(copyable) === 'object' ? copyable : null);
  190. if (copyConfig.text === undefined) {
  191. copyConfig.text = getChildrenText();
  192. }
  193. (0, _copyToClipboard.default)(copyConfig.text || '');
  194. state.copied = true;
  195. (0, _vue.nextTick)(function () {
  196. if (copyConfig.onCopy) {
  197. copyConfig.onCopy();
  198. }
  199. state.copyId = setTimeout(function () {
  200. state.copied = false;
  201. }, 3000);
  202. });
  203. }
  204. var editable = (0, _vue.computed)(function () {
  205. var editable = props.editable;
  206. if (!editable) return {
  207. editing: false
  208. };
  209. return (0, _objectSpread2.default)({}, (0, _typeof2.default)(editable) === 'object' ? editable : null);
  210. });
  211. var _useMergedState = (0, _useMergedState3.default)(false, {
  212. value: (0, _vue.computed)(function () {
  213. return editable.value.editing;
  214. })
  215. }),
  216. _useMergedState2 = (0, _slicedToArray2.default)(_useMergedState, 2),
  217. editing = _useMergedState2[0],
  218. setEditing = _useMergedState2[1];
  219. function triggerEdit(edit) {
  220. var onStart = editable.value.onStart;
  221. if (edit && onStart) {
  222. onStart();
  223. }
  224. setEditing(edit);
  225. }
  226. (0, _vue.watch)(editing, function (val) {
  227. if (!val) {
  228. var _editIcon$value;
  229. (_editIcon$value = editIcon.value) === null || _editIcon$value === void 0 ? void 0 : _editIcon$value.focus();
  230. }
  231. }, {
  232. flush: 'post'
  233. });
  234. // ============== Ellipsis ==============
  235. function resizeOnNextFrame() {
  236. _raf.default.cancel(state.rafId);
  237. state.rafId = (0, _raf.default)(function () {
  238. // Do not bind `syncEllipsis`. It need for test usage on prototype
  239. syncEllipsis();
  240. });
  241. }
  242. var canUseCSSEllipsis = (0, _vue.computed)(function () {
  243. var _ellipsis$value = ellipsis.value,
  244. rows = _ellipsis$value.rows,
  245. expandable = _ellipsis$value.expandable,
  246. suffix = _ellipsis$value.suffix,
  247. onEllipsis = _ellipsis$value.onEllipsis,
  248. tooltip = _ellipsis$value.tooltip;
  249. if (suffix || tooltip) return false;
  250. // Can't use css ellipsis since we need to provide the place for button
  251. if (props.editable || props.copyable || expandable || onEllipsis) {
  252. return false;
  253. }
  254. if (rows === 1) {
  255. return isTextOverflowSupport;
  256. }
  257. return isLineClampSupport;
  258. });
  259. var syncEllipsis = function syncEllipsis() {
  260. var _contentRef$value2, _contentRef$value3;
  261. var ellipsisText = state.ellipsisText,
  262. isEllipsis = state.isEllipsis;
  263. var _ellipsis$value2 = ellipsis.value,
  264. rows = _ellipsis$value2.rows,
  265. suffix = _ellipsis$value2.suffix,
  266. onEllipsis = _ellipsis$value2.onEllipsis;
  267. if (!rows || rows < 0 || !((_contentRef$value2 = contentRef.value) !== null && _contentRef$value2 !== void 0 && _contentRef$value2.$el) || state.expanded || props.content === undefined) return;
  268. // Do not measure if css already support ellipsis
  269. if (canUseCSSEllipsis.value) return;
  270. var _measure = (0, _util.default)((_contentRef$value3 = contentRef.value) === null || _contentRef$value3 === void 0 ? void 0 : _contentRef$value3.$el, {
  271. rows: rows,
  272. suffix: suffix
  273. }, props.content, renderOperations(true), ELLIPSIS_STR),
  274. content = _measure.content,
  275. text = _measure.text,
  276. ell = _measure.ellipsis;
  277. if (ellipsisText !== text || state.isEllipsis !== ell) {
  278. state.ellipsisText = text;
  279. state.ellipsisContent = content;
  280. state.isEllipsis = ell;
  281. if (isEllipsis !== ell && onEllipsis) {
  282. onEllipsis(ell);
  283. }
  284. }
  285. };
  286. function wrapperDecorations(_ref2, content) {
  287. var mark = _ref2.mark,
  288. code = _ref2.code,
  289. underline = _ref2.underline,
  290. del = _ref2.delete,
  291. strong = _ref2.strong,
  292. keyboard = _ref2.keyboard;
  293. var currentContent = content;
  294. function wrap(needed, Tag) {
  295. if (!needed) return;
  296. var _currentContent = function () {
  297. return currentContent;
  298. }();
  299. currentContent = (0, _vue.createVNode)(Tag, null, {
  300. default: function _default() {
  301. return [_currentContent];
  302. }
  303. });
  304. }
  305. wrap(strong, 'strong');
  306. wrap(underline, 'u');
  307. wrap(del, 'del');
  308. wrap(code, 'code');
  309. wrap(mark, 'mark');
  310. wrap(keyboard, 'kbd');
  311. return currentContent;
  312. }
  313. function renderExpand(forceRender) {
  314. var _ellipsis$value3 = ellipsis.value,
  315. expandable = _ellipsis$value3.expandable,
  316. symbol = _ellipsis$value3.symbol;
  317. if (!expandable) return null;
  318. // force render expand icon for measure usage or it will cause dead loop
  319. if (!forceRender && (state.expanded || !state.isEllipsis)) return null;
  320. var expandContent = (slots.ellipsisSymbol ? slots.ellipsisSymbol() : symbol) || state.expandStr;
  321. return (0, _vue.createVNode)("a", {
  322. "key": "expand",
  323. "class": "".concat(prefixCls.value, "-expand"),
  324. "onClick": onExpandClick,
  325. "aria-label": state.expandStr
  326. }, [expandContent]);
  327. }
  328. function renderEdit() {
  329. if (!props.editable) return;
  330. var _props$editable = props.editable,
  331. tooltip = _props$editable.tooltip,
  332. _props$editable$trigg = _props$editable.triggerType,
  333. triggerType = _props$editable$trigg === void 0 ? ['icon'] : _props$editable$trigg;
  334. var icon = slots.editableIcon ? slots.editableIcon() : (0, _vue.createVNode)(_EditOutlined.default, {
  335. "role": "button"
  336. }, null);
  337. var title = slots.editableTooltip ? slots.editableTooltip() : state.editStr;
  338. var ariaLabel = typeof title === 'string' ? title : '';
  339. return triggerType.indexOf('icon') !== -1 ? (0, _vue.createVNode)(_tooltip.default, {
  340. "key": "edit",
  341. "title": tooltip === false ? '' : title
  342. }, {
  343. default: function _default() {
  344. return [(0, _vue.createVNode)(_transButton.default, {
  345. "ref": editIcon,
  346. "class": "".concat(prefixCls.value, "-edit"),
  347. "onClick": onEditClick,
  348. "aria-label": ariaLabel
  349. }, {
  350. default: function _default() {
  351. return [icon];
  352. }
  353. })];
  354. }
  355. }) : null;
  356. }
  357. function renderCopy() {
  358. if (!props.copyable) return;
  359. var tooltip = props.copyable.tooltip;
  360. var defaultTitle = state.copied ? state.copiedStr : state.copyStr;
  361. var title = slots.copyableTooltip ? slots.copyableTooltip({
  362. copied: state.copied
  363. }) : defaultTitle;
  364. var ariaLabel = typeof title === 'string' ? title : '';
  365. var defaultIcon = state.copied ? (0, _vue.createVNode)(_CheckOutlined.default, null, null) : (0, _vue.createVNode)(_CopyOutlined.default, null, null);
  366. var icon = slots.copyableIcon ? slots.copyableIcon({
  367. copied: !!state.copied
  368. }) : defaultIcon;
  369. return (0, _vue.createVNode)(_tooltip.default, {
  370. "key": "copy",
  371. "title": tooltip === false ? '' : title
  372. }, {
  373. default: function _default() {
  374. return [(0, _vue.createVNode)(_transButton.default, {
  375. "class": ["".concat(prefixCls.value, "-copy"), (0, _defineProperty2.default)({}, "".concat(prefixCls.value, "-copy-success"), state.copied)],
  376. "onClick": onCopyClick,
  377. "aria-label": ariaLabel
  378. }, {
  379. default: function _default() {
  380. return [icon];
  381. }
  382. })];
  383. }
  384. });
  385. }
  386. function renderEditInput() {
  387. var className = attrs.class,
  388. style = attrs.style;
  389. var _editable$value2 = editable.value,
  390. maxlength = _editable$value2.maxlength,
  391. autoSize = _editable$value2.autoSize,
  392. onEnd = _editable$value2.onEnd;
  393. return (0, _vue.createVNode)(_Editable.default, {
  394. "class": className,
  395. "style": style,
  396. "prefixCls": prefixCls.value,
  397. "value": props.content,
  398. "originContent": state.originContent,
  399. "maxlength": maxlength,
  400. "autoSize": autoSize,
  401. "onSave": onEditChange,
  402. "onChange": onContentChange,
  403. "onCancel": onEditCancel,
  404. "onEnd": onEnd,
  405. "direction": direction.value
  406. }, {
  407. enterIcon: slots.editableEnterIcon
  408. });
  409. }
  410. function renderOperations(forceRenderExpanded) {
  411. return [renderExpand(forceRenderExpanded), renderEdit(), renderCopy()].filter(function (node) {
  412. return node;
  413. });
  414. }
  415. return function () {
  416. var _slots$default;
  417. var _editable$value$trigg = editable.value.triggerType,
  418. triggerType = _editable$value$trigg === void 0 ? ['icon'] : _editable$value$trigg;
  419. var _children = props.ellipsis || props.editable ? props.content !== undefined ? props.content : (_slots$default = slots.default) === null || _slots$default === void 0 ? void 0 : _slots$default.call(slots) : slots.default ? slots.default() : props.content;
  420. if (editing.value) {
  421. return renderEditInput();
  422. }
  423. return (0, _vue.createVNode)(_LocaleReceiver.default, {
  424. "componentName": "Text",
  425. "children": function children(locale) {
  426. var _ref4;
  427. var _props$attrs = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), attrs),
  428. type = _props$attrs.type,
  429. disabled = _props$attrs.disabled,
  430. content = _props$attrs.content,
  431. className = _props$attrs.class,
  432. style = _props$attrs.style,
  433. restProps = (0, _objectWithoutProperties2.default)(_props$attrs, _excluded);
  434. var _ellipsis$value4 = ellipsis.value,
  435. rows = _ellipsis$value4.rows,
  436. suffix = _ellipsis$value4.suffix,
  437. tooltip = _ellipsis$value4.tooltip;
  438. var edit = locale.edit,
  439. copyStr = locale.copy,
  440. copied = locale.copied,
  441. expand = locale.expand;
  442. state.editStr = edit;
  443. state.copyStr = copyStr;
  444. state.copiedStr = copied;
  445. state.expandStr = expand;
  446. var textProps = (0, _omit.default)(restProps, ['prefixCls', 'editable', 'copyable', 'ellipsis', 'mark', 'code', 'delete', 'underline', 'strong', 'keyboard', 'onUpdate:content']);
  447. var cssEllipsis = canUseCSSEllipsis.value;
  448. var cssTextOverflow = rows === 1 && cssEllipsis;
  449. var cssLineClamp = rows && rows > 1 && cssEllipsis;
  450. var textNode = _children;
  451. var ariaLabel;
  452. // Only use js ellipsis when css ellipsis not support
  453. if (rows && state.isEllipsis && !state.expanded && !cssEllipsis) {
  454. var _restContent;
  455. var _title = restProps.title;
  456. var restContent = _title || '';
  457. if (!_title && (typeof _children === 'string' || typeof _children === 'number')) {
  458. restContent = String(_children);
  459. }
  460. // show rest content as title on symbol
  461. restContent = (_restContent = restContent) === null || _restContent === void 0 ? void 0 : _restContent.slice(String(state.ellipsisContent || '').length);
  462. // We move full content to outer element to avoid repeat read the content by accessibility
  463. textNode = (0, _vue.createVNode)(_vue.Fragment, null, [(0, _vue.toRaw)(state.ellipsisContent), (0, _vue.createVNode)("span", {
  464. "title": restContent,
  465. "aria-hidden": "true"
  466. }, [ELLIPSIS_STR]), suffix]);
  467. } else {
  468. textNode = (0, _vue.createVNode)(_vue.Fragment, null, [_children, suffix]);
  469. }
  470. textNode = wrapperDecorations(props, textNode);
  471. var showTooltip = tooltip && rows && state.isEllipsis && !state.expanded && !cssEllipsis;
  472. var title = slots.ellipsisTooltip ? slots.ellipsisTooltip() : tooltip;
  473. return (0, _vue.createVNode)(_vcResizeObserver.default, {
  474. "onResize": resizeOnNextFrame,
  475. "disabled": !rows
  476. }, {
  477. default: function _default() {
  478. return [(0, _vue.createVNode)(_Typography.default, (0, _objectSpread2.default)({
  479. "ref": contentRef,
  480. "class": [(_ref4 = {}, (0, _defineProperty2.default)(_ref4, "".concat(prefixCls.value, "-").concat(type), type), (0, _defineProperty2.default)(_ref4, "".concat(prefixCls.value, "-disabled"), disabled), (0, _defineProperty2.default)(_ref4, "".concat(prefixCls.value, "-ellipsis"), rows), (0, _defineProperty2.default)(_ref4, "".concat(prefixCls.value, "-single-line"), rows === 1 && !state.isEllipsis), (0, _defineProperty2.default)(_ref4, "".concat(prefixCls.value, "-ellipsis-single-line"), cssTextOverflow), (0, _defineProperty2.default)(_ref4, "".concat(prefixCls.value, "-ellipsis-multiple-line"), cssLineClamp), _ref4), className],
  481. "style": (0, _objectSpread2.default)((0, _objectSpread2.default)({}, style), {}, {
  482. WebkitLineClamp: cssLineClamp ? rows : undefined
  483. }),
  484. "aria-label": ariaLabel,
  485. "direction": direction.value,
  486. "onClick": triggerType.indexOf('text') !== -1 ? onEditClick : function () {}
  487. }, textProps), {
  488. default: function _default() {
  489. return [showTooltip ? (0, _vue.createVNode)(_tooltip.default, {
  490. "title": tooltip === true ? _children : title
  491. }, {
  492. default: function _default() {
  493. return [(0, _vue.createVNode)("span", null, [textNode])];
  494. }
  495. }) : textNode, renderOperations()];
  496. }
  497. })];
  498. }
  499. });
  500. }
  501. }, null);
  502. };
  503. }
  504. });
  505. var _default2 = Base;
  506. exports.default = _default2;