diff --git a/packages/components/button/README.md b/packages/components/button/README.md
index 9066b9e57..2dd324a17 100644
--- a/packages/components/button/README.md
+++ b/packages/components/button/README.md
@@ -5,7 +5,7 @@ spline: base
isComponent: true
---
-


+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/components/dropdown-menu/README.md b/packages/components/dropdown-menu/README.md
index 7b7db3d69..0d15aaab7 100644
--- a/packages/components/dropdown-menu/README.md
+++ b/packages/components/dropdown-menu/README.md
@@ -13,7 +13,7 @@ isComponent: true
该组件于 0.8.0 版本上线,请留意版本。
-


+


## 引入
### 引入组件
diff --git a/packages/components/icon/README.md b/packages/components/icon/README.md
index abcf3e33f..0d08390de 100644
--- a/packages/components/icon/README.md
+++ b/packages/components/icon/README.md
@@ -12,9 +12,9 @@ isComponent: true
打开 TDesign 图标独立站点 查看全部支持的图标。
-


+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/components/paragraph/README.en-US.md b/packages/components/paragraph/README.en-US.md
new file mode 100644
index 000000000..623d3da44
--- /dev/null
+++ b/packages/components/paragraph/README.en-US.md
@@ -0,0 +1,62 @@
+:: BASE_DOC ::
+
+## API
+
+
+### Paragraph Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+style | Object | - | CSS(Cascading Style Sheets) | N
+custom-style | Object | - | CSS(Cascading Style Sheets),used to set style on virtual component | N
+content | String | - | content of paragraph | N
+ellipsis | Boolean / Object | false | add ellipsis style。Typescript: `boolean \| TypographyEllipsis `,[Text API Documents](./text?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/paragraph/type.ts) | N
+
+### Paragraph Slots
+
+name | Description
+-- | --
+content | content of paragraph
+
+
+### Text Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+style | Object | - | CSS(Cascading Style Sheets) | N
+custom-style | Object | - | CSS(Cascading Style Sheets),used to set style on virtual component | N
+code | Boolean | false | add code style | N
+content | String | - | content of text | N
+copyable | Boolean / Object | false | Whether copyable. When value is null, the copyable slot is enabled for custom copy icon. Typescript: `boolean \| TypographyCopyable \| null` `interface TypographyCopyable { text?: string }`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/text/type.ts) | N
+delete | Boolean | false | add delete line style | N
+disabled | Boolean | false | add disabled style | N
+ellipsis | Boolean / Object | false | add ellipsis style。Typescript: `boolean \| TypographyEllipsis ` `interface TypographyEllipsis { collapsible?: boolean; expandable?: boolean; row?: number;}`。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/text/type.ts) | N
+italic | Boolean | false | add italic style | N
+keyboard | Boolean | false | add keyboard style | N
+mark | String / Boolean | false | add mark style | N
+strong | Boolean | false | add bold style | N
+theme | String | - | theme of text。options: primary/secondary/success/warning/error | N
+underline | Boolean | false | add underline style | N
+
+### Text Slots
+
+name | Description
+-- | --
+content | content of text
+
+
+### Title Props
+
+name | type | default | description | required
+-- | -- | -- | -- | --
+style | Object | - | CSS(Cascading Style Sheets) | N
+custom-style | Object | - | CSS(Cascading Style Sheets),used to set style on virtual component | N
+content | String | - | content of title | N
+ellipsis | Boolean / Object | false | add ellipsis style。Typescript: `boolean \| TypographyEllipsis `,[Text API Documents](./text?tab=api)。[see more ts definition](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/title/type.ts) | N
+level | String | h1 | level of title。options: h1/h2/h3/h4/h5/h6 | N
+
+### Title Slots
+
+name | Description
+-- | --
+content | content of title
diff --git a/packages/components/paragraph/README.md b/packages/components/paragraph/README.md
new file mode 100644
index 000000000..f7b3b10c6
--- /dev/null
+++ b/packages/components/paragraph/README.md
@@ -0,0 +1,117 @@
+---
+title: Typography 排版
+description: 排版用于文本基础编排和样式,使用排版组件,可以快速完成页面中的文本内容制作,同时配合其他组件完成深色与浅色模式切换等风格统一的需求。
+isComponent: true
+spline: base
+---
+
+
+
+
+ 该组件于 1.15.0 版本上线,请留意版本。
+
+
+


