diff --git a/components/typography/Base.tsx b/components/typography/Base.tsx index 3976c065c..9b9b8c9ae 100644 --- a/components/typography/Base.tsx +++ b/components/typography/Base.tsx @@ -577,20 +577,22 @@ const Base = defineComponent({ }, }); -Base.props = { +export const baseProps = () => ({ editable: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]), copyable: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]), prefixCls: PropTypes.string, component: PropTypes.string, type: PropTypes.oneOf(['secondary', 'danger', 'warning']), - disabled: PropTypes.bool, + disabled: PropTypes.looseBool, ellipsis: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]), - code: PropTypes.bool, - mark: PropTypes.bool, - underline: PropTypes.bool, - delete: PropTypes.bool, - strong: PropTypes.bool, - keyboard: PropTypes.bool, -}; + code: PropTypes.looseBool, + mark: PropTypes.looseBool, + underline: PropTypes.looseBool, + delete: PropTypes.looseBool, + strong: PropTypes.looseBool, + keyboard: PropTypes.looseBool, +}); + +Base.props = baseProps(); export default Base; diff --git a/components/typography/Editable.tsx b/components/typography/Editable.tsx index b664f01aa..9d5c9f9fe 100644 --- a/components/typography/Editable.tsx +++ b/components/typography/Editable.tsx @@ -34,14 +34,16 @@ const Editable = defineComponent({ const textArea = ref(); onMounted(() => { - const resizableTextArea = textArea.value?.resizableTextArea; - const innerTextArea = resizableTextArea?.textArea; - innerTextArea.focus(); - const { length } = innerTextArea.value; - innerTextArea.setSelectionRange(length, length); + if (textArea.value) { + const resizableTextArea = textArea.value?.resizableTextArea; + const innerTextArea = resizableTextArea?.textArea; + innerTextArea.focus(); + const { length } = innerTextArea.value; + innerTextArea.setSelectionRange(length, length); + } }); - function saveTextAreaRef(node) { + function saveTextAreaRef(node: any) { textArea.value = node; } @@ -62,10 +64,6 @@ const Editable = defineComponent({ // We don't record keyCode when IME is using if (state.inComposition) return; - if (keyCode === KeyCode.ENTER) { - e.preventDefault(); - } - state.lastKeyCode = keyCode; } diff --git a/components/typography/Link.tsx b/components/typography/Link.tsx new file mode 100644 index 000000000..f727194e2 --- /dev/null +++ b/components/typography/Link.tsx @@ -0,0 +1,35 @@ +import { AnchorHTMLAttributes, FunctionalComponent } from 'vue'; +import warning from '../_util/warning'; +import Base, { baseProps, BlockProps } from './Base'; +import Omit from 'omit.js'; +import PropTypes from '../_util/vue-types'; + +export interface LinkProps extends BlockProps, Omit { + ellipsis?: boolean; +} + +const Link: FunctionalComponent = (props, { slots, attrs }) => { + const { ellipsis, rel, ...restProps } = { ...props, ...attrs }; + warning( + typeof ellipsis !== 'object', + 'Typography.Link', + '`ellipsis` only supports boolean value.', + ); + const mergedProps = { + ...restProps, + rel: rel === undefined && restProps.target === '_blank' ? 'noopener noreferrer' : rel, + ellipsis: !!ellipsis, + component: 'a', + }; + // https://github.com/ant-design/ant-design/issues/26622 + // @ts-ignore + delete mergedProps.navigate; + + return {slots.default?.()}; +}; + +Link.displayName = 'ATypographyText'; +Link.inheritAttrs = false; +Link.props = Omit({ ...baseProps(), ellipsis: PropTypes.looseBool }, ['component']); + +export default Link; diff --git a/components/typography/Paragraph.tsx b/components/typography/Paragraph.tsx index b5f254b76..b266b6845 100644 --- a/components/typography/Paragraph.tsx +++ b/components/typography/Paragraph.tsx @@ -1,5 +1,6 @@ +import Omit from 'omit.js'; import { FunctionalComponent } from 'vue'; -import Base, { BlockProps } from './Base'; +import Base, { BlockProps, baseProps } from './Base'; const Paragraph: FunctionalComponent = (props, { slots, attrs }) => { const paragraphProps = { @@ -13,5 +14,6 @@ const Paragraph: FunctionalComponent = (props, { slots, attrs }) => Paragraph.displayName = 'ATypographyParagraph'; Paragraph.inheritAttrs = false; +Paragraph.props = Omit(baseProps(), ['component']); export default Paragraph; diff --git a/components/typography/Text.tsx b/components/typography/Text.tsx index d714c52f2..7dbf12814 100644 --- a/components/typography/Text.tsx +++ b/components/typography/Text.tsx @@ -1,7 +1,8 @@ import { FunctionalComponent } from 'vue'; import omit from 'omit.js'; import warning from '../_util/warning'; -import Base, { BlockProps, EllipsisConfig } from './Base'; +import Base, { baseProps, BlockProps, EllipsisConfig } from './Base'; +import Omit from 'omit.js'; export interface TextProps extends BlockProps { ellipsis?: boolean | Omit; @@ -31,5 +32,6 @@ const Text: FunctionalComponent = (props, { slots, attrs }) => { Text.displayName = 'ATypographyText'; Text.inheritAttrs = false; +Text.props = Omit(baseProps(), ['component']); export default Text; diff --git a/components/typography/Title.tsx b/components/typography/Title.tsx index c2f9d9db6..f3ae3cf51 100644 --- a/components/typography/Title.tsx +++ b/components/typography/Title.tsx @@ -1,7 +1,9 @@ +import Omit from 'omit.js'; import { FunctionalComponent } from 'vue'; import { tupleNum } from '../_util/type'; +import PropTypes from '../_util/vue-types'; import warning from '../_util/warning'; -import Base, { BlockProps } from './Base'; +import Base, { baseProps, BlockProps } from './Base'; const TITLE_ELE_LIST = tupleNum(1, 2, 3, 4, 5); @@ -20,7 +22,7 @@ const Title: FunctionalComponent = (props, { slots, attrs }) => { const titleProps = { ...restProps, component, - attrs, + ...attrs, }; return {slots.default?.()}; @@ -28,5 +30,6 @@ const Title: FunctionalComponent = (props, { slots, attrs }) => { Title.displayName = 'ATypographyTitle'; Title.inheritAttrs = false; +Title.props = Omit({ ...baseProps(), level: PropTypes.number }, ['component', 'strong']); export default Title; diff --git a/components/typography/util.tsx b/components/typography/util.tsx index 531576144..823b95c41 100644 --- a/components/typography/util.tsx +++ b/components/typography/util.tsx @@ -1,4 +1,5 @@ import { createApp, CSSProperties, VNodeTypes } from 'vue'; +import toArray from '../vc-util/Children/toArray'; interface MeasureResult { finished: boolean; @@ -14,19 +15,7 @@ const ELEMENT_NODE = 1; const TEXT_NODE = 3; const COMMENT_NODE = 8; -export function toArray(children) { - const c = []; - children.forEach(child => { - if (child.text) { - c.push(child); - } else { - c.push(child); - } - }); - return c; -} - -let ellipsisContainer = null; +let ellipsisContainer: HTMLParagraphElement; const wrapperStyle: CSSProperties = { padding: 0, @@ -109,7 +98,7 @@ export default ( ellipsisContainer.style.webkitLineClamp = 'none'; // Render in the fake container - const contentList: VNodeTypes[] = mergeChildren(toArray(content)); + const contentList: VNodeTypes[] = mergeChildren(toArray(content as [])); const vm = createApp({ render() { return ( @@ -133,7 +122,7 @@ export default ( // Skip ellipsis if already match if (inRange()) { - vm.unmount(ellipsisContainer); + vm.unmount(); return { content, text: ellipsisContainer.innerHTML, ellipsis: false }; } @@ -145,7 +134,7 @@ export default ( ellipsisContainer.childNodes[0].childNodes[1].cloneNode(true).childNodes, ); - vm.unmount(ellipsisContainer); + vm.unmount(); // ========================= Find match ellipsis content ========================= const ellipsisChildren = []; @@ -200,9 +189,8 @@ export default ( if (inRange()) { return measureText(textNode, fullText, midLoc, endLoc, midLoc); - } else { - return measureText(textNode, fullText, startLoc, midLoc, lastSuccessLoc); } + return measureText(textNode, fullText, startLoc, midLoc, lastSuccessLoc); } function measureNode(childNode: ChildNode, index: number): MeasureResult { @@ -224,7 +212,8 @@ export default ( finished: true, vNode: null, }; - } else if (type === TEXT_NODE) { + } + if (type === TEXT_NODE) { const fullText = childNode.textContent || ''; const textNode = document.createTextNode(fullText); appendChildNode(textNode); diff --git a/components/vc-util/Children/toArray.ts b/components/vc-util/Children/toArray.ts new file mode 100644 index 000000000..af663dc30 --- /dev/null +++ b/components/vc-util/Children/toArray.ts @@ -0,0 +1,26 @@ +import { VNodeTypes } from '@vue/runtime-core'; +import { isFragment } from '../../_util/props-util'; + +export interface Option { + keepEmpty?: boolean; +} + +export default function toArray(children: any[], option: Option = {}): any[] { + let ret: VNodeTypes[] = []; + + children.forEach((child: any) => { + if ((child === undefined || child === null) && !option.keepEmpty) { + return; + } + debugger; + if (Array.isArray(child)) { + ret = ret.concat(toArray(child)); + } else if (isFragment(child) && child.props) { + ret = ret.concat(toArray(child.props.children, option)); + } else { + ret.push(child); + } + }); + + return ret; +}