mirror of
https://github.com/element-plus/element-plus.git
synced 2025-02-17 11:49:41 +08:00
feat(components): add el-text component (#11653)
* test(components): [text] el-text unit test * docs(components): [text] el-text website documentation * feat(components): [text] el-text implementation * fix(components): [text] prop 'as' rename 'tag' * docs(components): [text] rename slot default, optimize document * test(components): [text] render text & class change the execution order * fix(components): [text] use template and render function together
This commit is contained in:
parent
6077e64021
commit
4f78411bb8
@ -30,6 +30,10 @@
|
||||
"link": "/link",
|
||||
"text": "Link"
|
||||
},
|
||||
{
|
||||
"link": "/text",
|
||||
"text": "Text"
|
||||
},
|
||||
{
|
||||
"link": "/scrollbar",
|
||||
"text": "Scrollbar"
|
||||
|
65
docs/en-US/component/text.md
Normal file
65
docs/en-US/component/text.md
Normal file
@ -0,0 +1,65 @@
|
||||
---
|
||||
title: Text
|
||||
lang: en-US
|
||||
---
|
||||
|
||||
# Text
|
||||
|
||||
Used for text.
|
||||
|
||||
## Basic
|
||||
|
||||
:::demo Use the `type` attribute to define Text's type.
|
||||
|
||||
text/basic
|
||||
|
||||
:::
|
||||
|
||||
## Sizes
|
||||
|
||||
:::demo Use attribute `size` to set additional sizes with `large`, `default` or `small`.
|
||||
|
||||
text/sizes
|
||||
|
||||
:::
|
||||
|
||||
## Ellipsis
|
||||
|
||||
:::demo Pass the `truncated` prop to render an ellipsis when the text exceeds the width of the viewport or max-width set.
|
||||
|
||||
text/truncated
|
||||
|
||||
:::
|
||||
|
||||
## Override
|
||||
|
||||
:::demo Use attribute `tag` to override element
|
||||
|
||||
text/override
|
||||
|
||||
:::
|
||||
|
||||
## Mixed
|
||||
|
||||
:::demo Text mixed component
|
||||
|
||||
text/mixed
|
||||
|
||||
:::
|
||||
|
||||
## API
|
||||
|
||||
### Attributes
|
||||
|
||||
| Name | Description | Type | Default |
|
||||
| --------- | ------------------ | ------------------------------------------------------------------ | ------- |
|
||||
| type | text type | ^[enum]`'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'` | — |
|
||||
| size | text size | ^[enum]`'large' \| 'default' \| 'small'` | default |
|
||||
| truncated | render ellipsis | ^[boolean] | false |
|
||||
| tag | custom element tag | ^[string] | span |
|
||||
|
||||
### Slots
|
||||
|
||||
| Name | Description |
|
||||
| ------- | --------------- |
|
||||
| default | default content |
|
8
docs/examples/text/basic.vue
Normal file
8
docs/examples/text/basic.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<el-text class="mx-1">Default</el-text>
|
||||
<el-text class="mx-1" type="primary">Primary</el-text>
|
||||
<el-text class="mx-1" type="success">Success</el-text>
|
||||
<el-text class="mx-1" type="info">Info</el-text>
|
||||
<el-text class="mx-1" type="warning">Warning</el-text>
|
||||
<el-text class="mx-1" type="danger">Danger</el-text>
|
||||
</template>
|
26
docs/examples/text/mixed.vue
Normal file
26
docs/examples/text/mixed.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<el-space direction="vertical">
|
||||
<el-text>
|
||||
<el-icon>
|
||||
<ElementPlus />
|
||||
</el-icon>
|
||||
Element-Plus
|
||||
</el-text>
|
||||
<el-row>
|
||||
<el-text>Rate</el-text>
|
||||
<el-rate class="ml-1" />
|
||||
</el-row>
|
||||
<el-text>
|
||||
This is text mixed icon
|
||||
<el-icon>
|
||||
<Bell />
|
||||
</el-icon>
|
||||
and component
|
||||
<el-button>Button</el-button>
|
||||
</el-text>
|
||||
</el-space>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Bell, ElementPlus } from '@element-plus/icons-vue'
|
||||
</script>
|
19
docs/examples/text/override.vue
Normal file
19
docs/examples/text/override.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<el-space direction="vertical">
|
||||
<el-text>span</el-text>
|
||||
<el-text tag="p">This is a paragraph.</el-text>
|
||||
<el-text tag="b">Bold</el-text>
|
||||
<el-text tag="i">Italic</el-text>
|
||||
<el-text>
|
||||
This is
|
||||
<el-text tag="sub" size="small">subscript</el-text>
|
||||
</el-text>
|
||||
<el-text>
|
||||
This is
|
||||
<el-text tag="sup" size="small">superscript</el-text>
|
||||
</el-text>
|
||||
<el-text tag="ins">Inserted</el-text>
|
||||
<el-text tag="del">Deleted</el-text>
|
||||
<el-text tag="mark">Marked</el-text>
|
||||
</el-space>
|
||||
</template>
|
5
docs/examples/text/sizes.vue
Normal file
5
docs/examples/text/sizes.vue
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<el-text class="mx-1" size="large">Large</el-text>
|
||||
<el-text class="mx-1">Default</el-text>
|
||||
<el-text class="mx-1" size="small">Small</el-text>
|
||||
</template>
|
8
docs/examples/text/truncated.vue
Normal file
8
docs/examples/text/truncated.vue
Normal file
@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<el-text class="w-100px" truncated>Self element set width 100px</el-text>
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-text truncated>Squeezed by parent element</el-text>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
@ -58,6 +58,7 @@ export * from './table'
|
||||
export * from './table-v2'
|
||||
export * from './tabs'
|
||||
export * from './tag'
|
||||
export * from './text'
|
||||
export * from './time-picker'
|
||||
export * from './time-select'
|
||||
export * from './timeline'
|
||||
|
47
packages/components/text/__tests__/text.test.tsx
Normal file
47
packages/components/text/__tests__/text.test.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import Text from '../src/text.vue'
|
||||
|
||||
const AXIOM = 'Rem is the best girl'
|
||||
|
||||
describe('Text.vue', () => {
|
||||
test('render text & class', () => {
|
||||
const wrapper = mount(() => (
|
||||
<Text
|
||||
v-slots={{
|
||||
default: () => AXIOM,
|
||||
}}
|
||||
/>
|
||||
))
|
||||
const vm = wrapper.vm
|
||||
|
||||
expect(vm.$el.classList.contains('el-text')).toEqual(true)
|
||||
expect(wrapper.text()).toEqual(AXIOM)
|
||||
})
|
||||
|
||||
test('type', () => {
|
||||
const wrapper = mount(() => <Text type="success" />)
|
||||
const vm = wrapper.vm
|
||||
expect(vm.$el.classList.contains('el-text--success')).toEqual(true)
|
||||
})
|
||||
|
||||
test('size', () => {
|
||||
const wrapper = mount(() => <Text size="large" />)
|
||||
const vm = wrapper.vm
|
||||
expect(vm.$el.className.includes('el-text--large')).toEqual(true)
|
||||
expect(vm.$el.className.includes('el-text--default')).toEqual(false)
|
||||
expect(vm.$el.className.includes('el-text--small')).toEqual(false)
|
||||
})
|
||||
|
||||
test('truncated', () => {
|
||||
const wrapper = mount(() => <Text truncated />)
|
||||
const vm = wrapper.vm
|
||||
expect(vm.$el.className.includes('is-truncated')).toEqual(true)
|
||||
})
|
||||
|
||||
test('tag', () => {
|
||||
const wrapper = mount(() => <Text tag="del" />)
|
||||
const vm = wrapper.vm
|
||||
expect(vm.$el.tagName).toEqual('DEL')
|
||||
})
|
||||
})
|
8
packages/components/text/index.ts
Normal file
8
packages/components/text/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { withInstall } from '@element-plus/utils'
|
||||
|
||||
import Text from './src/text.vue'
|
||||
|
||||
export const ElText = withInstall(Text)
|
||||
export default ElText
|
||||
|
||||
export * from './src/text'
|
39
packages/components/text/src/text.ts
Normal file
39
packages/components/text/src/text.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { buildProps } from '@element-plus/utils'
|
||||
import { componentSizes } from '@element-plus/constants'
|
||||
import type Text from './text.vue'
|
||||
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
|
||||
export const textProps = buildProps({
|
||||
/**
|
||||
* @description text type
|
||||
*/
|
||||
type: {
|
||||
type: String,
|
||||
values: ['primary', 'success', 'info', 'warning', 'danger', ''],
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description text size
|
||||
*/
|
||||
size: {
|
||||
type: String,
|
||||
values: componentSizes,
|
||||
default: '',
|
||||
},
|
||||
/**
|
||||
* @description render ellipsis
|
||||
*/
|
||||
truncated: {
|
||||
type: Boolean,
|
||||
},
|
||||
/**
|
||||
* @description custom element tag
|
||||
*/
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'span',
|
||||
},
|
||||
} as const)
|
||||
export type TextProps = ExtractPropTypes<typeof textProps>
|
||||
export type TextInstance = InstanceType<typeof Text>
|
28
packages/components/text/src/text.vue
Normal file
28
packages/components/text/src/text.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<component :is="tag" :class="textKls">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { useFormSize } from '@element-plus/components/form'
|
||||
import { textProps } from './text'
|
||||
|
||||
defineOptions({
|
||||
name: 'ElText',
|
||||
})
|
||||
|
||||
const props = defineProps(textProps)
|
||||
|
||||
const textSize = useFormSize()
|
||||
const ns = useNamespace('text')
|
||||
|
||||
const textKls = computed(() => [
|
||||
ns.b(),
|
||||
ns.m(props.type),
|
||||
ns.m(textSize.value),
|
||||
ns.is('truncated', props.truncated),
|
||||
])
|
||||
</script>
|
2
packages/components/text/style/css.ts
Normal file
2
packages/components/text/style/css.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '@element-plus/components/base/style/css'
|
||||
import '@element-plus/theme-chalk/el-text.css'
|
2
packages/components/text/style/index.ts
Normal file
2
packages/components/text/style/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import '@element-plus/components/base/style'
|
||||
import '@element-plus/theme-chalk/src/text.scss'
|
@ -91,6 +91,7 @@ import { ElTable, ElTableColumn } from '@element-plus/components/table'
|
||||
import { ElAutoResizer, ElTableV2 } from '@element-plus/components/table-v2'
|
||||
import { ElTabPane, ElTabs } from '@element-plus/components/tabs'
|
||||
import { ElTag } from '@element-plus/components/tag'
|
||||
import { ElText } from '@element-plus/components/text'
|
||||
import { ElTimePicker } from '@element-plus/components/time-picker'
|
||||
import { ElTimeSelect } from '@element-plus/components/time-select'
|
||||
import { ElTimeline, ElTimelineItem } from '@element-plus/components/timeline'
|
||||
@ -191,6 +192,7 @@ export default [
|
||||
ElTabs,
|
||||
ElTabPane,
|
||||
ElTag,
|
||||
ElText,
|
||||
ElTimePicker,
|
||||
ElTimeSelect,
|
||||
ElTimeline,
|
||||
|
@ -923,6 +923,27 @@ $tag-icon-size: map.merge(
|
||||
$tag-icon-size
|
||||
);
|
||||
|
||||
// Text
|
||||
// css3 var in packages/theme-chalk/src/text.scss
|
||||
$text: () !default;
|
||||
$text: map.merge(
|
||||
(
|
||||
'font-size': getCssVar('font-size', 'base'),
|
||||
'color': getCssVar('text-color', 'regular'),
|
||||
),
|
||||
$text
|
||||
);
|
||||
|
||||
$text-font-size: () !default;
|
||||
$text-font-size: map.merge(
|
||||
(
|
||||
'large': getCssVar('font-size', 'medium'),
|
||||
'default': getCssVar('font-size', 'base'),
|
||||
'small': getCssVar('font-size', 'extra-small'),
|
||||
),
|
||||
$text-font-size
|
||||
);
|
||||
|
||||
// Tree
|
||||
// css3 var in packages/theme-chalk/src/tree.scss
|
||||
$tree: () !default;
|
||||
|
@ -85,6 +85,7 @@
|
||||
@use './table-v2.scss';
|
||||
@use './tabs.scss';
|
||||
@use './tag.scss';
|
||||
@use './text.scss';
|
||||
@use './time-picker.scss';
|
||||
@use './time-select.scss';
|
||||
@use './timeline-item.scss';
|
||||
|
45
packages/theme-chalk/src/text.scss
Normal file
45
packages/theme-chalk/src/text.scss
Normal file
@ -0,0 +1,45 @@
|
||||
@use 'sass:map';
|
||||
|
||||
@use 'mixins/mixins' as *;
|
||||
@use 'mixins/var' as *;
|
||||
@use 'common/var' as *;
|
||||
|
||||
@include b(text) {
|
||||
@include set-component-css-var('text', $text);
|
||||
}
|
||||
|
||||
@include b(text) {
|
||||
align-self: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: getCssVar('text', 'font-size');
|
||||
color: getCssVar('text', 'color');
|
||||
word-break: break-all;
|
||||
|
||||
@include when(truncated) {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@each $size in (large, default, small) {
|
||||
@include m($size) {
|
||||
@include set-css-var-value(
|
||||
('text', 'font-size'),
|
||||
map.get($text-font-size, $size)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@each $type in $types {
|
||||
&.#{bem('text', '', $type)} {
|
||||
@include css-var-from-global(('text', 'color'), ('color', $type));
|
||||
}
|
||||
}
|
||||
|
||||
&>.#{bem('icon')} {
|
||||
vertical-align: -2px;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user