+## 引入
+
+全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
+
+```json
+"usingComponents": {
+ "t-paragraph": "tdesign-miniprogram/paragraph/paragraph",
+ "t-text": "tdesign-miniprogram/text/text",
+ "t-title": "tdesign-miniprogram/title/title"
+}
+```
+
+## 代码演示
+
+ 在开发者工具中预览效果
+
+
+Tips: 请确保开发者工具为打开状态。导入开发者工具后,依次执行:npm i > 构建npm包 > 勾选 "将JS编译成ES5"
+
+
+### 基础文本
+
+{{ base }}
+
+### 组合用法
+
+{{ combination }}
+
+### 主题样式
+
+{{ theme }}
+
+### 可复制
+
+{{ copyable }}
+
+### 文本省略
+
+{{ ellipsis }}
+
+
+## API
+
+
+### Paragraph Props
+
+名称 | 类型 | 默认值 | 描述 | 必传
+-- | -- | -- | -- | --
+style | Object | - | 样式 | N
+custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
+content | String | - | 段落内容 | N
+ellipsis | Boolean / Object | false | 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式。TS 类型:`boolean \| TypographyEllipsis `,[Text API Documents](./text?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/paragraph/type.ts) | N
+
+### Paragraph Slots
+
+名称 | 描述
+-- | --
+content | 自定义 `content` 显示内容
+
+
+### Text Props
+
+名称 | 类型 | 默认值 | 描述 | 必传
+-- | -- | -- | -- | --
+style | Object | - | 样式 | N
+custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
+code | Boolean | false | 是否添加代码样式 | N
+content | String | - | 文本内容 | N
+copyable | Boolean / Object | false | 是否可复制,值为 null 时表示使用 copyable 插槽自定义复制图标。TS 类型:`boolean \| TypographyCopyable \| null` `interface TypographyCopyable { text?: string }`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/text/type.ts) | N
+delete | Boolean | false | 是否添加删除线样式 | N
+disabled | Boolean | false | 是否添加不可用样式 | N
+ellipsis | Boolean / Object | false | 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式。TS 类型:`boolean \| TypographyEllipsis ` `interface TypographyEllipsis { collapsible?: boolean; expandable?: boolean; row?: number;}`。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/text/type.ts) | N
+italic | Boolean | false | 文本是否为斜体 | N
+keyboard | Boolean | false | 是否添加键盘样式 | N
+mark | String / Boolean | false | 是否添加标记样式,默认为黄色,可通过配置颜色修改标记样式,如#0052D9 | N
+strong | Boolean | false | 文本是否加粗 | N
+theme | String | - | 主题。可选项:primary/secondary/success/warning/error | N
+underline | Boolean | false | 是否添加下划线样式 | N
+
+### Text Slots
+
+名称 | 描述
+-- | --
+content | 自定义 `content` 显示内容
+
+
+### Title Props
+
+名称 | 类型 | 默认值 | 描述 | 必传
+-- | -- | -- | -- | --
+style | Object | - | 样式 | N
+custom-style | Object | - | 样式,一般用于开启虚拟化组件节点场景 | N
+content | String | - | 段落内容 | N
+ellipsis | Boolean / Object | false | 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式。TS 类型:`boolean \| TypographyEllipsis `,[Text API Documents](./text?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-miniprogram/blob/develop/packages/components/title/type.ts) | N
+level | String | h1 | 标题等级。可选项:h1/h2/h3/h4/h5/h6 | N
+
+### Title Slots
+
+名称 | 描述
+-- | --
+content | 自定义 `content` 显示内容
diff --git a/packages/components/paragraph/__test__/__snapshots__/demo.test.js.snap b/packages/components/paragraph/__test__/__snapshots__/demo.test.js.snap
new file mode 100644
index 000000000..7196a3d88
--- /dev/null
+++ b/packages/components/paragraph/__test__/__snapshots__/demo.test.js.snap
@@ -0,0 +1,237 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Paragraph Paragraph base demo works fine 1`] = `
+
+
+
+
+
+`;
+
+exports[`Paragraph Paragraph combination demo works fine 1`] = `
+
+
+
+
+
+
+
+ TDesign features a unified design values, consistent design language, and visual style, helping users form
+ continuous and coherent perceptions of the experience.
+
+
+
+ Based on this, TDesign offers out-typography-of-the-box UI component libraries, design guidelines, and design
+ assets, elegantly and efficiently freeing design and development from repetitive tasks. Simultaneously, it
+ facilitates easy extension on top of TDesign, enabling a better alignment with business requirements.
+
+
+
+ Comprehensive
+
+
+
+ TDesign Support
+
+
+ Vue 2
+
+ ,
+
+ Vue 3
+
+ ,
+
+
+ React
+
+
+ components for Desktop Application and
+
+
+ Vue 3
+
+ ,
+
+
+ Wechat MiniProgram
+
+
+ components for Mobile Application.
+
+
+
+
+ • Features
+
+
+ • Comprehensive
+
+
+ • Consistency
+
+
+ • Usability
+
+
+ • Join TDesign
+
+
+
+
+ 1. Features
+
+
+ 2. Comprehensive
+
+
+ 1. Consistency
+
+
+ 2. Usability
+
+
+ 3. Join TDesign
+
+
+
+
+`;
+
+exports[`Paragraph Paragraph copyable demo works fine 1`] = `
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Paragraph Paragraph ellipsis demo works fine 1`] = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Paragraph Paragraph theme demo works fine 1`] = `
+
+
+
+
+
+
+
+
+
+`;
diff --git a/packages/components/paragraph/__test__/demo.test.js b/packages/components/paragraph/__test__/demo.test.js
new file mode 100644
index 000000000..5634d74f3
--- /dev/null
+++ b/packages/components/paragraph/__test__/demo.test.js
@@ -0,0 +1,19 @@
+/**
+ * 该文件为由脚本 `npm run test:demo` 自动生成,如需修改,执行脚本命令即可。请勿手写直接修改,否则会被覆盖
+ */
+
+import path from 'path';
+import simulate from 'miniprogram-simulate';
+
+const mapper = ['base', 'combination', 'copyable', 'ellipsis', 'theme'];
+
+describe('Paragraph', () => {
+ mapper.forEach((demoName) => {
+ it(`Paragraph ${demoName} demo works fine`, () => {
+ const id = load(path.resolve(__dirname, `../../paragraph/_example/${demoName}/index`), demoName);
+ const container = simulate.render(id);
+ container.attach(document.createElement('parent-wrapper'));
+ expect(container.toJSON()).toMatchSnapshot();
+ });
+ });
+});
diff --git a/packages/components/paragraph/__test__/index.test.js b/packages/components/paragraph/__test__/index.test.js
new file mode 100644
index 000000000..7576be5ec
--- /dev/null
+++ b/packages/components/paragraph/__test__/index.test.js
@@ -0,0 +1,283 @@
+import path from 'path';
+import simulate from 'miniprogram-simulate';
+import * as paragraphProps from '../props';
+import * as paragraphType from '../type';
+
+describe('paragraph exports', () => {
+ it(': props module can be loaded', () => {
+ expect(paragraphProps).toBeDefined();
+ });
+
+ it(': type module can be loaded', () => {
+ expect(paragraphType).toBeDefined();
+ });
+});
+
+describe('paragraph', () => {
+ const Paragraph = load(path.resolve(__dirname, '../paragraph'));
+
+ describe('props', () => {
+ it(': style && customStyle', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ style: 'color: red',
+ customStyle: 'font-size: 9px',
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $paragraph = comp.querySelector('.paragraph >>> .t-typography');
+ if (VIRTUAL_HOST) {
+ expect(
+ $paragraph.dom.getAttribute('style').includes(`${comp.data.style}; ${comp.data.customStyle}`),
+ ).toBeTruthy();
+ } else {
+ expect($paragraph.dom.getAttribute('style').includes(`${comp.data.customStyle}`)).toBeTruthy();
+ }
+ });
+
+ it(': content', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 是腾讯各业务团队在服务业务过程中沉淀的一套企业级设计体系。',
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ expect(comp.querySelector('.paragraph').dom.textContent).toContain(comp.data.content);
+ });
+
+ it(': slot content', () => {
+ const id = simulate.load({
+ template: `Slot Content`,
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ expect(comp.querySelector('.paragraph').dom.textContent).toContain('Slot Content');
+ });
+
+ it(': ellipsis[Boolean]', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $wrapper = comp.querySelector('.paragraph >>> .t-typography__ellipsis-wrapper');
+ expect($wrapper).toBeDefined();
+ const $content = comp.querySelector('.paragraph >>> .t-typography__ellipsis-content');
+ expect($content).toBeDefined();
+ });
+
+ it(': ellipsis[Object] with row', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 3 },
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $content = comp.querySelector('.paragraph >>> .t-typography__ellipsis-content');
+ expect($content).toBeDefined();
+ expect($content.dom.getAttribute('style')).toContain('-webkit-line-clamp:3');
+ });
+
+ it(': ellipsis[Object] with expandable', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).toBeDefined();
+ expect($expandBtn.dom.textContent).toContain('展开');
+
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(1);
+ });
+
+ it(': ellipsis[Object] with expandable and collapsible', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 2, expandable: true, collapsible: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ // 展开
+ const $expandBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 收起按钮
+ const $collapseBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ expect($collapseBtn).toBeDefined();
+ expect($collapseBtn.dom.textContent).toContain('收起');
+
+ // 收起
+ $collapseBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(2);
+ });
+
+ it(': ellipsis[Object] without expandable does not show button', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 2, expandable: false },
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).not.toBeTruthy();
+ });
+
+ it(': ellipsis[Object] with expandable but not collapsible', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true, collapsible: false },
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).toBeDefined();
+
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 展开后 collapsible=false,不应有收起按钮
+ const $paragraph = comp.querySelector('.paragraph');
+ expect($paragraph.data.isExpanded).toBe(true);
+ });
+
+ it(': ellipsis[Object] with suffix slot', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: `更多`,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true, collapsible: false, suffix: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $suffixBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ expect($suffixBtn).toBeDefined();
+
+ $suffixBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(1);
+ });
+
+ it(': without ellipsis does not show ellipsis wrapper', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $wrapper = comp.querySelector('.paragraph >>> .t-typography__ellipsis-wrapper');
+ expect($wrapper).not.toBeTruthy();
+ });
+
+ it(': ellipsis expanded removes line clamp style', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 2, expandable: true, collapsible: true },
+ },
+ usingComponents: {
+ 't-paragraph': Paragraph,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ // 展开前有 line-clamp 样式
+ let $content = comp.querySelector('.paragraph >>> .t-typography__ellipsis-content');
+ expect($content.dom.getAttribute('style')).toContain('-webkit-line-clamp:2');
+
+ // 点击展开
+ const $expandBtn = comp.querySelector('.paragraph >>> .t-typography-ellipsis-symbol');
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 展开后样式应为空(isExpanded = true)
+ $content = comp.querySelector('.paragraph >>> .t-typography__ellipsis-content');
+ expect($content.dom.getAttribute('style')).toBe('');
+ });
+ });
+});
diff --git a/packages/components/paragraph/__test__/text.test.js b/packages/components/paragraph/__test__/text.test.js
new file mode 100644
index 000000000..35c1000bd
--- /dev/null
+++ b/packages/components/paragraph/__test__/text.test.js
@@ -0,0 +1,642 @@
+import path from 'path';
+import simulate from 'miniprogram-simulate';
+import * as textExports from '../../text/index';
+
+describe('text exports', () => {
+ it(': index.ts should export props and type', () => {
+ expect(textExports).toBeDefined();
+ });
+});
+
+describe('text', () => {
+ const Text = load(path.resolve(__dirname, '../../text/text'));
+
+ describe('props', () => {
+ it(': style && customStyle', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ style: 'color: red',
+ customStyle: 'font-size: 9px',
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ if (VIRTUAL_HOST) {
+ expect($text.dom.getAttribute('style').includes(`${comp.data.style}; ${comp.data.customStyle}`)).toBeTruthy();
+ } else {
+ expect($text.dom.getAttribute('style').includes(`${comp.data.customStyle}`)).toBeTruthy();
+ }
+ });
+
+ it(': content', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 是腾讯各业务团队在服务业务过程中沉淀的一套企业级设计体系。',
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ expect(comp.querySelector('.text').dom.textContent).toContain(comp.data.content);
+ });
+
+ it(': code', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--code');
+ expect($inner).toBeDefined();
+ });
+
+ it(': strong', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--strong');
+ expect($inner).toBeDefined();
+ });
+
+ it(': italic', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--italic');
+ expect($inner).toBeDefined();
+ });
+
+ it(': underline', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--underline');
+ expect($inner).toBeDefined();
+ });
+
+ it(': delete', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--delete');
+ expect($inner).toBeDefined();
+ });
+
+ it(': keyboard', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--keyboard');
+ expect($inner).toBeDefined();
+ });
+
+ it(': mark[Boolean]', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--mark');
+ expect($inner).toBeDefined();
+ });
+
+ it(': mark[String] with custom color', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ mark: '#07c160',
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $inner = comp.querySelector('.text >>> .t-typography--mark');
+ expect($inner).toBeDefined();
+ // markStyle 在上层容器或 decor 元素的 style 中
+ const $text = comp.querySelector('.text >>> .t-typography');
+ const style = $text.dom.getAttribute('style') || '';
+ const decorStyle = $inner.dom.getAttribute('style') || '';
+ expect(style + decorStyle).toContain('background-color:#07c160');
+ });
+
+ it(': disabled', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--disabled')).toBeTruthy();
+ });
+
+ it(': theme - primary', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--primary')).toBeTruthy();
+ });
+
+ it(': theme - secondary', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--secondary')).toBeTruthy();
+ });
+
+ it(': theme - success', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--success')).toBeTruthy();
+ });
+
+ it(': theme - warning', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--warning')).toBeTruthy();
+ });
+
+ it(': theme - error', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--error')).toBeTruthy();
+ });
+
+ it(': theme should not add class when disabled', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('class').includes('t-typography--disabled')).toBeTruthy();
+ expect($text.dom.getAttribute('class').includes('t-typography--primary')).not.toBeTruthy();
+ });
+
+ it(': multiple decorations combined', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $strong = comp.querySelector('.text >>> .t-typography--strong');
+ const $italic = comp.querySelector('.text >>> .t-typography--italic');
+ const $underline = comp.querySelector('.text >>> .t-typography--underline');
+ const $code = comp.querySelector('.text >>> .t-typography--code');
+ expect($strong).toBeDefined();
+ expect($italic).toBeDefined();
+ expect($underline).toBeDefined();
+ expect($code).toBeDefined();
+ });
+
+ it(': ellipsis[Boolean]', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $wrapper = comp.querySelector('.text >>> .t-typography__ellipsis-wrapper');
+ expect($wrapper).toBeDefined();
+ const $content = comp.querySelector('.text >>> .t-typography__ellipsis-content');
+ expect($content).toBeDefined();
+ });
+
+ it(': ellipsis[Object] with row', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 2 },
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $content = comp.querySelector('.text >>> .t-typography__ellipsis-content');
+ expect($content).toBeDefined();
+ expect($content.dom.getAttribute('style')).toContain('-webkit-line-clamp:2');
+ });
+
+ it(': ellipsis[Object] with expandable', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.text >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).toBeDefined();
+ expect($expandBtn.dom.textContent).toContain('展开');
+
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(1);
+ });
+
+ it(': ellipsis[Object] with collapsible', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true, collapsible: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ // 先展开
+ const $expandBtn = comp.querySelector('.text >>> .t-typography-ellipsis-symbol');
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 展开后应有收起按钮
+ const $collapseBtn = comp.querySelector('.text >>> .t-typography-ellipsis-symbol');
+ expect($collapseBtn).toBeDefined();
+ expect($collapseBtn.dom.textContent).toContain('收起');
+
+ $collapseBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(2);
+ });
+
+ it(': ellipsis[Object] with expandable but not collapsible', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true, collapsible: false },
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.text >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).toBeDefined();
+
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 展开后 collapsible=false,不应有收起按钮(querySelector 未找到返回 undefined)
+ const $text = comp.querySelector('.text');
+ expect($text.data.isExpanded).toBe(true);
+ });
+
+ it(': ellipsis with copyable shows extra margin', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { expandable: true },
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.text >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).toBeDefined();
+ // rpx 在编译后变为 px
+ expect($expandBtn.dom.getAttribute('style')).toContain('margin-right:16px');
+ });
+
+ it(': copyable[Boolean]', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ expect($copy).toBeDefined();
+ });
+
+ it(': copyable triggers copy event', async () => {
+ const handleCopy = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: '复制文本',
+ },
+ methods: {
+ handleCopy,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ $copy.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleCopy).toHaveBeenCalledTimes(1);
+ });
+
+ it(': copyable[Object] with custom text', async () => {
+ const handleCopy = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ copyable: { text: '自定义复制内容' },
+ },
+ methods: {
+ handleCopy,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ $copy.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleCopy).toHaveBeenCalledTimes(1);
+ });
+
+ it(': copyable prevents double click', async () => {
+ const handleCopy = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ methods: {
+ handleCopy,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ $copy.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 第二次点击应被忽略(isCopied 状态)
+ $copy.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleCopy).toHaveBeenCalledTimes(1);
+ });
+
+ it(': copyable icon resets after timeout', async () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ $copy.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ const $text = comp.querySelector('.text');
+ expect($text.data.isCopied).toBe(true);
+
+ // 等待 1500ms+ 后恢复
+ await simulate.sleep(1600);
+ expect($text.data.isCopied).toBe(false);
+ });
+
+ it(': copyable triggers copy event with empty content', async () => {
+ const handleCopy = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ methods: {
+ handleCopy,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ $copy.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleCopy).toHaveBeenCalledTimes(1);
+ expect(handleCopy.mock.calls[0][0].detail).toEqual({ text: '' });
+ });
+
+ it(': copyable with suffix slot', () => {
+ const id = simulate.load({
+ template: `自定义`,
+ data: {
+ copyable: { suffix: true },
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $copy = comp.querySelector('.text >>> .t-typography__copy');
+ expect($copy).toBeDefined();
+ });
+
+ it(': without ellipsis renders inline', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $text = comp.querySelector('.text >>> .t-typography');
+ expect($text.dom.getAttribute('style')).toContain('display:inline');
+ });
+ });
+
+ describe('observers', () => {
+ it(': theme change updates className', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ theme: 'primary',
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $textComp = comp.querySelector('.text');
+ expect($textComp.data.className.includes('t-typography--primary')).toBeTruthy();
+
+ // 通过组件实例直接修改 properties 来触发 observer
+ $textComp.setData({ theme: 'success' });
+ await simulate.sleep(10);
+
+ expect($textComp.data.className.includes('t-typography--success')).toBeTruthy();
+ expect($textComp.data.className.includes('t-typography--primary')).not.toBeTruthy();
+ });
+
+ it(': disabled change updates className', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ disabled: false,
+ },
+ usingComponents: {
+ 't-text': Text,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $textComp = comp.querySelector('.text');
+ expect($textComp.data.className.includes('t-typography--primary')).toBeTruthy();
+
+ $textComp.setData({ disabled: true });
+ await simulate.sleep(10);
+
+ expect($textComp.data.className.includes('t-typography--disabled')).toBeTruthy();
+ expect($textComp.data.className.includes('t-typography--primary')).not.toBeTruthy();
+ });
+ });
+});
diff --git a/packages/components/paragraph/__test__/title.test.js b/packages/components/paragraph/__test__/title.test.js
new file mode 100644
index 000000000..478285d56
--- /dev/null
+++ b/packages/components/paragraph/__test__/title.test.js
@@ -0,0 +1,286 @@
+import path from 'path';
+import simulate from 'miniprogram-simulate';
+import * as titleProps from '../../title/props';
+import * as titleType from '../../title/type';
+
+describe('title exports', () => {
+ it(': props module can be loaded', () => {
+ expect(titleProps).toBeDefined();
+ });
+
+ it(': type module can be loaded', () => {
+ expect(titleType).toBeDefined();
+ });
+});
+
+describe('title', () => {
+ const Title = load(path.resolve(__dirname, '../../title/title'));
+
+ describe('props', () => {
+ it(': style && customStyle', async () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ style: 'color: red',
+ customStyle: 'font-size: 9px',
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ if (VIRTUAL_HOST) {
+ expect($title.dom.getAttribute('style').includes(`${comp.data.style}; ${comp.data.customStyle}`)).toBeTruthy();
+ } else {
+ expect($title.dom.getAttribute('style').includes(`${comp.data.customStyle}`)).toBeTruthy();
+ }
+ });
+
+ it(': content', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: '标题内容',
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ expect(comp.querySelector('.title').dom.textContent).toContain(comp.data.content);
+ });
+
+ it(': level - h1 (default)', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ expect($title.dom.getAttribute('class').includes('t-typography--h1')).toBeTruthy();
+ });
+
+ it(': level - h2', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ expect($title.dom.getAttribute('class').includes('t-typography--h2')).toBeTruthy();
+ });
+
+ it(': level - h3', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ expect($title.dom.getAttribute('class').includes('t-typography--h3')).toBeTruthy();
+ });
+
+ it(': level - h4', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ expect($title.dom.getAttribute('class').includes('t-typography--h4')).toBeTruthy();
+ });
+
+ it(': level - h5', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ expect($title.dom.getAttribute('class').includes('t-typography--h5')).toBeTruthy();
+ });
+
+ it(': level - h6', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $title = comp.querySelector('.title >>> .t-typography');
+ expect($title.dom.getAttribute('class').includes('t-typography--h6')).toBeTruthy();
+ });
+
+ it(': ellipsis[Boolean]', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $wrapper = comp.querySelector('.title >>> .t-typography__ellipsis-wrapper');
+ expect($wrapper).toBeDefined();
+ const $content = comp.querySelector('.title >>> .t-typography__ellipsis-content');
+ expect($content).toBeDefined();
+ });
+
+ it(': ellipsis[Object] with row', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 2 },
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $content = comp.querySelector('.title >>> .t-typography__ellipsis-content');
+ expect($content).toBeDefined();
+ expect($content.dom.getAttribute('style')).toContain('-webkit-line-clamp:2');
+ });
+
+ it(': ellipsis[Object] with expandable', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.title >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).toBeDefined();
+ expect($expandBtn.dom.textContent).toContain('展开');
+
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(1);
+ });
+
+ it(': ellipsis[Object] with expandable and collapsible', async () => {
+ const handleExpand = jest.fn();
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 1, expandable: true, collapsible: true },
+ },
+ methods: {
+ handleExpand,
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ // 展开
+ const $expandBtn = comp.querySelector('.title >>> .t-typography-ellipsis-symbol');
+ $expandBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+
+ // 收起按钮出现
+ const $collapseBtn = comp.querySelector('.title >>> .t-typography-ellipsis-symbol');
+ expect($collapseBtn).toBeDefined();
+ expect($collapseBtn.dom.textContent).toContain('收起');
+
+ // 收起
+ $collapseBtn.dispatchEvent('tap');
+ await simulate.sleep(10);
+ expect(handleExpand).toHaveBeenCalledTimes(2);
+ });
+
+ it(': ellipsis[Object] without expandable does not show button', () => {
+ const id = simulate.load({
+ template: ``,
+ data: {
+ content: 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。',
+ ellipsis: { row: 2, expandable: false },
+ },
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $expandBtn = comp.querySelector('.title >>> .t-typography-ellipsis-symbol');
+ expect($expandBtn).not.toBeTruthy();
+ });
+
+ it(': without ellipsis does not show ellipsis wrapper', () => {
+ const id = simulate.load({
+ template: ``,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ const $wrapper = comp.querySelector('.title >>> .t-typography__ellipsis-wrapper');
+ expect($wrapper).not.toBeTruthy();
+ });
+
+ it(': slot content', () => {
+ const id = simulate.load({
+ template: `Slot Title`,
+ usingComponents: {
+ 't-title': Title,
+ },
+ });
+ const comp = simulate.render(id);
+ comp.attach(document.createElement('parent-wrapper'));
+
+ expect(comp.querySelector('.title').dom.textContent).toContain('Slot Title');
+ });
+ });
+});
diff --git a/packages/components/paragraph/_example/base/index.js b/packages/components/paragraph/_example/base/index.js
new file mode 100644
index 000000000..b79c5124b
--- /dev/null
+++ b/packages/components/paragraph/_example/base/index.js
@@ -0,0 +1 @@
+Component({});
diff --git a/packages/components/paragraph/_example/base/index.json b/packages/components/paragraph/_example/base/index.json
new file mode 100644
index 000000000..e0cb8aade
--- /dev/null
+++ b/packages/components/paragraph/_example/base/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "t-typography-text": "tdesign-miniprogram/text/text"
+ }
+}
diff --git a/packages/components/paragraph/_example/base/index.wxml b/packages/components/paragraph/_example/base/index.wxml
new file mode 100644
index 000000000..cb97291c9
--- /dev/null
+++ b/packages/components/paragraph/_example/base/index.wxml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/components/paragraph/_example/base/index.wxss b/packages/components/paragraph/_example/base/index.wxss
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/components/paragraph/_example/combination/index.js b/packages/components/paragraph/_example/combination/index.js
new file mode 100644
index 000000000..b79c5124b
--- /dev/null
+++ b/packages/components/paragraph/_example/combination/index.js
@@ -0,0 +1 @@
+Component({});
diff --git a/packages/components/paragraph/_example/combination/index.json b/packages/components/paragraph/_example/combination/index.json
new file mode 100644
index 000000000..cd240fabe
--- /dev/null
+++ b/packages/components/paragraph/_example/combination/index.json
@@ -0,0 +1,9 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "t-typography-text": "tdesign-miniprogram/text/text",
+ "t-typography-title": "tdesign-miniprogram/title/title",
+ "t-typography-paragraph": "tdesign-miniprogram/paragraph/paragraph"
+ }
+}
diff --git a/packages/components/paragraph/_example/combination/index.wxml b/packages/components/paragraph/_example/combination/index.wxml
new file mode 100644
index 000000000..2c2aad69a
--- /dev/null
+++ b/packages/components/paragraph/_example/combination/index.wxml
@@ -0,0 +1,41 @@
+
+
+
+
+
+ TDesign features a unified design values, consistent design language, and visual style, helping users form
+ continuous and coherent perceptions of the experience.
+
+ Based on this, TDesign offers out-typography-of-the-box UI component libraries, design guidelines, and design
+ assets, elegantly and efficiently freeing design and development from repetitive tasks. Simultaneously, it
+ facilitates easy extension on top of TDesign, enabling a better alignment with business requirements.
+
+
+ Comprehensive
+
+ TDesign Support
+ Vue 2, Vue 3,
+ React
+ components for Desktop Application and
+ Vue 3,
+ Wechat MiniProgram
+ components for Mobile Application.
+
+
+ • Features
+ • Comprehensive
+ • Consistency
+ • Usability
+ • Join TDesign
+
+
+ 1. Features
+ 2. Comprehensive
+ 1. Consistency
+ 2. Usability
+ 3. Join TDesign
+
+
diff --git a/packages/components/paragraph/_example/combination/index.wxss b/packages/components/paragraph/_example/combination/index.wxss
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/components/paragraph/_example/copyable/index.js b/packages/components/paragraph/_example/copyable/index.js
new file mode 100644
index 000000000..36bfc6357
--- /dev/null
+++ b/packages/components/paragraph/_example/copyable/index.js
@@ -0,0 +1,7 @@
+Component({
+ data: {
+ copyableCustomSuffix: {
+ suffix: true,
+ },
+ },
+});
diff --git a/packages/components/paragraph/_example/copyable/index.json b/packages/components/paragraph/_example/copyable/index.json
new file mode 100644
index 000000000..e783eb00c
--- /dev/null
+++ b/packages/components/paragraph/_example/copyable/index.json
@@ -0,0 +1,8 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "t-typography-text": "tdesign-miniprogram/text/text",
+ "t-icon": "tdesign-miniprogram/icon/icon"
+ }
+}
diff --git a/packages/components/paragraph/_example/copyable/index.wxml b/packages/components/paragraph/_example/copyable/index.wxml
new file mode 100644
index 000000000..218d77f5d
--- /dev/null
+++ b/packages/components/paragraph/_example/copyable/index.wxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/paragraph/_example/copyable/index.wxss b/packages/components/paragraph/_example/copyable/index.wxss
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/components/paragraph/_example/ellipsis/index.js b/packages/components/paragraph/_example/ellipsis/index.js
new file mode 100644
index 000000000..e91d3101c
--- /dev/null
+++ b/packages/components/paragraph/_example/ellipsis/index.js
@@ -0,0 +1,17 @@
+Component({
+ data: {
+ content:
+ 'TDesign 秉承开放的设计理念从创立之初就采用开源协作的方式进行设计和开发。协作方案讨论、组件设计以及 API 设计,包括源代码在内均在公司内部完全开放,赢得了内部开发者和设计师的广泛关注。TDesign 遵循平等、开放、严格的原则,不论参与者的角色如何。',
+ ellipsisExpandable: {
+ row: 2,
+ expandable: true,
+ collapsible: true,
+ },
+ ellipsisCustomSuffix: {
+ row: 1,
+ expandable: true,
+ collapsible: false,
+ suffix: true,
+ },
+ },
+});
diff --git a/packages/components/paragraph/_example/ellipsis/index.json b/packages/components/paragraph/_example/ellipsis/index.json
new file mode 100644
index 000000000..c24644ca7
--- /dev/null
+++ b/packages/components/paragraph/_example/ellipsis/index.json
@@ -0,0 +1,8 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "t-typography-paragraph": "tdesign-miniprogram/paragraph/paragraph",
+ "t-icon": "tdesign-miniprogram/icon/icon"
+ }
+}
diff --git a/packages/components/paragraph/_example/ellipsis/index.wxml b/packages/components/paragraph/_example/ellipsis/index.wxml
new file mode 100644
index 000000000..6ab9160d7
--- /dev/null
+++ b/packages/components/paragraph/_example/ellipsis/index.wxml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/paragraph/_example/ellipsis/index.wxss b/packages/components/paragraph/_example/ellipsis/index.wxss
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/components/paragraph/_example/paragraph.json b/packages/components/paragraph/_example/paragraph.json
new file mode 100644
index 000000000..31f76ff2e
--- /dev/null
+++ b/packages/components/paragraph/_example/paragraph.json
@@ -0,0 +1,11 @@
+{
+ "navigationBarTitleText": "Typography",
+ "navigationBarBackgroundColor": "#fff",
+ "usingComponents": {
+ "base": "./base",
+ "theme": "./theme",
+ "copyable": "./copyable",
+ "ellipsis": "./ellipsis",
+ "combination": "./combination"
+ }
+}
diff --git a/packages/components/paragraph/_example/paragraph.less b/packages/components/paragraph/_example/paragraph.less
new file mode 100644
index 000000000..1af7bc8bf
--- /dev/null
+++ b/packages/components/paragraph/_example/paragraph.less
@@ -0,0 +1,27 @@
+.typography-example {
+ display: flex;
+ padding: 0 32rpx;
+ background-color: var(--bg-color-demo, #fff);
+
+ &--inline {
+ display: inline-block;
+ }
+
+ &--theme {
+ gap: 24px;
+ }
+
+ &--border {
+ position: relative;
+
+ &::after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ left: 16px;
+ right: 16px;
+ border-bottom: 1px solid var(--td-stroke-color, #e7e7e7);
+ transform: scaleY(0.5);
+ }
+ }
+}
diff --git a/packages/components/paragraph/_example/paragraph.ts b/packages/components/paragraph/_example/paragraph.ts
new file mode 100644
index 000000000..560d44d43
--- /dev/null
+++ b/packages/components/paragraph/_example/paragraph.ts
@@ -0,0 +1 @@
+Page({});
diff --git a/packages/components/paragraph/_example/paragraph.wxml b/packages/components/paragraph/_example/paragraph.wxml
new file mode 100644
index 000000000..b5bbf42fb
--- /dev/null
+++ b/packages/components/paragraph/_example/paragraph.wxml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/paragraph/_example/theme/index.js b/packages/components/paragraph/_example/theme/index.js
new file mode 100644
index 000000000..b79c5124b
--- /dev/null
+++ b/packages/components/paragraph/_example/theme/index.js
@@ -0,0 +1 @@
+Component({});
diff --git a/packages/components/paragraph/_example/theme/index.json b/packages/components/paragraph/_example/theme/index.json
new file mode 100644
index 000000000..e0cb8aade
--- /dev/null
+++ b/packages/components/paragraph/_example/theme/index.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "t-typography-text": "tdesign-miniprogram/text/text"
+ }
+}
diff --git a/packages/components/paragraph/_example/theme/index.wxml b/packages/components/paragraph/_example/theme/index.wxml
new file mode 100644
index 000000000..b4ba5b539
--- /dev/null
+++ b/packages/components/paragraph/_example/theme/index.wxml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/packages/components/paragraph/_example/theme/index.wxss b/packages/components/paragraph/_example/theme/index.wxss
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/components/paragraph/ellipsis.wxml b/packages/components/paragraph/ellipsis.wxml
new file mode 100644
index 000000000..36ca7e1de
--- /dev/null
+++ b/packages/components/paragraph/ellipsis.wxml
@@ -0,0 +1,18 @@
+
+
+ 展开
+
+ 收起
+
diff --git a/packages/components/paragraph/paragraph.json b/packages/components/paragraph/paragraph.json
new file mode 100644
index 000000000..79f273097
--- /dev/null
+++ b/packages/components/paragraph/paragraph.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared"
+}
diff --git a/packages/components/paragraph/paragraph.less b/packages/components/paragraph/paragraph.less
new file mode 100644
index 000000000..feae8f6aa
--- /dev/null
+++ b/packages/components/paragraph/paragraph.less
@@ -0,0 +1,189 @@
+@import '../common/style/base.less';
+
+// ==================== 变量定义(对应 _var.less) ====================
+@typography-text-primary-color: @text-color-primary;
+@typography-text-secondary-color: @text-color-secondary;
+@typography-text-disabled-color: @text-color-disabled;
+@typography-text-success-color: @success-color;
+@typography-text-error-color: @error-color;
+@typography-text-warning-color: @warning-color;
+@typography-text-mark-color: #fcdf47;
+@typography-icon-color: @brand-color;
+
+@typography-text-strong: 600;
+
+@typography-text-font: @font-body-medium;
+@typography-code-font: @font-body-small;
+@typography-h1-font: @font-headline-large;
+@typography-h2-font: @font-headline-medium;
+@typography-h3-font: @font-headline-small;
+@typography-h4-font: @font-title-large;
+@typography-h5-font: @font-title-medium;
+@typography-h6-font: @font-title-small;
+
+@typography-code-family:
+ Source Code Pro,
+ -apple-system,
+ BlinkMacSystemFont,
+ Segoe UI,
+ Roboto,
+ Hiragino Sans GB,
+ Microsoft YaHei UI,
+ Microsoft YaHei;
+
+// ==================== 主样式(对应 _index.less) ====================
+.@{prefix}-typography {
+ color: @typography-text-primary-color;
+ font: @font-body-medium;
+ margin: @spacer-2 0;
+
+ // 标题级别(小程序用 modifier 类名模拟 h1-h6 标签选择器)
+ &--h1 {
+ font: @typography-h1-font;
+ margin-top: @spacer-4;
+ margin-bottom: @spacer-3;
+ }
+
+ &--h2 {
+ font: @typography-h2-font;
+ margin-top: @spacer-4;
+ margin-bottom: @spacer-3;
+ }
+
+ &--h3 {
+ font: @typography-h3-font;
+ margin-top: @spacer-4;
+ margin-bottom: @spacer-2;
+ }
+
+ &--h4 {
+ font: @typography-h4-font;
+ margin-top: @spacer-3;
+ margin-bottom: @spacer-2;
+ }
+
+ &--h5 {
+ font: @typography-h5-font;
+ margin-top: @spacer-3;
+ margin-bottom: @spacer-2;
+ }
+
+ &--h6 {
+ font: @typography-h6-font;
+ }
+
+ strong,
+ &--strong {
+ font-weight: @typography-text-strong;
+ }
+
+ mark,
+ &--mark {
+ background-color: @typography-text-mark-color;
+ }
+
+ code,
+ &--code {
+ border-radius: @radius-default;
+ border: 1px solid @component-border;
+ margin: 0 @spacer;
+ background-color: @bg-color-secondarycontainer;
+ padding: 0 @spacer;
+ transition: background-color 0.2s;
+ white-space: nowrap;
+ font: @typography-code-font;
+ font-family: @typography-code-family;
+ display: inline-block;
+ }
+
+ kbd,
+ &--keyboard {
+ border-radius: @radius-default;
+ border: 1px solid @component-border;
+ margin: 0 calc(@spacer / 2);
+ background-color: @bg-color-secondarycontainer;
+ padding: 0 @spacer;
+ box-shadow: 0 1px 0 0 @component-border;
+ font: @typography-code-font;
+ font-family: @typography-code-family;
+ display: inline-block;
+ }
+
+ // 不可选样式
+ &--disabled {
+ color: @typography-text-disabled-color;
+ cursor: not-allowed;
+ }
+
+ // 主题样式
+ &--success {
+ color: @typography-text-success-color;
+ }
+
+ &--warning {
+ color: @typography-text-warning-color;
+ }
+
+ &--error {
+ color: @typography-text-error-color;
+ }
+
+ &--secondary {
+ color: @typography-text-secondary-color;
+ }
+
+ &-ellipsis-symbol,
+ .t-icon-copy {
+ color: @typography-icon-color;
+ cursor: pointer;
+ }
+
+ .t-icon-checked {
+ color: @success-color;
+ }
+
+ // ==================== 小程序适配补充 ====================
+
+ i,
+ &--italic {
+ font-style: italic;
+ }
+
+ u,
+ &--underline {
+ text-decoration: underline;
+ }
+
+ del,
+ &--delete {
+ text-decoration: line-through;
+ }
+
+ // 省略相关
+ &__ellipsis-wrapper {
+ display: flex;
+ align-items: flex-end;
+ }
+
+ &__ellipsis-content {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: normal;
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ }
+
+ &-ellipsis-symbol {
+ text-decoration: none;
+ white-space: nowrap;
+ flex: 1;
+ }
+
+ // 复制按钮
+ &__copy {
+ display: inline-flex;
+ align-items: center;
+ margin-left: 16rpx;
+ flex-shrink: 0;
+ }
+}
diff --git a/packages/components/paragraph/paragraph.ts b/packages/components/paragraph/paragraph.ts
new file mode 100644
index 000000000..d0634c22f
--- /dev/null
+++ b/packages/components/paragraph/paragraph.ts
@@ -0,0 +1,41 @@
+import { SuperComponent, wxComponent } from '../common/src/index';
+import config from '../common/config';
+import props from './props';
+
+const { prefix } = config;
+const name = `${prefix}-typography`;
+
+@wxComponent()
+export default class Paragraph extends SuperComponent {
+ externalClasses = [`${prefix}-class`];
+
+ options = {
+ multipleSlots: true,
+ };
+
+ properties = props;
+
+ data = {
+ prefix,
+ classPrefix: name,
+ isExpanded: false,
+ };
+
+ methods = {
+ onExpand() {
+ this.setData({ isExpanded: true });
+ const { ellipsis } = this.properties;
+ if (typeof ellipsis === 'object') {
+ this.triggerEvent('expand', { expanded: true });
+ }
+ },
+
+ onCollapse() {
+ this.setData({ isExpanded: false });
+ const { ellipsis } = this.properties;
+ if (typeof ellipsis === 'object') {
+ this.triggerEvent('expand', { expanded: false });
+ }
+ },
+ };
+}
diff --git a/packages/components/paragraph/paragraph.wxml b/packages/components/paragraph/paragraph.wxml
new file mode 100644
index 000000000..30952c275
--- /dev/null
+++ b/packages/components/paragraph/paragraph.wxml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+ {{content}}
+
+
+
+ {{content}}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/paragraph/paragraph.wxs b/packages/components/paragraph/paragraph.wxs
new file mode 100644
index 000000000..61f1a1925
--- /dev/null
+++ b/packages/components/paragraph/paragraph.wxs
@@ -0,0 +1,49 @@
+/* typography 公共计算逻辑 */
+
+/* 计算省略内容的内联样式 */
+function ellipsisStyle(ellipsis, isExpanded) {
+ if (!ellipsis || isExpanded) return '';
+ var row = typeof ellipsis === 'object' && ellipsis.row ? ellipsis.row : 1;
+ return (
+ 'overflow:hidden;text-overflow:ellipsis;white-space:normal;display:-webkit-box;-webkit-line-clamp:' +
+ row +
+ ';-webkit-box-orient:vertical;'
+ );
+}
+
+/* 计算外层容器 class */
+function wrapperClass(classPrefix, ellipsis) {
+ if (ellipsis) {
+ return classPrefix + '__ellipsis-wrapper';
+ }
+ return '';
+}
+
+/* 根据装饰属性拼接内层 class */
+function decorClass(classPrefix, strong, underline, del, code, mark, keyboard, italic) {
+ var list = [];
+ if (strong) list.push(classPrefix + '--strong');
+ if (underline) list.push(classPrefix + '--underline');
+ if (del) list.push(classPrefix + '--delete');
+ if (code) list.push(classPrefix + '--code');
+ if (mark) list.push(classPrefix + '--mark');
+ if (keyboard) list.push(classPrefix + '--keyboard');
+ if (italic) list.push(classPrefix + '--italic');
+ return list.join(' ');
+}
+
+/* mark 自定义颜色 */
+function markStyle(mark) {
+ if (!mark || mark === true || mark === 'true') return '';
+ if (mark && mark !== 'false' && mark !== false) {
+ return 'background-color:' + mark + ';';
+ }
+ return '';
+}
+
+module.exports = {
+ ellipsisStyle: ellipsisStyle,
+ wrapperClass: wrapperClass,
+ decorClass: decorClass,
+ markStyle: markStyle,
+};
diff --git a/packages/components/paragraph/props.ts b/packages/components/paragraph/props.ts
new file mode 100644
index 000000000..4cfaea9e2
--- /dev/null
+++ b/packages/components/paragraph/props.ts
@@ -0,0 +1,20 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TdParagraphProps } from './type';
+const props: TdParagraphProps = {
+ /** 段落内容 */
+ content: {
+ type: String,
+ },
+ /** 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式 */
+ ellipsis: {
+ type: null,
+ value: false,
+ },
+};
+
+export default props;
diff --git a/packages/components/paragraph/type.ts b/packages/components/paragraph/type.ts
new file mode 100644
index 000000000..b658bc300
--- /dev/null
+++ b/packages/components/paragraph/type.ts
@@ -0,0 +1,25 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TypographyEllipsis } from '../text/index';
+
+export interface TdParagraphProps {
+ /**
+ * 段落内容
+ */
+ content?: {
+ type: StringConstructor;
+ value?: string;
+ };
+ /**
+ * 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式
+ * @default false
+ */
+ ellipsis?: {
+ type: null;
+ value?: boolean | TypographyEllipsis;
+ };
+}
diff --git a/packages/components/search/README.md b/packages/components/search/README.md
index 2b6859e5c..3db5966fa 100644
--- a/packages/components/search/README.md
+++ b/packages/components/search/README.md
@@ -6,7 +6,7 @@ isComponent: true
---
-


