From 69e2ec8580c14eee69f6550ae10116a87d7d9eb4 Mon Sep 17 00:00:00 2001 From: duenyang <377153400@qq.com> Date: Tue, 25 Jun 2024 16:30:20 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(tooltip):=20add=20tooltip=20?= =?UTF-8?q?=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 60 --------- package.json | 1 - script/plugin-tdoc/md-to-wc.mjs | 26 +++- site/sidebar.config.ts | 6 + src/index.ts | 3 +- src/popup/popup.tsx | 1 - src/tooltip/README.md | 53 ++++++++ src/tooltip/_example/arrow.tsx | 10 ++ src/tooltip/_example/base.tsx | 203 ++++++++++++++++++++++++++++++ src/tooltip/_example/duration.tsx | 60 +++++++++ src/tooltip/_example/no-arrow.tsx | 10 ++ src/tooltip/_example/theme.tsx | 28 +++++ src/tooltip/_example/trigger.tsx | 23 ++++ src/tooltip/index.ts | 9 ++ src/tooltip/style/index.ts | 10 ++ src/tooltip/tooltip.tsx | 103 +++++++++++++++ src/tooltip/type.ts | 80 ++++++++++++ 17 files changed, 622 insertions(+), 64 deletions(-) create mode 100644 src/tooltip/README.md create mode 100644 src/tooltip/_example/arrow.tsx create mode 100644 src/tooltip/_example/base.tsx create mode 100644 src/tooltip/_example/duration.tsx create mode 100644 src/tooltip/_example/no-arrow.tsx create mode 100644 src/tooltip/_example/theme.tsx create mode 100644 src/tooltip/_example/trigger.tsx create mode 100644 src/tooltip/index.ts create mode 100644 src/tooltip/style/index.ts create mode 100644 src/tooltip/tooltip.tsx create mode 100644 src/tooltip/type.ts diff --git a/package-lock.json b/package-lock.json index d75f40d..270aac4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "MIT", "dependencies": { "@babel/runtime": "^7.24.7", - "@omiu/transition": "^0.0.17", "@popperjs/core": "^2.11.8", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", @@ -2550,14 +2549,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://mirrors.tencent.com/npm/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", - "engines": { - "node": ">=10" - } - }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -3165,24 +3156,6 @@ "node": ">= 8" } }, - "node_modules/@omiu/common": { - "version": "0.0.17", - "resolved": "https://mirrors.tencent.com/npm/@omiu/common/-/common-0.0.17.tgz", - "integrity": "sha512-OrT9GS5QcKGTWs+EtKLL70Fs/FXKgABuR7Qni/5s4vk4DfTJwRTnpYfnRwwYsbDM7CMYBxdXG59OHis+SKMpTA==", - "dependencies": { - "@ctrl/tinycolor": "^3.4.0" - } - }, - "node_modules/@omiu/transition": { - "version": "0.0.17", - "resolved": "https://mirrors.tencent.com/npm/@omiu/transition/-/transition-0.0.17.tgz", - "integrity": "sha512-+lNj7A4ReFngvir4WpOLsZWoC8XoJ5UIY9SlJ/AlRXyjdKGelOTNIVQBsSoVTT1uO4U70nhozrP4p/KWd1kKOQ==", - "dependencies": { - "@omiu/common": "latest", - "dready": "^0.0.3", - "omi": "latest" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -5960,11 +5933,6 @@ "node": ">=8" } }, - "node_modules/dready": { - "version": "0.0.3", - "resolved": "https://mirrors.tencent.com/npm/dready/-/dready-0.0.3.tgz", - "integrity": "sha512-x/c39NQ6QUAoXtbPB/KkrhXKqF5Cmzt1+td+LyjLyiIOZF27yP7Jdwoni+qHgAjqgokmdDX/JWQMKKRCc8m86Q==" - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -15885,11 +15853,6 @@ } } }, - "@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://mirrors.tencent.com/npm/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" - }, "@esbuild/android-arm": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", @@ -16234,24 +16197,6 @@ "fastq": "^1.6.0" } }, - "@omiu/common": { - "version": "0.0.17", - "resolved": "https://mirrors.tencent.com/npm/@omiu/common/-/common-0.0.17.tgz", - "integrity": "sha512-OrT9GS5QcKGTWs+EtKLL70Fs/FXKgABuR7Qni/5s4vk4DfTJwRTnpYfnRwwYsbDM7CMYBxdXG59OHis+SKMpTA==", - "requires": { - "@ctrl/tinycolor": "^3.4.0" - } - }, - "@omiu/transition": { - "version": "0.0.17", - "resolved": "https://mirrors.tencent.com/npm/@omiu/transition/-/transition-0.0.17.tgz", - "integrity": "sha512-+lNj7A4ReFngvir4WpOLsZWoC8XoJ5UIY9SlJ/AlRXyjdKGelOTNIVQBsSoVTT1uO4U70nhozrP4p/KWd1kKOQ==", - "requires": { - "@omiu/common": "latest", - "dready": "^0.0.3", - "omi": "latest" - } - }, "@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -18215,11 +18160,6 @@ } } }, - "dready": { - "version": "0.0.3", - "resolved": "https://mirrors.tencent.com/npm/dready/-/dready-0.0.3.tgz", - "integrity": "sha512-x/c39NQ6QUAoXtbPB/KkrhXKqF5Cmzt1+td+LyjLyiIOZF27yP7Jdwoni+qHgAjqgokmdDX/JWQMKKRCc8m86Q==" - }, "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", diff --git a/package.json b/package.json index 268a712..2596de2 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ }, "dependencies": { "@babel/runtime": "^7.24.7", - "@omiu/transition": "^0.0.17", "@popperjs/core": "^2.11.8", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", diff --git a/script/plugin-tdoc/md-to-wc.mjs b/script/plugin-tdoc/md-to-wc.mjs index 6c320c9..0289584 100644 --- a/script/plugin-tdoc/md-to-wc.mjs +++ b/script/plugin-tdoc/md-to-wc.mjs @@ -2,6 +2,7 @@ import esbuild from 'esbuild'; import fs from 'fs'; import matter from 'gray-matter'; import { spawn } from 'node:child_process'; +import path from 'path'; // import camelCase from 'camelcase'; // import { compileUsage } from '../../src/_common/docs/compile'; @@ -80,6 +81,8 @@ export default async function mdToReact(options) { const tab = signal(query.get('tab') || 'demo'); const tabRef = signal({}); + const lastUpdated = tab === 'design' ? ${mdSegment.designDocLastUpdated} : ${mdSegment.lastUpdated}; + effect(() => { tabRef.value?.addEventListener?.('change', (event) => { tab.value = event.detail; @@ -108,11 +111,14 @@ export default async function mdToReact(options) {
${mdSegment.apiMd}
+
+ ${mdSegment.designMd} +
) :
${mdSegment.docMd}
}
- +
) @@ -152,6 +158,7 @@ async function customRender({ source, file, md }) { apiFlag: /#+\s*API/, docClass: '', lastUpdated, + designDocLastUpdated: lastUpdated, ...data, }; @@ -210,5 +217,22 @@ async function customRender({ source, file, md }) { `${pageData.toc ? '[toc]\n' : ''}${content.replace(//g, '')}`, ).html; } + + // 设计指南内容 不展示 design Tab 则不解析 + if (pageData.isComponent && pageData.tdDocTabs.some((item) => item.tab === 'design')) { + const designDocPath = path.resolve(__dirname, `../../src/_common/docs/web/design/${componentName}.md`); + + if (fs.existsSync(designDocPath)) { + const designDocLastUpdated = + (await getGitTimestamp(designDocPath)) || Math.round(fs.statSync(designDocPath).mtimeMs); + mdSegment.designDocLastUpdated = designDocLastUpdated; + + const designMd = fs.readFileSync(designDocPath, 'utf-8'); + mdSegment.designMd = md.render.call(md, `${pageData.toc ? '[toc]\n' : ''}${designMd}`).html; + } else { + console.log(`[vite-plugin-tdoc]: 未找到 ${designDocPath} 文件`); + } + } + return mdSegment; } diff --git a/site/sidebar.config.ts b/site/sidebar.config.ts index 87c90ce..d139d0e 100644 --- a/site/sidebar.config.ts +++ b/site/sidebar.config.ts @@ -148,6 +148,12 @@ export default [ path: '/components/image', component: () => import('tdesign-web-components/image/README.md'), }, + { + title: 'Tooltip 文字提示', + name: 'tooltip', + path: '/components/tooltip', + component: () => import('tdesign-web-components/tooltip/README.md'), + }, ], }, { diff --git a/src/index.ts b/src/index.ts index cfe4768..3fe8e78 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ export * from './icon'; export * from './image'; export * from './input'; export * from './popup'; -export * from './textarea'; export * from './space'; export * from './switch'; +export * from './textarea'; +export * from './tooltip'; diff --git a/src/popup/popup.tsx b/src/popup/popup.tsx index 193045f..99b1d34 100644 --- a/src/popup/popup.tsx +++ b/src/popup/popup.tsx @@ -1,6 +1,5 @@ import 'omi-transition'; -// import '@omiu/transition'; import { createPopper } from '@popperjs/core'; import debounce from 'lodash/debounce'; import { Component, createRef, OmiProps, tag } from 'omi'; diff --git a/src/tooltip/README.md b/src/tooltip/README.md new file mode 100644 index 0000000..bdc8d0a --- /dev/null +++ b/src/tooltip/README.md @@ -0,0 +1,53 @@ +--- +title: Tooltip 文字提示 +description: 用于文字提示的气泡框。 +isComponent: true +usage: { title: '', description: '' } +spline: data +--- + +### 基础用法 + +{{ base }} + +### 带箭头的文字提示 + +带箭头的文字提示有较明确的指向性。常用于有多个需要提示的信息并列放置时,对某个具体信息进行提示。 + +{{ arrow }} + +### 不带箭头的文字提示 + +不带箭头的文字提示没有明确指向性。常用于不需要针对性提示的场景中。 + +{{ no-arrow }} + +### 带主题色的文字提示 + +提供浅灰色、蓝色、绿色、红色、黄色主题的文字提示。 + +{{ theme }} + +### 不同触发方式的文字提示 + +支持常见元素事件触发文字提示。 + +{{ trigger }} + +### 定时消失 + +{{ duration }} + + +## API +### Tooltip Props + +名称 | 类型 | 默认值 | 说明 | 必传 +-- | -- | -- | -- | -- +delay | Number | - | 【议案讨论中】延迟出现提示,用于异步加载提示信息需要延迟显示的业务场景下 | N +destroyOnClose | Boolean | true | 是否在关闭浮层时销毁浮层 | N +duration | Number | - | 用于设置提示默认显示多长时间之后消失,初始第一次有效,单位:毫秒 | N +placement | String | top | 浮层出现位置。TS 类型:`PopupPlacement`,[Popup API Documents](./popup?tab=api)。[详细类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/tooltip/type.ts) | N +showArrow | Boolean | true | 是否显示浮层箭头 | N +theme | String | default | 文字提示风格。可选项:default/primary/success/danger/warning/light | N +`PopupProps` | \- | - | 继承 `PopupProps` 中的全部 API | N \ No newline at end of file diff --git a/src/tooltip/_example/arrow.tsx b/src/tooltip/_example/arrow.tsx new file mode 100644 index 0000000..04b5100 --- /dev/null +++ b/src/tooltip/_example/arrow.tsx @@ -0,0 +1,10 @@ +import 'tdesign-web-components/button'; +import 'tdesign-web-components/tooltip'; + +export default function BasicUsage() { + return ( + + 默认文字提示 + + ); +} diff --git a/src/tooltip/_example/base.tsx b/src/tooltip/_example/base.tsx new file mode 100644 index 0000000..5d8ac95 --- /dev/null +++ b/src/tooltip/_example/base.tsx @@ -0,0 +1,203 @@ +import 'tdesign-web-components/button'; +import 'tdesign-web-components/tooltip'; + +const styles = { + container: { + margin: '0 auto', + width: '500px', + height: '260px', + position: 'relative', + }, + placementTop: { + position: 'absolute', + top: '0', + left: '42%', + }, + placementTopLeft: { + position: 'absolute', + top: '0', + left: '70px', + }, + placementTopRight: { + position: 'absolute', + top: '0', + right: '70px', + }, + placementBottom: { + position: 'absolute', + bottom: '0', + left: '42%', + }, + placementBottomLeft: { + position: 'absolute', + bottom: '0', + left: '70px', + width: '120px', + }, + placementBottomRight: { + position: 'absolute', + bottom: '0', + right: '70px', + }, + placementLeft: { + position: 'absolute', + left: '0', + top: '42%', + }, + placementLeftTop: { + position: 'absolute', + left: '0', + top: '50px', + }, + placementLeftBottom: { + position: 'absolute', + left: '0', + bottom: '50px', + }, + placementRight: { + position: 'absolute', + right: '0', + top: '42%', + }, + placementRightTop: { + position: 'absolute', + right: '0', + top: '50px', + }, + placementRightBottom: { + position: 'absolute', + right: '0', + bottom: '50px', + }, +}; + +export default function Placements() { + return ( +
+ + top + + + top-left + + + top-right + + + bottom + + + bottom-left + + + bottom-right + + + left + + + left-top + + + left-bottom + + + right + + + right-top + + + right-bottom + +
+ ); +} diff --git a/src/tooltip/_example/duration.tsx b/src/tooltip/_example/duration.tsx new file mode 100644 index 0000000..aee0d1a --- /dev/null +++ b/src/tooltip/_example/duration.tsx @@ -0,0 +1,60 @@ +import 'tdesign-web-components/tooltip'; +import 'tdesign-web-components/button'; + +import { Component } from 'omi'; + +export default class Placements extends Component { + timer: NodeJS.Timeout; + + reset = true; + + count = 5; + + duration = 5000; + + setTimer = () => { + this.timer = setInterval(() => { + this.count -= 1; + if (this.count <= 0) { + clearInterval(this.timer); + this.reset = true; + this.duration = 0; + } + this.update(); + }, 1000); + }; + + onResetClick = () => { + this.reset = false; + this.count = 5; + this.duration = 5000; + + this.update(); + + clearInterval(this.timer); + this.setTimer(); + }; + + install() { + this.setTimer(); + } + + uninstall() { + clearInterval(this.timer); + } + + render() { + return ( + <> + + 定时消失 + + {this.reset && ( + + 点击再次查看 + + )} + + ); + } +} diff --git a/src/tooltip/_example/no-arrow.tsx b/src/tooltip/_example/no-arrow.tsx new file mode 100644 index 0000000..ef34810 --- /dev/null +++ b/src/tooltip/_example/no-arrow.tsx @@ -0,0 +1,10 @@ +import 'tdesign-web-components/button'; +import 'tdesign-web-components/tooltip'; + +export default function BasicUsage() { + return ( + + 不带箭头等文字提示 + + ); +} diff --git a/src/tooltip/_example/theme.tsx b/src/tooltip/_example/theme.tsx new file mode 100644 index 0000000..9ed0188 --- /dev/null +++ b/src/tooltip/_example/theme.tsx @@ -0,0 +1,28 @@ +import 'tdesign-web-components/button'; +import 'tdesign-web-components/tooltip'; +import 'tdesign-web-components/space'; + +export default function Cumstomize() { + return ( + + + default + + + primary + + + success + + + danger + + + warning + + + light + + + ); +} diff --git a/src/tooltip/_example/trigger.tsx b/src/tooltip/_example/trigger.tsx new file mode 100644 index 0000000..0c5534d --- /dev/null +++ b/src/tooltip/_example/trigger.tsx @@ -0,0 +1,23 @@ +import 'tdesign-web-components/button'; +import 'tdesign-web-components/tooltip'; +import 'tdesign-web-components/space'; +import 'tdesign-web-components/input'; + +export default function Cumstomize() { + return ( + + + 悬浮时触发(默认) + + + + + + 点击时触发 + + + 右击时触发 + + + ); +} diff --git a/src/tooltip/index.ts b/src/tooltip/index.ts new file mode 100644 index 0000000..a0c91a2 --- /dev/null +++ b/src/tooltip/index.ts @@ -0,0 +1,9 @@ +import './style/index.js'; + +import _Tooltip from './tooltip'; + +export type { TooltipProps } from './tooltip'; +export * from './type'; + +export const Tooltip = _Tooltip; +export default Tooltip; diff --git a/src/tooltip/style/index.ts b/src/tooltip/style/index.ts new file mode 100644 index 0000000..abbb7ee --- /dev/null +++ b/src/tooltip/style/index.ts @@ -0,0 +1,10 @@ +import { css, globalCSS } from 'omi'; + +// 为了做主题切换 +import styles from '../../_common/style/web/components/tooltip/_index.less'; + +export const styleSheet = css` + ${styles} +`; + +globalCSS(styleSheet); diff --git a/src/tooltip/tooltip.tsx b/src/tooltip/tooltip.tsx new file mode 100644 index 0000000..ed0621e --- /dev/null +++ b/src/tooltip/tooltip.tsx @@ -0,0 +1,103 @@ +import '../popup'; + +import { Component, createRef, OmiProps, tag } from 'omi'; + +import classname, { getClassPrefix } from '../_util/classname'; +import { type PopupVisibleChangeContext } from '../popup'; +import { TdTooltipProps } from './type'; + +export type TooltipProps = TdTooltipProps; + +export const tooltipDefaultProps: TooltipProps = { + destroyOnClose: true, + placement: 'top', + showArrow: true, + theme: 'default', + duration: 0, +}; + +@tag('t-tooltip') +export default class Tooltip extends Component { + static defaultProps = tooltipDefaultProps; + + popupRef = createRef(); + + timerRef = createRef(); + + timeUp = false; + + popupVisible = undefined; + + handleVisibleChange(visible: boolean, { e, trigger }: PopupVisibleChangeContext) { + this.props?.onVisibleChange?.(visible, { e, trigger }); + } + + countDown(props: TooltipProps) { + if (props.duration !== 0 && !this.timeUp) { + this.timeUp = true; + this.popupVisible = true; + this.update(); + clearTimeout(this.timerRef.current as number); + this.timerRef.current = window.setTimeout(() => { + this.popupVisible = undefined; + this.timeUp = false; + this.update(); + }, props.duration); + } + } + + receiveProps(props: TooltipProps, old: TooltipProps) { + if (props.duration !== old.duration) { + this.countDown(props); + } + + return true; + } + + installed(): void { + this.countDown(this.props); + } + + uninstall(): void { + if (this.timerRef.current) { + clearTimeout(this.timerRef.current as number); + } + } + + render(props: TooltipProps | OmiProps): JSX.Element { + const { destroyOnClose, showArrow, theme, placement, overlayClassName, ignoreAttributes, ...restProps } = props; + const classPrefix = getClassPrefix(); + const toolTipClass = classname( + `${classPrefix}-tooltip`, + { + [`${classPrefix}-tooltip--${theme}`]: theme, + }, + overlayClassName, + ); + + delete restProps.onVisibleChange; + delete restProps.duration; + delete restProps.children; + + if (ignoreAttributes?.length > 0) { + ignoreAttributes.forEach((attr) => { + this.removeAttribute(attr); + }); + } + + return ( + + + + ); + } +} diff --git a/src/tooltip/type.ts b/src/tooltip/type.ts new file mode 100644 index 0000000..07431b5 --- /dev/null +++ b/src/tooltip/type.ts @@ -0,0 +1,80 @@ +/* eslint-disable */ + +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { PopupPlacement } from '../popup'; +import { TdPopupProps } from '../popup'; +import { Styles, TNode } from '../common'; + +export interface TdTooltipProps extends TdPopupProps { + /** + * 【议案讨论中】延迟出现提示,用于异步加载提示信息需要延迟显示的业务场景下 + */ + delay?: number; + /** + * 是否在关闭浮层时销毁浮层 + * @default true + */ + destroyOnClose?: boolean; + /** + * 用于设置提示默认显示多长时间之后消失,初始第一次有效,单位:毫秒 + */ + duration?: number; + /** + * 浮层出现位置 + * @default top + */ + placement?: PopupPlacement; + /** + * 是否显示浮层箭头 + * @default true + */ + showArrow?: boolean; + /** + * 文字提示风格 + * @default default + */ + theme?: 'default' | 'primary' | 'success' | 'danger' | 'warning' | 'light'; + /** + * 在host标签上忽略的属性 + * @default [] + */ + ignoreAttributes?: string[]; +} + +export interface TdTooltipLiteProps { + /** + * 触发元素,同 triggerElement + */ + children?: TNode; + /** + * 文字提示内容 + */ + content?: TNode; + /** + * 提示浮层出现的位置 + * @default top + */ + placement?: 'top' | 'bottom' | 'mouse'; + /** + * 是否显示箭头 + * @default true + */ + showArrow?: boolean; + /** + * 文字提示浮层是否需要阴影 + * @default true + */ + showShadow?: boolean; + /** + * 组件风格,有亮色模式和暗色模式两种 + * @default default + */ + theme?: 'light' | 'default'; + /** + * 触发元素 + */ + triggerElement?: TNode; +} From 079fceae05225aa18952beaa0fd297418c1116a0 Mon Sep 17 00:00:00 2001 From: duenyang <377153400@qq.com> Date: Tue, 25 Jun 2024 16:32:51 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat(tooltip):=20add=20tooltip=20?= =?UTF-8?q?=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/button/button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/button/button.tsx b/src/button/button.tsx index 2d1ff59..640857b 100644 --- a/src/button/button.tsx +++ b/src/button/button.tsx @@ -63,7 +63,7 @@ export default class Button extends Component { } let iconNode = icon; - if (loading) iconNode = ; + if (loading) iconNode = ; const Tag = this.tag as string; return (