feat: update typography
parent
2515077386
commit
2191656479
|
@ -0,0 +1,8 @@
|
||||||
|
import { computed, inject } from 'vue';
|
||||||
|
import { defaultConfigProvider } from '../../config-provider';
|
||||||
|
|
||||||
|
export default (name: string, props: Record<any, any>) => {
|
||||||
|
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||||
|
const prefixCls = computed(() => configProvider.getPrefixCls(name, props.prefixCls));
|
||||||
|
return { configProvider, prefixCls };
|
||||||
|
};
|
|
@ -11,29 +11,26 @@ import Typography, { TypographyProps } from './Typography';
|
||||||
import ResizeObserver from '../vc-resize-observer';
|
import ResizeObserver from '../vc-resize-observer';
|
||||||
import Tooltip from '../tooltip';
|
import Tooltip from '../tooltip';
|
||||||
import copy from '../_util/copy-to-clipboard';
|
import copy from '../_util/copy-to-clipboard';
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
|
||||||
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
|
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
|
||||||
import CopyOutlined from '@ant-design/icons-vue/CopyOutlined';
|
import CopyOutlined from '@ant-design/icons-vue/CopyOutlined';
|
||||||
import EditOutlined from '@ant-design/icons-vue/EditOutlined';
|
import EditOutlined from '@ant-design/icons-vue/EditOutlined';
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
inject,
|
|
||||||
VNodeTypes,
|
VNodeTypes,
|
||||||
Text,
|
|
||||||
VNode,
|
VNode,
|
||||||
reactive,
|
reactive,
|
||||||
ref,
|
ref,
|
||||||
onMounted,
|
onMounted,
|
||||||
onUpdated,
|
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
watch,
|
watch,
|
||||||
watchEffect,
|
watchEffect,
|
||||||
nextTick,
|
nextTick,
|
||||||
CSSProperties,
|
CSSProperties,
|
||||||
toRaw,
|
toRaw,
|
||||||
|
computed,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { filterEmpty } from '../_util/props-util';
|
|
||||||
import { AutoSizeType } from '../input/ResizableTextArea';
|
import { AutoSizeType } from '../input/ResizableTextArea';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
|
||||||
export type BaseType = 'secondary' | 'success' | 'warning' | 'danger';
|
export type BaseType = 'secondary' | 'success' | 'warning' | 'danger';
|
||||||
|
|
||||||
|
@ -63,7 +60,7 @@ interface EditConfig {
|
||||||
tooltip?: boolean | VNodeTypes;
|
tooltip?: boolean | VNodeTypes;
|
||||||
onStart?: () => void;
|
onStart?: () => void;
|
||||||
onChange?: (value: string) => void;
|
onChange?: (value: string) => void;
|
||||||
maxLength?: number;
|
maxlength?: number;
|
||||||
autoSize?: boolean | AutoSizeType;
|
autoSize?: boolean | AutoSizeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +71,7 @@ export interface EllipsisConfig {
|
||||||
symbol?: VNodeTypes;
|
symbol?: VNodeTypes;
|
||||||
onExpand?: EventHandlerNonNull;
|
onExpand?: EventHandlerNonNull;
|
||||||
onEllipsis?: (ellipsis: boolean) => void;
|
onEllipsis?: (ellipsis: boolean) => void;
|
||||||
tooltip?: VNodeTypes;
|
tooltip?: boolean | VNodeTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlockProps extends TypographyProps {
|
export interface BlockProps extends TypographyProps {
|
||||||
|
@ -91,6 +88,7 @@ export interface BlockProps extends TypographyProps {
|
||||||
delete?: boolean;
|
delete?: boolean;
|
||||||
strong?: boolean;
|
strong?: boolean;
|
||||||
keyboard?: boolean;
|
keyboard?: boolean;
|
||||||
|
content?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Locale {
|
interface Locale {
|
||||||
|
@ -110,7 +108,7 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
name: 'Base',
|
name: 'Base',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
setup(props, { slots, attrs }) {
|
setup(props, { slots, attrs }) {
|
||||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
const { prefixCls } = useConfigInject('typography', props);
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
edit: false,
|
edit: false,
|
||||||
|
@ -133,25 +131,20 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
|
|
||||||
const contentRef = ref();
|
const contentRef = ref();
|
||||||
const editIcon = ref();
|
const editIcon = ref();
|
||||||
|
const ellipsis = computed(
|
||||||
|
(): EllipsisConfig => {
|
||||||
|
const ellipsis = props.ellipsis;
|
||||||
|
if (!ellipsis) return {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
rows: 1,
|
||||||
|
expandable: false,
|
||||||
|
...(typeof ellipsis === 'object' ? ellipsis : null),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
state.prevProps = { ...props, children: getChildren() };
|
|
||||||
state.clientRendered = true;
|
state.clientRendered = true;
|
||||||
resizeOnNextFrame();
|
|
||||||
});
|
|
||||||
|
|
||||||
onUpdated(() => {
|
|
||||||
const ellipsis = getEllipsis();
|
|
||||||
const prevEllipsis = getEllipsis(state.prevProps);
|
|
||||||
const children = getChildren();
|
|
||||||
|
|
||||||
if (
|
|
||||||
JSON.stringify(children) !== JSON.stringify(toRaw(state.prevProps.children)) ||
|
|
||||||
ellipsis.rows !== prevEllipsis.rows
|
|
||||||
) {
|
|
||||||
resizeOnNextFrame();
|
|
||||||
}
|
|
||||||
state.prevProps = { ...props, children };
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
@ -160,25 +153,29 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.ellipsis,
|
[() => ellipsis.value.rows, () => props.content],
|
||||||
() => {
|
() => {
|
||||||
|
nextTick(() => {
|
||||||
resizeOnNextFrame();
|
resizeOnNextFrame();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
{ flush: 'post', deep: true, immediate: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const children = getChildren();
|
if (!('content' in props)) {
|
||||||
|
|
||||||
warning(
|
warning(
|
||||||
!props.editable || children.every(item => item.type === Text),
|
!props.editable,
|
||||||
'Typography',
|
'Typography',
|
||||||
'When `editable` is enabled, the `children` should use string.',
|
'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 getChildren() {
|
|
||||||
return filterEmpty(slots.default?.());
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function saveTypographyRef(node: VNode) {
|
function saveTypographyRef(node: VNode) {
|
||||||
contentRef.value = node;
|
contentRef.value = node;
|
||||||
|
@ -189,23 +186,14 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChildrenText(): string {
|
function getChildrenText(): string {
|
||||||
const children = getChildren();
|
return props.ellipsis || props.editable ? props.content : contentRef.value.text;
|
||||||
return children.length !== 0
|
|
||||||
? children
|
|
||||||
.filter(item => item.type === Text)
|
|
||||||
.map(item => item.children)
|
|
||||||
.reduce((cur, prev) => cur + prev, '')
|
|
||||||
: '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============== Expand ===============
|
// =============== Expand ===============
|
||||||
function onExpandClick(e: MouseEvent) {
|
function onExpandClick(e: MouseEvent) {
|
||||||
const { onExpand } = getEllipsis();
|
const { onExpand } = ellipsis.value;
|
||||||
state.expanded = true;
|
state.expanded = true;
|
||||||
|
onExpand?.(e);
|
||||||
if (onExpand) {
|
|
||||||
onExpand(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// ================ Edit ================
|
// ================ Edit ================
|
||||||
function onEditClick() {
|
function onEditClick() {
|
||||||
|
@ -213,10 +201,8 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEditChange(value: string) {
|
function onEditChange(value: string) {
|
||||||
const { onChange } = getEditable();
|
const { onChange } = editable.value;
|
||||||
if (onChange) {
|
onChange?.(value);
|
||||||
onChange(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
triggerEdit(false);
|
triggerEdit(false);
|
||||||
}
|
}
|
||||||
|
@ -226,7 +212,8 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}
|
}
|
||||||
|
|
||||||
// ================ Copy ================
|
// ================ Copy ================
|
||||||
function onCopyClick() {
|
function onCopyClick(e: MouseEvent) {
|
||||||
|
e.preventDefault();
|
||||||
const { copyable } = props;
|
const { copyable } = props;
|
||||||
|
|
||||||
const copyConfig = {
|
const copyConfig = {
|
||||||
|
@ -250,30 +237,18 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}, 3000);
|
}, 3000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const editable = computed(() => {
|
||||||
function getEditable($props?: BlockProps): EditConfig {
|
const editable = props.editable;
|
||||||
const editable = ($props || props).editable;
|
|
||||||
if (!editable) return { editing: state.edit };
|
if (!editable) return { editing: state.edit };
|
||||||
|
|
||||||
return {
|
return {
|
||||||
editing: state.edit,
|
editing: state.edit,
|
||||||
...(typeof editable === 'object' ? editable : null),
|
...(typeof editable === 'object' ? editable : null),
|
||||||
};
|
};
|
||||||
}
|
});
|
||||||
|
|
||||||
function getEllipsis($props?: BlockProps): EllipsisConfig {
|
|
||||||
const ellipsis = ($props || props).ellipsis;
|
|
||||||
if (!ellipsis) return {};
|
|
||||||
|
|
||||||
return {
|
|
||||||
rows: 1,
|
|
||||||
expandable: false,
|
|
||||||
...(typeof ellipsis === 'object' ? ellipsis : null),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function triggerEdit(edit: boolean) {
|
function triggerEdit(edit: boolean) {
|
||||||
const { onStart } = getEditable();
|
const { onStart } = editable.value;
|
||||||
if (edit && onStart) {
|
if (edit && onStart) {
|
||||||
onStart();
|
onStart();
|
||||||
}
|
}
|
||||||
|
@ -295,13 +270,13 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function canUseCSSEllipsis(): boolean {
|
const canUseCSSEllipsis = computed(() => {
|
||||||
const { rows, expandable, suffix } = getEllipsis();
|
const { rows, expandable, suffix, onEllipsis, tooltip } = ellipsis.value;
|
||||||
|
|
||||||
if (suffix) return false;
|
if (suffix || tooltip) return false;
|
||||||
|
|
||||||
// Can't use css ellipsis since we need to provide the place for button
|
// Can't use css ellipsis since we need to provide the place for button
|
||||||
if (props.editable || props.copyable || expandable || !state.clientRendered) {
|
if (props.editable || props.copyable || expandable || onEllipsis) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,40 +285,33 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}
|
}
|
||||||
|
|
||||||
return isLineClampSupport;
|
return isLineClampSupport;
|
||||||
}
|
});
|
||||||
|
|
||||||
function syncEllipsis() {
|
const syncEllipsis = () => {
|
||||||
const { ellipsisText, isEllipsis } = state;
|
const { ellipsisText, isEllipsis } = state;
|
||||||
const children = getChildren();
|
const { rows, suffix, onEllipsis } = ellipsis.value;
|
||||||
const { rows, suffix, onEllipsis } = getEllipsis();
|
|
||||||
if (!rows || rows < 0 || !contentRef.value?.$el || state.expanded) return;
|
if (!rows || rows < 0 || !contentRef.value?.$el || state.expanded) return;
|
||||||
|
|
||||||
// Do not measure if css already support ellipsis
|
// Do not measure if css already support ellipsis
|
||||||
if (canUseCSSEllipsis()) return;
|
if (canUseCSSEllipsis.value) return;
|
||||||
|
|
||||||
warning(
|
const { content, text, ellipsis: ell } = measure(
|
||||||
children.every(item => item.type === Text),
|
|
||||||
'Typography',
|
|
||||||
'`ellipsis` should use string as children only.',
|
|
||||||
);
|
|
||||||
|
|
||||||
const { content, text, ellipsis } = measure(
|
|
||||||
contentRef.value?.$el,
|
contentRef.value?.$el,
|
||||||
{ rows, suffix },
|
{ rows, suffix },
|
||||||
children,
|
props.content,
|
||||||
renderOperations(true),
|
renderOperations(true),
|
||||||
ELLIPSIS_STR,
|
ELLIPSIS_STR,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (ellipsisText !== text || state.isEllipsis !== ellipsis) {
|
if (ellipsisText !== text || state.isEllipsis !== ell) {
|
||||||
state.ellipsisText = text;
|
state.ellipsisText = text;
|
||||||
state.ellipsisContent = content;
|
state.ellipsisContent = content;
|
||||||
state.isEllipsis = ellipsis;
|
state.isEllipsis = ell;
|
||||||
if (isEllipsis !== ellipsis && onEllipsis) {
|
if (isEllipsis !== ell && onEllipsis) {
|
||||||
onEllipsis(ellipsis);
|
onEllipsis(ell);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function wrapperDecorations(
|
function wrapperDecorations(
|
||||||
{ mark, code, underline, delete: del, strong, keyboard }: BlockProps,
|
{ mark, code, underline, delete: del, strong, keyboard }: BlockProps,
|
||||||
|
@ -368,8 +336,7 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderExpand(forceRender?: boolean) {
|
function renderExpand(forceRender?: boolean) {
|
||||||
const { expandable, symbol } = getEllipsis();
|
const { expandable, symbol } = ellipsis.value;
|
||||||
const prefixCls = getPrefixCls();
|
|
||||||
|
|
||||||
if (!expandable) return null;
|
if (!expandable) return null;
|
||||||
|
|
||||||
|
@ -386,7 +353,7 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
key="expand"
|
key="expand"
|
||||||
class={`${prefixCls}-expand`}
|
class={`${prefixCls.value}-expand`}
|
||||||
onClick={onExpandClick}
|
onClick={onExpandClick}
|
||||||
aria-label={state.expandStr}
|
aria-label={state.expandStr}
|
||||||
>
|
>
|
||||||
|
@ -398,7 +365,6 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
function renderEdit() {
|
function renderEdit() {
|
||||||
if (!props.editable) return;
|
if (!props.editable) return;
|
||||||
|
|
||||||
const prefixCls = getPrefixCls();
|
|
||||||
const { icon, tooltip } = props.editable as EditConfig;
|
const { icon, tooltip } = props.editable as EditConfig;
|
||||||
|
|
||||||
const title = tooltip || state.editStr;
|
const title = tooltip || state.editStr;
|
||||||
|
@ -408,7 +374,7 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
<Tooltip key="edit" title={tooltip === false ? '' : title}>
|
<Tooltip key="edit" title={tooltip === false ? '' : title}>
|
||||||
<TransButton
|
<TransButton
|
||||||
ref={saveEditIconRef}
|
ref={saveEditIconRef}
|
||||||
class={`${prefixCls}-edit`}
|
class={`${prefixCls.value}-edit`}
|
||||||
onClick={onEditClick}
|
onClick={onEditClick}
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
>
|
>
|
||||||
|
@ -421,8 +387,6 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
function renderCopy() {
|
function renderCopy() {
|
||||||
if (!props.copyable) return;
|
if (!props.copyable) return;
|
||||||
|
|
||||||
const prefixCls = getPrefixCls();
|
|
||||||
|
|
||||||
const { tooltips } = props.copyable as CopyConfig;
|
const { tooltips } = props.copyable as CopyConfig;
|
||||||
let tooltipNodes = toArray(tooltips) as VNodeTypes[];
|
let tooltipNodes = toArray(tooltips) as VNodeTypes[];
|
||||||
if (tooltipNodes.length === 0) {
|
if (tooltipNodes.length === 0) {
|
||||||
|
@ -435,7 +399,10 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
return (
|
return (
|
||||||
<Tooltip key="copy" title={tooltips === false ? '' : title}>
|
<Tooltip key="copy" title={tooltips === false ? '' : title}>
|
||||||
<TransButton
|
<TransButton
|
||||||
class={[`${prefixCls}-copy`, { [`${prefixCls}-copy-success`]: state.copied }]}
|
class={[
|
||||||
|
`${prefixCls.value}-copy`,
|
||||||
|
{ [`${prefixCls.value}-copy-success`]: state.copied },
|
||||||
|
]}
|
||||||
onClick={onCopyClick}
|
onClick={onCopyClick}
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
>
|
>
|
||||||
|
@ -446,19 +413,16 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderEditInput() {
|
function renderEditInput() {
|
||||||
const prefixCls = getPrefixCls();
|
|
||||||
const { class: className, style } = attrs;
|
const { class: className, style } = attrs;
|
||||||
const { maxLength, autoSize } = getEditable();
|
const { maxlength, autoSize } = editable.value;
|
||||||
|
|
||||||
const value = getChildrenText();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Editable
|
<Editable
|
||||||
class={className}
|
class={className}
|
||||||
style={style}
|
style={style}
|
||||||
prefixCls={prefixCls}
|
prefixCls={prefixCls.value}
|
||||||
value={value}
|
value={props.content}
|
||||||
maxlength={maxLength}
|
maxlength={maxlength}
|
||||||
autoSize={autoSize}
|
autoSize={autoSize}
|
||||||
onSave={onEditChange}
|
onSave={onEditChange}
|
||||||
onCancel={onEditCancel}
|
onCancel={onEditCancel}
|
||||||
|
@ -470,14 +434,14 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
return [renderExpand(forceRenderExpanded), renderEdit(), renderCopy()].filter(node => node);
|
return [renderExpand(forceRenderExpanded), renderEdit(), renderCopy()].filter(node => node);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrefixCls() {
|
|
||||||
const getPrefixCls = configProvider.getPrefixCls;
|
|
||||||
return getPrefixCls('typography', props.prefixCls);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
const { editing } = getEditable();
|
const { editing } = editable.value;
|
||||||
const children = filterEmpty(slots.default?.());
|
const children =
|
||||||
|
props.ellipsis || props.editable
|
||||||
|
? props.content
|
||||||
|
: slots.default
|
||||||
|
? slots.default()
|
||||||
|
: props.content;
|
||||||
|
|
||||||
if (editing) {
|
if (editing) {
|
||||||
return renderEditInput();
|
return renderEditInput();
|
||||||
|
@ -486,9 +450,11 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
<LocaleReceiver
|
<LocaleReceiver
|
||||||
componentName="Text"
|
componentName="Text"
|
||||||
children={(locale: Locale) => {
|
children={(locale: Locale) => {
|
||||||
const { type, disabled, title, ...restProps } = props;
|
const { type, disabled, title, content, class: className, style, ...restProps } = {
|
||||||
const { class: className, style } = attrs;
|
...props,
|
||||||
const { rows, suffix } = getEllipsis();
|
...attrs,
|
||||||
|
};
|
||||||
|
const { rows, suffix, tooltip } = ellipsis.value;
|
||||||
|
|
||||||
const { edit, copy: copyStr, copied, expand } = locale;
|
const { edit, copy: copyStr, copied, expand } = locale;
|
||||||
|
|
||||||
|
@ -510,7 +476,7 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
'keyboard',
|
'keyboard',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const cssEllipsis = canUseCSSEllipsis();
|
const cssEllipsis = canUseCSSEllipsis.value;
|
||||||
const cssTextOverflow = rows === 1 && cssEllipsis;
|
const cssTextOverflow = rows === 1 && cssEllipsis;
|
||||||
const cssLineClamp = rows && rows > 1 && cssEllipsis;
|
const cssLineClamp = rows && rows > 1 && cssEllipsis;
|
||||||
|
|
||||||
|
@ -520,10 +486,8 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
// Only use js ellipsis when css ellipsis not support
|
// Only use js ellipsis when css ellipsis not support
|
||||||
if (rows && state.isEllipsis && !state.expanded && !cssEllipsis) {
|
if (rows && state.isEllipsis && !state.expanded && !cssEllipsis) {
|
||||||
ariaLabel = title;
|
ariaLabel = title;
|
||||||
if (!title && children.every(item => item.type === Text)) {
|
if (!title) {
|
||||||
ariaLabel = children
|
ariaLabel = content;
|
||||||
.map(item => item.children)
|
|
||||||
.reduce((cur, prev) => cur + prev, '');
|
|
||||||
}
|
}
|
||||||
// We move full content to outer element to avoid repeat read the content by accessibility
|
// We move full content to outer element to avoid repeat read the content by accessibility
|
||||||
textNode = (
|
textNode = (
|
||||||
|
@ -533,6 +497,14 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
{suffix}
|
{suffix}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
// If provided tooltip, we need wrap with span to let Tooltip inject events
|
||||||
|
if (tooltip) {
|
||||||
|
textNode = (
|
||||||
|
<Tooltip title={tooltip === true ? children : tooltip}>
|
||||||
|
<span>{textNode}</span>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
textNode = (
|
textNode = (
|
||||||
<>
|
<>
|
||||||
|
@ -544,23 +516,21 @@ const Base = defineComponent<InternalBlockProps>({
|
||||||
|
|
||||||
textNode = wrapperDecorations(props, textNode);
|
textNode = wrapperDecorations(props, textNode);
|
||||||
|
|
||||||
const prefixCls = getPrefixCls();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResizeObserver onResize={resizeOnNextFrame} disabled={!rows}>
|
<ResizeObserver onResize={resizeOnNextFrame} disabled={!rows}>
|
||||||
<Typography
|
<Typography
|
||||||
ref={saveTypographyRef}
|
ref={saveTypographyRef}
|
||||||
class={[
|
class={[
|
||||||
{ [`${prefixCls}-${type}`]: type },
|
{ [`${prefixCls.value}-${type}`]: type },
|
||||||
{ [`${prefixCls}-disabled`]: disabled },
|
{ [`${prefixCls.value}-disabled`]: disabled },
|
||||||
{ [`${prefixCls}-ellipsis`]: rows },
|
{ [`${prefixCls.value}-ellipsis`]: rows },
|
||||||
{ [`${prefixCls}-ellipsis-single-line`]: cssTextOverflow },
|
{ [`${prefixCls.value}-ellipsis-single-line`]: cssTextOverflow },
|
||||||
{ [`${prefixCls}-ellipsis-multiple-line`]: cssLineClamp },
|
{ [`${prefixCls.value}-ellipsis-multiple-line`]: cssLineClamp },
|
||||||
className,
|
className,
|
||||||
]}
|
]}
|
||||||
style={{
|
style={{
|
||||||
...(style as CSSProperties),
|
...(style as CSSProperties),
|
||||||
WebkitLineClamp: cssLineClamp ? rows : null,
|
WebkitLineClamp: cssLineClamp ? rows : undefined,
|
||||||
}}
|
}}
|
||||||
aria-label={ariaLabel}
|
aria-label={ariaLabel}
|
||||||
{...textProps}
|
{...textProps}
|
||||||
|
@ -582,7 +552,7 @@ export const baseProps = () => ({
|
||||||
copyable: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]),
|
copyable: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]),
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
component: PropTypes.string,
|
component: PropTypes.string,
|
||||||
type: PropTypes.oneOf(['secondary', 'danger', 'warning']),
|
type: PropTypes.oneOf(['secondary', 'success', 'danger', 'warning']),
|
||||||
disabled: PropTypes.looseBool,
|
disabled: PropTypes.looseBool,
|
||||||
ellipsis: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]),
|
ellipsis: PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object]),
|
||||||
code: PropTypes.looseBool,
|
code: PropTypes.looseBool,
|
||||||
|
@ -591,6 +561,7 @@ export const baseProps = () => ({
|
||||||
delete: PropTypes.looseBool,
|
delete: PropTypes.looseBool,
|
||||||
strong: PropTypes.looseBool,
|
strong: PropTypes.looseBool,
|
||||||
keyboard: PropTypes.looseBool,
|
keyboard: PropTypes.looseBool,
|
||||||
|
content: PropTypes.string,
|
||||||
});
|
});
|
||||||
|
|
||||||
Base.props = baseProps();
|
Base.props = baseProps();
|
||||||
|
|
|
@ -25,10 +25,10 @@ const Link: FunctionalComponent<LinkProps> = (props, { slots, attrs }) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
delete mergedProps.navigate;
|
delete mergedProps.navigate;
|
||||||
|
|
||||||
return <Base {...mergedProps}>{slots.default?.()}</Base>;
|
return <Base {...mergedProps} v-slots={slots}></Base>;
|
||||||
};
|
};
|
||||||
|
|
||||||
Link.displayName = 'ATypographyText';
|
Link.displayName = 'ATypographyLink';
|
||||||
Link.inheritAttrs = false;
|
Link.inheritAttrs = false;
|
||||||
Link.props = Omit({ ...baseProps(), ellipsis: PropTypes.looseBool }, ['component']);
|
Link.props = Omit({ ...baseProps(), ellipsis: PropTypes.looseBool }, ['component']);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ const Paragraph: FunctionalComponent<BlockProps> = (props, { slots, attrs }) =>
|
||||||
...attrs,
|
...attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Base {...paragraphProps}>{slots.default?.()}</Base>;
|
return <Base {...paragraphProps} v-slots={slots}></Base>;
|
||||||
};
|
};
|
||||||
|
|
||||||
Paragraph.displayName = 'ATypographyParagraph';
|
Paragraph.displayName = 'ATypographyParagraph';
|
||||||
|
|
|
@ -27,7 +27,7 @@ const Text: FunctionalComponent<TextProps> = (props, { slots, attrs }) => {
|
||||||
...attrs,
|
...attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Base {...textProps}>{slots.default?.()}</Base>;
|
return <Base {...textProps} v-slots={slots}></Base>;
|
||||||
};
|
};
|
||||||
|
|
||||||
Text.displayName = 'ATypographyText';
|
Text.displayName = 'ATypographyText';
|
||||||
|
|
|
@ -25,7 +25,7 @@ const Title: FunctionalComponent<TitleProps> = (props, { slots, attrs }) => {
|
||||||
...attrs,
|
...attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Base {...titleProps}>{slots.default?.()}</Base>;
|
return <Base {...titleProps} v-slots={slots}></Base>;
|
||||||
};
|
};
|
||||||
|
|
||||||
Title.displayName = 'ATypographyTitle';
|
Title.displayName = 'ATypographyTitle';
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { defaultConfigProvider } from '../config-provider';
|
|
||||||
import Text from './Text';
|
import Text from './Text';
|
||||||
import Title from './Title';
|
import Title from './Title';
|
||||||
import Paragraph from './Paragraph';
|
import Paragraph from './Paragraph';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { defineComponent, HTMLAttributes, inject, App, Plugin } from 'vue';
|
import { defineComponent, HTMLAttributes, App, Plugin, computed } from 'vue';
|
||||||
|
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||||
|
import Link from './Link';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
|
||||||
export interface TypographyProps extends HTMLAttributes {
|
export interface TypographyProps extends HTMLAttributes {
|
||||||
prefixCls?: string;
|
prefixCls?: string;
|
||||||
|
@ -18,14 +20,22 @@ const Typography = defineComponent<InternalTypographyProps>({
|
||||||
Text: Text,
|
Text: Text,
|
||||||
Title: Title,
|
Title: Title,
|
||||||
Paragraph: Paragraph,
|
Paragraph: Paragraph,
|
||||||
setup(props, { slots }) {
|
Link: Link,
|
||||||
const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
|
inheritAttrs: false,
|
||||||
|
setup(props, { slots, attrs }) {
|
||||||
|
const { prefixCls } = useConfigInject('typography', props);
|
||||||
return () => {
|
return () => {
|
||||||
const { prefixCls: customizePrefixCls, component: Component = 'article' as any } = props;
|
const {
|
||||||
const prefixCls = getPrefixCls('typography', customizePrefixCls);
|
prefixCls: _prefixCls,
|
||||||
|
class: _className,
|
||||||
return <Component class={prefixCls}>{slots.default?.()}</Component>;
|
component: Component = 'article' as any,
|
||||||
|
...restProps
|
||||||
|
} = { ...props, ...attrs };
|
||||||
|
return (
|
||||||
|
<Component class={classNames(prefixCls.value, attrs.class)} {...restProps}>
|
||||||
|
{slots.default?.()}
|
||||||
|
</Component>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -40,6 +50,7 @@ Typography.install = function(app: App) {
|
||||||
app.component(Typography.Text.displayName, Text);
|
app.component(Typography.Text.displayName, Text);
|
||||||
app.component(Typography.Title.displayName, Title);
|
app.component(Typography.Title.displayName, Title);
|
||||||
app.component(Typography.Paragraph.displayName, Paragraph);
|
app.component(Typography.Paragraph.displayName, Paragraph);
|
||||||
|
app.component(Typography.Link.displayName, Link);
|
||||||
return app;
|
return app;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,4 +59,5 @@ export default Typography as typeof Typography &
|
||||||
readonly Text: typeof Text;
|
readonly Text: typeof Text;
|
||||||
readonly Title: typeof Title;
|
readonly Title: typeof Title;
|
||||||
readonly Paragraph: typeof Paragraph;
|
readonly Paragraph: typeof Paragraph;
|
||||||
|
readonly Link: typeof Link;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
|
|
||||||
&&-danger {
|
&&-danger {
|
||||||
color: @error-color;
|
color: @error-color;
|
||||||
|
a&:active,
|
||||||
|
a&:focus,
|
||||||
|
a&:hover {
|
||||||
|
color: ~`colorPalette('@{error-color}', 5) `;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&&-disabled {
|
&&-disabled {
|
||||||
|
@ -60,7 +65,8 @@
|
||||||
h1&,
|
h1&,
|
||||||
h2&,
|
h2&,
|
||||||
h3&,
|
h3&,
|
||||||
h4& h5& {
|
h4&,
|
||||||
|
h5& {
|
||||||
.@{typography-prefix-cls} + & {
|
.@{typography-prefix-cls} + & {
|
||||||
margin-top: @typography-title-margin-top;
|
margin-top: @typography-title-margin-top;
|
||||||
}
|
}
|
||||||
|
@ -92,25 +98,35 @@
|
||||||
a&,
|
a&,
|
||||||
a {
|
a {
|
||||||
.operation-unit();
|
.operation-unit();
|
||||||
|
text-decoration: @link-decoration;
|
||||||
|
|
||||||
&:active,
|
&:active,
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: @link-hover-decoration;
|
text-decoration: @link-hover-decoration;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[disabled] {
|
&[disabled],
|
||||||
|
&.@{typography-prefix-cls}-disabled {
|
||||||
color: @disabled-color;
|
color: @disabled-color;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:hover {
|
||||||
|
color: @disabled-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
margin: 0 0.2em;
|
margin: 0 0.2em;
|
||||||
padding: 0.2em 0.4em 0.1em;
|
padding: 0.2em 0.4em 0.1em;
|
||||||
font-size: 85%;
|
font-size: 85%;
|
||||||
background: rgba(0, 0, 0, 0.06);
|
background: rgba(150, 150, 150, 0.1);
|
||||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
border: 1px solid rgba(100, 100, 100, 0.2);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,11 +194,6 @@
|
||||||
bottom: 8px;
|
bottom: 8px;
|
||||||
color: @text-color-secondary;
|
color: @text-color-secondary;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
.@{typography-prefix-cls}-rtl & {
|
|
||||||
right: auto;
|
|
||||||
left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix Editable Textarea flash in Firefox
|
// Fix Editable Textarea flash in Firefox
|
||||||
|
@ -215,6 +226,38 @@
|
||||||
list-style-type: decimal;
|
list-style-type: decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pre & block
|
||||||
|
pre,
|
||||||
|
blockquote {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 0.4em 0.6em;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background: rgba(150, 150, 150, 0.1);
|
||||||
|
border: 1px solid rgba(100, 100, 100, 0.2);
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
// Compatible for marked
|
||||||
|
code {
|
||||||
|
display: inline;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: inherit;
|
||||||
|
font-family: inherit;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
padding: 0 0 0 0.6em;
|
||||||
|
border-left: 4px solid rgba(100, 100, 100, 0.2);
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
// ============ Ellipsis ============
|
// ============ Ellipsis ============
|
||||||
&-ellipsis-single-line {
|
&-ellipsis-single-line {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -230,9 +273,11 @@
|
||||||
|
|
||||||
&-ellipsis-multiple-line {
|
&-ellipsis-multiple-line {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
-webkit-line-clamp: 3;
|
-webkit-line-clamp: 3;
|
||||||
/*! autoprefixer: ignore next */
|
/*! autoprefixer: ignore next */
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@import './rtl';
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
@import '../../style/themes/index';
|
||||||
|
@import '../../style/mixins/index';
|
||||||
|
|
||||||
|
@typography-prefix-cls: ~'@{ant-prefix}-typography';
|
||||||
|
|
||||||
|
.@{typography-prefix-cls} {
|
||||||
|
&-rtl {
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operation
|
||||||
|
&-expand,
|
||||||
|
&-edit,
|
||||||
|
&-copy {
|
||||||
|
.@{typography-prefix-cls}-rtl & {
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-expand {
|
||||||
|
.@{typography-prefix-cls}-rtl & {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Text input area
|
||||||
|
&-edit-content {
|
||||||
|
div& {
|
||||||
|
&.@{typography-prefix-cls}-rtl {
|
||||||
|
right: -@input-padding-horizontal - 1px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-confirm {
|
||||||
|
.@{typography-prefix-cls}-rtl & {
|
||||||
|
right: auto;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// list
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
li {
|
||||||
|
.@{typography-prefix-cls}-rtl& {
|
||||||
|
margin: 0 20px 0 0;
|
||||||
|
padding: 0 4px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import demo from '../v2-doc/src/docs/affix/demo/basic.vue';
|
import demo from '../v2-doc/src/docs/typography/demo/text.vue';
|
||||||
// import Affix from '../components/affix';
|
// import Affix from '../components/affix';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
|
2
v2-doc
2
v2-doc
|
@ -1 +1 @@
|
||||||
Subproject commit 0468ad3010f71ad6b267c66c4f5e28c89c19d83e
|
Subproject commit a295627e3b35302ee9da1215fb102a42210e3ba3
|
Loading…
Reference in New Issue