Skip to content

Commit

Permalink
feat(components): 新增WordBalloon文字气泡组件
Browse files Browse the repository at this point in the history
Closes #23
  • Loading branch information
mengxinssfd committed Jul 7, 2023
1 parent ce1e027 commit 1444b7b
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 3 deletions.
5 changes: 4 additions & 1 deletion packages/components/src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
@import './icon';
@import './space';
@import './message';
@import './divider';@import './drawer';@import './resizer';
@import './divider';
@import './drawer';
@import './resizer';
@import './word-balloon';
3 changes: 2 additions & 1 deletion packages/components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export * from './space';
export * from './message';
export * from './divider';
export * from './drawer';
export { PLACEMENTS } from '@pkg/shared';
export { PLACEMENTS, PLACEMENTS_8, PLACEMENTS_12 } from '@pkg/shared';
export * from './resizer';
export * from './word-balloon';
54 changes: 54 additions & 0 deletions packages/components/src/word-balloon/WordBalloon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import type { WordBalloonProps } from './word-balloon.types';
import { getComponentClass } from '@pkg/shared';
import { RequiredPart } from '@tool-pack/types';
import { getClassNames } from '@tool-pack/basic';

const rootName = getComponentClass('word-balloon');

export const WordBalloon: React.FC<WordBalloonProps> = React.forwardRef<
HTMLDivElement,
WordBalloonProps
>((props, ref) => {
const {
children,
placement,
showArrow,
background,
style,
contentStyle,
arrowStyle,
...rest
} = props as RequiredPart<WordBalloonProps, keyof typeof defaultProps>;
return (
<div
{...rest}
ref={ref}
style={
{
...style,
'--t-word-balloon-bg': background || '',
} as React.CSSProperties
}
className={getClassNames(rootName, `${rootName}--${placement}`)}>
<div className={`${rootName}__content`} style={contentStyle}>
{children}
</div>
{showArrow && (
<div className={`${rootName}__arrow`} style={arrowStyle}>
<svg viewBox="-8 -5.5 16 5.515">
<path d="M8-5.5A4 4 180 005.1716-4.3284L1.4142-.5711A2 2 180 01-1.4142-.5711L-5.1716-4.3284A4 4 180 00-8-5.5Z" />
</svg>
</div>
)}
</div>
);
});

const defaultProps = {
placement: 'bottom',
showArrow: true,
} satisfies Partial<WordBalloonProps>;
WordBalloon.defaultProps = defaultProps;

WordBalloon.displayName = 'WordBalloon';
53 changes: 53 additions & 0 deletions packages/components/src/word-balloon/demo/basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* title: 基础用法
*/

import React from 'react';
import { WordBalloon, Space, PLACEMENTS_12 } from '@tool-pack/react-ui';

const App: React.FC = () => {
return (
<Space gap={30} vertical>
<WordBalloon
placement="right-start"
background={'#b8cfef'}
style={{ alignSelf: 'flex-end', maxWidth: '50%' }}>
{'你是谁? 你是谁? 你是谁?\n'.repeat(5)}
</WordBalloon>
<WordBalloon
placement="left-start"
background={'#9eec9e'}
style={{ alignSelf: 'flex-start', maxWidth: '50%' }}>
{'你好,我是ChatGPT,我是ChatGPT,我真的是ChatGPT。\n'.repeat(5)}
</WordBalloon>

<WordBalloon>
<p>
道可道,非常道;名可名,非常名。无名天地之始,有名万物之母。故常无欲,以观其妙;常有欲,以观其徼(jiào)。此两者同出而异名,同谓之玄,玄之又玄,众妙之门。
</p>
<p>
天下皆知美之为美,斯恶(è)已;皆知善之为善,斯不善已。故有无相生,难易相成,长短相较,高下相倾,音声相和(hè),前后相随。是以圣人处无为之事,行不言之教,万物作焉而不辞,生而不有,为而不恃,功成而弗居。夫(fú)唯弗居,是以不去。
</p>
<p>
不尚贤,使民不争;不贵难得之货,使民不为盗;不见(xiàn)可欲,使民心不乱。是以圣人之治,虚其心,实其腹;弱其志,强其骨。常使民无知无欲,使夫(fú)智者不敢为也。为无为,则无不治。
</p>
</WordBalloon>

<Space gap={30}>
{PLACEMENTS_12.map((p) => (
<WordBalloon key={p} placement={p} background={'#b8cfef'}>
<div style={{ width: '80px' }}>{p}</div>
</WordBalloon>
))}
</Space>

<WordBalloon
background={'linear-gradient(225deg,#ffdee9,#b5fffc)'}
showArrow={false}>
{'无箭头 '.repeat(5)}
</WordBalloon>
</Space>
);
};

export default App;
110 changes: 110 additions & 0 deletions packages/components/src/word-balloon/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
@import '../scss.variable';

$r: '#{$prefix}word-balloon';

.#{$r} {
--t-word-balloon-bg: var(--t-bg-color);
--t-word-balloon-arrow-offset: calc(var(--t-radius) + 2px);