+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/components/segmented/README.md b/packages/components/segmented/README.md
index 6c579cbd1..fdbb708ad 100644
--- a/packages/components/segmented/README.md
+++ b/packages/components/segmented/README.md
@@ -14,6 +14,7 @@ isComponent: true
+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/components/table/README.md b/packages/components/table/README.md
index 6c01dd0ba..e8ddad4f7 100644
--- a/packages/components/table/README.md
+++ b/packages/components/table/README.md
@@ -13,6 +13,7 @@ toc: false
该组件于 1.14.0 版本上线,请留意版本。
+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/components/tabs/README.md b/packages/components/tabs/README.md
index c5aafa98a..aaa00766d 100644
--- a/packages/components/tabs/README.md
+++ b/packages/components/tabs/README.md
@@ -5,7 +5,7 @@ spline: navigation
isComponent: true
---
-


+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/components/text/index.ts b/packages/components/text/index.ts
new file mode 100644
index 000000000..e5ac9994d
--- /dev/null
+++ b/packages/components/text/index.ts
@@ -0,0 +1,2 @@
+export * from './props';
+export * from './type';
diff --git a/packages/components/text/props.ts b/packages/components/text/props.ts
new file mode 100644
index 000000000..ced9c8ed2
--- /dev/null
+++ b/packages/components/text/props.ts
@@ -0,0 +1,69 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TdTextProps } from './type';
+const props: TdTextProps = {
+ /** 是否添加代码样式 */
+ code: {
+ type: Boolean,
+ value: false,
+ },
+ /** 文本内容 */
+ content: {
+ type: String,
+ },
+ /** 是否可复制 */
+ copyable: {
+ type: null,
+ value: false,
+ },
+ /** 是否添加删除线样式 */
+ delete: {
+ type: Boolean,
+ value: false,
+ },
+ /** 是否添加不可用样式 */
+ disabled: {
+ type: Boolean,
+ value: false,
+ },
+ /** 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式 */
+ ellipsis: {
+ type: null,
+ value: false,
+ },
+ /** 文本是否为斜体 */
+ italic: {
+ type: Boolean,
+ value: false,
+ },
+ /** 是否添加键盘样式 */
+ keyboard: {
+ type: Boolean,
+ value: false,
+ },
+ /** 是否添加标记样式,默认为黄色,可通过配置颜色修改标记样式,如#0052D9 */
+ mark: {
+ type: null,
+ value: false,
+ },
+ /** 文本是否加粗 */
+ strong: {
+ type: Boolean,
+ value: false,
+ },
+ /** 主题 */
+ theme: {
+ type: String,
+ },
+ /** 是否添加下划线样式 */
+ underline: {
+ type: Boolean,
+ value: false,
+ },
+};
+
+export default props;
diff --git a/packages/components/text/text.json b/packages/components/text/text.json
new file mode 100644
index 000000000..f783dae79
--- /dev/null
+++ b/packages/components/text/text.json
@@ -0,0 +1,7 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared",
+ "usingComponents": {
+ "t-icon": "../icon/icon"
+ }
+}
diff --git a/packages/components/text/text.less b/packages/components/text/text.less
new file mode 100644
index 000000000..d20abff77
--- /dev/null
+++ b/packages/components/text/text.less
@@ -0,0 +1 @@
+@import '../paragraph/paragraph.less';
diff --git a/packages/components/text/text.ts b/packages/components/text/text.ts
new file mode 100644
index 000000000..d0bda3692
--- /dev/null
+++ b/packages/components/text/text.ts
@@ -0,0 +1,91 @@
+import { SuperComponent, wxComponent } from '../common/src/index';
+import config from '../common/config';
+import props from './props';
+
+const { prefix } = config;
+const name = `${prefix}-typography`;
+
+@wxComponent()
+export default class Text extends SuperComponent {
+ externalClasses = [`${prefix}-class`, `${prefix}-class-copy`];
+
+ options = {
+ multipleSlots: true,
+ };
+
+ properties = props;
+
+ data = {
+ prefix,
+ classPrefix: name,
+ className: '',
+ isExpanded: false,
+ isCopied: false,
+ };
+
+ lifetimes = {
+ attached() {
+ this.updateClass();
+ },
+ };
+
+ observers = {
+ 'theme, disabled'() {
+ this.updateClass();
+ },
+ };
+
+ methods = {
+ updateClass() {
+ const { classPrefix } = this.data;
+ const { theme, disabled } = this.properties;
+ const classList = [classPrefix];
+
+ if (disabled) {
+ classList.push(`${classPrefix}--disabled`);
+ } else if (theme && ['primary', 'secondary', 'success', 'warning', 'error'].includes(theme)) {
+ classList.push(`${classPrefix}--${theme}`);
+ }
+
+ this.setData({ className: classList.join(' ') });
+ },
+
+ onExpand() {
+ this.setData({ isExpanded: true });
+ const { ellipsis } = this.properties;
+ if (typeof ellipsis === 'object') {
+ this.triggerEvent('expand', { expanded: true });
+ }
+ },
+
+ onCollapse() {
+ this.setData({ isExpanded: false });
+ const { ellipsis } = this.properties;
+ if (typeof ellipsis === 'object') {
+ this.triggerEvent('expand', { expanded: false });
+ }
+ },
+
+ onCopy() {
+ if (this.data.isCopied) return;
+
+ const { copyable, content } = this.properties;
+ let text = content || '';
+
+ if (typeof copyable === 'object' && copyable !== null && copyable.text) {
+ text = copyable.text;
+ }
+
+ wx.setClipboardData({
+ data: text,
+ success: () => {
+ this.setData({ isCopied: true });
+ this.triggerEvent('copy', { text });
+ setTimeout(() => {
+ this.setData({ isCopied: false });
+ }, 1500);
+ },
+ });
+ },
+ };
+}
diff --git a/packages/components/text/text.wxml b/packages/components/text/text.wxml
new file mode 100644
index 000000000..03ed1342f
--- /dev/null
+++ b/packages/components/text/text.wxml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+ {{content}}
+
+
+
+
+ {{content}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/components/text/type.ts b/packages/components/text/type.ts
new file mode 100644
index 000000000..d8c8a1381
--- /dev/null
+++ b/packages/components/text/type.ts
@@ -0,0 +1,114 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
+ * */
+
+export interface TdTextProps {
+ /**
+ * 是否添加代码样式
+ * @default false
+ */
+ code?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ /**
+ * 文本内容
+ */
+ content?: {
+ type: StringConstructor;
+ value?: string;
+ };
+ /**
+ * 是否可复制
+ * @default false
+ */
+ copyable?: {
+ type: null;
+ value?: boolean | TypographyCopyable;
+ };
+ /**
+ * 是否添加删除线样式
+ * @default false
+ */
+ delete?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ /**
+ * 是否添加不可用样式
+ * @default false
+ */
+ disabled?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ /**
+ * 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式
+ * @default false
+ */
+ ellipsis?: {
+ type: null;
+ value?: boolean | TypographyEllipsis;
+ };
+ /**
+ * 文本是否为斜体
+ * @default false
+ */
+ italic?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ /**
+ * 是否添加键盘样式
+ * @default false
+ */
+ keyboard?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ /**
+ * 是否添加标记样式,默认为黄色,可通过配置颜色修改标记样式,如#0052D9
+ * @default false
+ */
+ mark?: {
+ type: null;
+ value?: string | boolean;
+ };
+ /**
+ * 文本是否加粗
+ * @default false
+ */
+ strong?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+ /**
+ * 主题
+ */
+ theme?: {
+ type: StringConstructor;
+ value?: 'primary' | 'secondary' | 'success' | 'warning' | 'error';
+ };
+ /**
+ * 是否添加下划线样式
+ * @default false
+ */
+ underline?: {
+ type: BooleanConstructor;
+ value?: boolean;
+ };
+}
+
+export interface TypographyCopyable {
+ text?: string;
+ suffix?: boolean;
+}
+
+export interface TypographyEllipsis {
+ collapsible?: boolean;
+ expandable?: boolean;
+ row?: number;
+ suffix?: boolean;
+}
diff --git a/packages/components/title/props.ts b/packages/components/title/props.ts
new file mode 100644
index 000000000..ba34e4324
--- /dev/null
+++ b/packages/components/title/props.ts
@@ -0,0 +1,25 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TdTitleProps } from './type';
+const props: TdTitleProps = {
+ /** 段落内容 */
+ content: {
+ type: String,
+ },
+ /** 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式 */
+ ellipsis: {
+ type: null,
+ value: false,
+ },
+ /** 标题等级 */
+ level: {
+ type: String,
+ value: 'h1',
+ },
+};
+
+export default props;
diff --git a/packages/components/title/title.json b/packages/components/title/title.json
new file mode 100644
index 000000000..79f273097
--- /dev/null
+++ b/packages/components/title/title.json
@@ -0,0 +1,4 @@
+{
+ "component": true,
+ "styleIsolation": "apply-shared"
+}
diff --git a/packages/components/title/title.less b/packages/components/title/title.less
new file mode 100644
index 000000000..d20abff77
--- /dev/null
+++ b/packages/components/title/title.less
@@ -0,0 +1 @@
+@import '../paragraph/paragraph.less';
diff --git a/packages/components/title/title.ts b/packages/components/title/title.ts
new file mode 100644
index 000000000..d9ef084b9
--- /dev/null
+++ b/packages/components/title/title.ts
@@ -0,0 +1,41 @@
+import { SuperComponent, wxComponent } from '../common/src/index';
+import config from '../common/config';
+import props from './props';
+
+const { prefix } = config;
+const name = `${prefix}-typography`;
+
+@wxComponent()
+export default class Title extends SuperComponent {
+ externalClasses = [`${prefix}-class`];
+
+ options = {
+ multipleSlots: true,
+ };
+
+ properties = props;
+
+ data = {
+ prefix,
+ classPrefix: name,
+ isExpanded: false,
+ };
+
+ methods = {
+ onExpand() {
+ this.setData({ isExpanded: true });
+ const { ellipsis } = this.properties;
+ if (typeof ellipsis === 'object') {
+ this.triggerEvent('expand', { expanded: true });
+ }
+ },
+
+ onCollapse() {
+ this.setData({ isExpanded: false });
+ const { ellipsis } = this.properties;
+ if (typeof ellipsis === 'object') {
+ this.triggerEvent('expand', { expanded: false });
+ }
+ },
+ };
+}
diff --git a/packages/components/title/title.wxml b/packages/components/title/title.wxml
new file mode 100644
index 000000000..c9effebd8
--- /dev/null
+++ b/packages/components/title/title.wxml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+ {{content}}
+
+
+
+ {{content}}
+
+
+
+
+
+
diff --git a/packages/components/title/type.ts b/packages/components/title/type.ts
new file mode 100644
index 000000000..a2cfa1650
--- /dev/null
+++ b/packages/components/title/type.ts
@@ -0,0 +1,33 @@
+/* eslint-disable */
+
+/**
+ * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
+ * */
+
+import { TypographyEllipsis } from '../text/index';
+
+export interface TdTitleProps {
+ /**
+ * 段落内容
+ */
+ content?: {
+ type: StringConstructor;
+ value?: string;
+ };
+ /**
+ * 是否省略展示,可通过配置参数自定义省略操作的具体功能和样式
+ * @default false
+ */
+ ellipsis?: {
+ type: null;
+ value?: boolean | TypographyEllipsis;
+ };
+ /**
+ * 标题等级
+ * @default h1
+ */
+ level?: {
+ type: StringConstructor;
+ value?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
+ };
+}
diff --git a/packages/components/upload/README.md b/packages/components/upload/README.md
index d1e959bed..3b2d83e57 100644
--- a/packages/components/upload/README.md
+++ b/packages/components/upload/README.md
@@ -5,7 +5,7 @@ spline: form
isComponent: true
---
-