position: relative;
&__content {
padding: var(--t-radius) 14px;
min-width: 32px;
min-height: 32px;
border-radius: var(--t-radius);
white-space: pre-wrap;
background: var(--t-word-balloon-bg);
box-shadow: 0 6px 16px 0 rgb(0 0 0 / 8%), 0 3px 6px -4px rgb(0 0 0 / 12%),
0 9px 28px 8px rgb(0 0 0 / 5%);
word-wrap: break-word;
box-sizing: border-box;
}

$arrow-height: 5.51px;
&__arrow {
position: absolute;
width: 16px;
height: $arrow-height;
font-size: 0;
svg {
fill: var(--t-word-balloon-bg);
}
}
&--top,
&--bottom {
.#{$r}__arrow {
right: 0;
left: 0;
margin: auto;
}
&-start {
.#{$r}__arrow {
left: var(--t-word-balloon-arrow-offset);
}
}
&-end {
.#{$r}__arrow {
right: var(--t-word-balloon-arrow-offset);
}
}
}
&--right,
&--left {
.#{$r}__arrow {
top: 0;
bottom: 0;
margin: auto;
}
&-start {
.#{$r}__arrow {
top: var(--t-word-balloon-arrow-offset);
}
}
&-end {
.#{$r}__arrow {
bottom: var(--t-word-balloon-arrow-offset);
}
}
}
&--top {
&,
&-start,
&-end {
.#{$r}__arrow {
bottom: 100%;
transform: rotate(180deg);
}
}
}
&--right {
&,
&-start,
&-end {
.#{$r}__arrow {
left: 100%;
margin-left: -$arrow-height;
transform: rotate(-90deg);
}
}
}
&--bottom {
&,
&-start,
&-end {
.#{$r}__arrow {
top: 100%;
}
}
}
&--left {
&,
&-start,
&-end {
.#{$r}__arrow {
right: 100%;
margin-right: -$arrow-height;
transform: rotate(90deg);
}
}
}
}
2 changes: 2 additions & 0 deletions packages/components/src/word-balloon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type { WordBalloonProps } from './word-balloon.types';
export * from './WordBalloon';
30 changes: 30 additions & 0 deletions packages/components/src/word-balloon/index.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
category: Components
title: WordBalloon 文字气泡
atomId: WordBalloon
demo:
cols: 2
group:
title: 通用
---

WordBalloon 文字气泡/文字气球(像一个飘在天上的 🎈),可用在各种弹出层信息展示,也可以用于类似移动端的聊天气泡。

## 代码演示

<!-- prettier-ignore -->
<code src="./demo/basic.tsx"></code>

## API

WordBalloon 的属性说明如下:

| 属性 | 说明 | 类型 | 默认值 | 版本 |
| ------------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ---- |
| contentStyle | 气泡内容元素的行内样式 | React.CSSProperties | -- | -- |
| arrowStyle | 气泡箭头元素的行内样式 | React.CSSProperties | -- | -- |
| background | 气泡内容和箭头的背景色 | React.CSSProperties['background'] | -- | -- |
| showArrow | 是否显示箭头 | boolean | true | -- |
| placement | 箭头对应气泡的位置<br /><div style="width:200px"></div> | 'top' \| 'right' \| 'bottom' \| 'left' \| 'top-start' \| 'top-end' \| 'right-start' \| 'right-end' \| 'bottom-start' \| 'bottom-end' \| 'left-start' \| 'left-end' | 'bottom' | -- |

组件根元素支持原生 HTML 的其他所有属性。。
10 changes: 10 additions & 0 deletions packages/components/src/word-balloon/word-balloon.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react';
import { PLACEMENTS_12 } from '@pkg/shared';

export type WordBalloonProps = React.HTMLAttributes<HTMLElement> & {
placement?: (typeof PLACEMENTS_12)[number];
contentStyle?: React.CSSProperties;
arrowStyle?: React.CSSProperties;
background?: React.CSSProperties['background'];
showArrow?: boolean;
};
22 changes: 21 additions & 1 deletion packages/shared/src/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,24 @@ export const CLASS_SIZE_SM = `${UI_PREFIX}--size-sm`;
export const CLASS_SIZE_M = `${UI_PREFIX}--size-m`;
export const CLASS_SIZE_LG = `${UI_PREFIX}--size-lg`;
export const Z_INDEX = 1000;
export const PLACEMENTS = ['top', 'bottom', 'left', 'right'] as const;
export const PLACEMENTS = ['top', 'right', 'bottom', 'left'] as const;
// 8方位
export const PLACEMENTS_8 = [
...PLACEMENTS,
'top-left',
'top-right',
'bottom-left',
'bottom-right',
] as const;
// 12方位
export const PLACEMENTS_12 = [
...PLACEMENTS,
'top-start',
'top-end',
'right-start',
'right-end',
'bottom-start',
'bottom-end',
'left-start',
'left-end',
] as const;

0 comments on commit 1444b7b

Please sign in to comment.