+


## 引入
全局引入,在 miniprogram 根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
diff --git a/packages/tdesign-miniprogram/example/app.json b/packages/tdesign-miniprogram/example/app.json
index 2a65cc32b..2660bc10b 100644
--- a/packages/tdesign-miniprogram/example/app.json
+++ b/packages/tdesign-miniprogram/example/app.json
@@ -97,132 +97,85 @@
"pages/config-provider/config-provider",
"pages/form/form",
"pages/segmented/segmented",
+ "pages/paragraph/paragraph",
"pages/chat-message/chat-message"
],
"subpackages": [
{
"root": "pages/chat-list/",
- "pages": [
- "chat-list"
- ]
+ "pages": ["chat-list"]
},
{
"root": "pages/chat-content/",
- "pages": [
- "chat-content"
- ]
+ "pages": ["chat-content"]
},
{
"root": "pages/chat-actionbar/",
- "pages": [
- "chat-actionbar"
- ]
+ "pages": ["chat-actionbar"]
},
{
"root": "pages/chat-loading/",
- "pages": [
- "chat-loading"
- ]
+ "pages": ["chat-loading"]
},
{
"root": "pages/chat-thinking/",
- "pages": [
- "chat-thinking"
- ]
+ "pages": ["chat-thinking"]
},
{
"root": "pages/attachments/",
- "pages": [
- "attachments"
- ]
+ "pages": ["attachments"]
},
{
"root": "pages/chat-markdown/",
- "pages": [
- "chat-markdown"
- ]
+ "pages": ["chat-markdown"]
},
{
"root": "pages/chat-sender/",
- "pages": [
- "chat-sender"
- ]
+ "pages": ["chat-sender"]
},
{
"root": "pages/side-bar/",
- "pages": [
- "side-bar",
- "base/index",
- "switch/index",
- "custom/index",
- "with-icon/index"
- ]
+ "pages": ["side-bar", "base/index", "switch/index", "custom/index", "with-icon/index"]
},
{
"root": "pages/action-sheet/",
- "pages": [
- "action-sheet"
- ]
+ "pages": ["action-sheet"]
},
{
"root": "pages/avatar/",
- "pages": [
- "avatar",
- "skyline/avatar"
- ]
+ "pages": ["avatar", "skyline/avatar"]
},
{
"root": "pages/calendar/",
- "pages": [
- "calendar"
- ]
+ "pages": ["calendar"]
},
{
"root": "pages/dialog/",
- "pages": [
- "dialog",
- "skyline/dialog"
- ]
+ "pages": ["dialog", "skyline/dialog"]
},
{
"root": "pages/picker/",
- "pages": [
- "picker",
- "skyline/picker"
- ]
+ "pages": ["picker", "skyline/picker"]
},
{
"root": "pages/rate/",
- "pages": [
- "rate"
- ]
+ "pages": ["rate"]
},
{
"root": "pages/swiper/",
- "pages": [
- "swiper",
- "skyline/swiper"
- ]
+ "pages": ["swiper", "skyline/swiper"]
},
{
"root": "pages/swipe-cell/",
- "pages": [
- "swipe-cell"
- ]
+ "pages": ["swipe-cell"]
},
{
"root": "pages/tree-select/",
- "pages": [
- "tree-select"
- ]
+ "pages": ["tree-select"]
},
{
"root": "pages/indexes/",
- "pages": [
- "indexes",
- "base/index",
- "custom/index"
- ]
+ "pages": ["indexes", "base/index", "custom/index"]
}
],
"themeLocation": "theme.json",
@@ -252,4 +205,4 @@
"sdkVersionEnd": "15.255.255"
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/tdesign-miniprogram/example/pages/home/data/base.ts b/packages/tdesign-miniprogram/example/pages/home/data/base.ts
index bfc463d5a..19a7b2cbc 100644
--- a/packages/tdesign-miniprogram/example/pages/home/data/base.ts
+++ b/packages/tdesign-miniprogram/example/pages/home/data/base.ts
@@ -39,10 +39,10 @@ const base = {
label: '布局',
path: '/pages/col/col',
},
- // {
- // name: 'Typography',
- // label: '字体',
- // },
+ {
+ name: 'Typography',
+ label: '排版',
+ },
],
};
diff --git a/packages/tdesign-miniprogram/example/project.config.json b/packages/tdesign-miniprogram/example/project.config.json
index 1663f49b0..a05bb5e32 100644
--- a/packages/tdesign-miniprogram/example/project.config.json
+++ b/packages/tdesign-miniprogram/example/project.config.json
@@ -136,6 +136,12 @@
"query": "",
"scene": null
},
+ {
+ "name": "layout",
+ "pathName": "pages/col/col",
+ "query": "",
+ "scene": null
+ },
{
"name": "config-provider",
"pathName": "pages/config-provider/config-provider",
@@ -430,6 +436,12 @@
"query": "",
"scene": null
},
+ {
+ "name": "typography",
+ "pathName": "pages/paragraph/paragraph",
+ "query": "",
+ "scene": null
+ },
{
"name": "upload",
"pathName": "pages/upload/upload",
diff --git a/packages/tdesign-miniprogram/site/docs/overview.en-US.md b/packages/tdesign-miniprogram/site/docs/overview.en-US.md
index 952b56dbc..2dfc9d038 100644
--- a/packages/tdesign-miniprogram/site/docs/overview.en-US.md
+++ b/packages/tdesign-miniprogram/site/docs/overview.en-US.md
@@ -54,6 +54,14 @@ spline: explain
Link
+
+
Navigation8
diff --git a/packages/tdesign-miniprogram/site/docs/overview.md b/packages/tdesign-miniprogram/site/docs/overview.md
index 1c988145c..2cf4ea685 100644
--- a/packages/tdesign-miniprogram/site/docs/overview.md
+++ b/packages/tdesign-miniprogram/site/docs/overview.md
@@ -4,7 +4,7 @@ description: 将根据业务实践持续新增组件类型,敬请留意组件
spline: explain
---
-基础6
+基础7
导航8
diff --git a/packages/tdesign-miniprogram/site/plugins/plugin-tdoc/component.vue b/packages/tdesign-miniprogram/site/plugins/plugin-tdoc/component.vue
index 45fb4b2df..7db3c9d81 100644
--- a/packages/tdesign-miniprogram/site/plugins/plugin-tdoc/component.vue
+++ b/packages/tdesign-miniprogram/site/plugins/plugin-tdoc/component.vue
@@ -71,8 +71,8 @@ export default defineComponent({
},
name() {
const { path } = this.$route;
- const name = path.slice(path.lastIndexOf('/') + 1);
- return name.replace('layout', 'col');
+ const nameMap: Record = { layout: 'col', typography: 'paragraph' };
+ return path.slice(path.lastIndexOf('/') + 1).replace(/layout|typography/, (m) => nameMap[m]);
},
liveHost() {
const { host } = window.location;
diff --git a/packages/tdesign-miniprogram/site/public/assets/qrcode/paragraph.png b/packages/tdesign-miniprogram/site/public/assets/qrcode/paragraph.png
new file mode 100644
index 000000000..7230f8814
Binary files /dev/null and b/packages/tdesign-miniprogram/site/public/assets/qrcode/paragraph.png differ
diff --git a/packages/tdesign-miniprogram/site/site.config.mjs b/packages/tdesign-miniprogram/site/site.config.mjs
index 7bc509531..88149b784 100644
--- a/packages/tdesign-miniprogram/site/site.config.mjs
+++ b/packages/tdesign-miniprogram/site/site.config.mjs
@@ -160,6 +160,14 @@ export const docs = [
path: '/miniprogram/components/link',
component: () => import('@/link/README.md'),
},
+ {
+ title: 'Typography 排版',
+ titleEn: 'Typography',
+ name: 'typography',
+ meta: { docType: 'base' },
+ path: '/miniprogram/components/typography',
+ component: () => import('@/paragraph/README.md'),
+ },
],
},
{
diff --git a/packages/tdesign-miniprogram/test/scripts/coverage-badge.js b/packages/tdesign-miniprogram/test/scripts/coverage-badge.js
index 362f4043f..e543d8d87 100644
--- a/packages/tdesign-miniprogram/test/scripts/coverage-badge.js
+++ b/packages/tdesign-miniprogram/test/scripts/coverage-badge.js
@@ -19,6 +19,7 @@ const RELATED_MAP = {
'tab-bar': 'tab-bar-item',
tabs: 'tab-panel',
tag: 'check-tag',
+ paragraph: ['paragraph', 'text', 'title'],
};
/**
@@ -112,11 +113,17 @@ ans.forEach((items, component) => {
// 处理相关组件的合并覆盖率
if (component in RELATED_MAP) {
- const related = ans.get(RELATED_MAP[component]);
- if (related) {
- const denominator = item.total + related[type].total;
- val = denominator === 0 ? '100' : (((item.covered + related[type].covered) / denominator) * 100).toFixed(0);
- }
+ const relatedKeys = Array.isArray(RELATED_MAP[component]) ? RELATED_MAP[component] : [RELATED_MAP[component]];
+ let totalSum = item.total;
+ let coveredSum = item.covered;
+ relatedKeys.forEach((key) => {
+ const related = ans.get(key);
+ if (related) {
+ totalSum += related[type].total;
+ coveredSum += related[type].covered;
+ }
+ });
+ val = totalSum === 0 ? '100' : ((coveredSum / totalSum) * 100).toFixed(0);
}
const message = Number.isNaN(val) ? '0' : val;