@yorkjs/hive-ui 2.2.3 → 2.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
@import '../../styles/mixin.styl'
|
|
2
|
+
@import '../../styles/variable.styl'
|
|
3
|
+
|
|
4
|
+
.rich-text-editor
|
|
5
|
+
display flex
|
|
6
|
+
flex-direction column
|
|
7
|
+
gap 15PX
|
|
8
|
+
|
|
9
|
+
:global
|
|
10
|
+
taro-textarea-core
|
|
11
|
+
width 100%
|
|
12
|
+
.auto-height
|
|
13
|
+
height auto
|
|
14
|
+
min-height 80PX
|
|
15
|
+
background-color transparent
|
|
16
|
+
|
|
17
|
+
.block
|
|
18
|
+
position relative
|
|
19
|
+
border-radius 10PX
|
|
20
|
+
halfBorder(top right bottom left, var(--lineBorder), 10PX)
|
|
21
|
+
|
|
22
|
+
.delete-btn
|
|
23
|
+
position absolute
|
|
24
|
+
top -6PX
|
|
25
|
+
right -6PX
|
|
26
|
+
width 16PX
|
|
27
|
+
height 16PX
|
|
28
|
+
line-height 16PX
|
|
29
|
+
text-align center
|
|
30
|
+
border-radius 50%
|
|
31
|
+
z-index 2
|
|
32
|
+
|
|
33
|
+
.delete-icon
|
|
34
|
+
position absolute
|
|
35
|
+
top 50%
|
|
36
|
+
left 50%
|
|
37
|
+
transform translate(-50%, -50%)
|
|
38
|
+
line-height 1
|
|
39
|
+
display block
|
|
40
|
+
|
|
41
|
+
.text-block
|
|
42
|
+
padding 15PX 15PX 6PX
|
|
43
|
+
|
|
44
|
+
.editor-textarea
|
|
45
|
+
:global(.taro-textarea)
|
|
46
|
+
width 100%
|
|
47
|
+
font-size 14PX
|
|
48
|
+
line-height 1.6
|
|
49
|
+
color var(--textTitle)
|
|
50
|
+
|
|
51
|
+
&.is-align-left
|
|
52
|
+
:global(.taro-textarea)
|
|
53
|
+
text-align left !important
|
|
54
|
+
&.is-align-center
|
|
55
|
+
:global(.taro-textarea)
|
|
56
|
+
text-align center !important
|
|
57
|
+
&.is-align-right
|
|
58
|
+
:global(.taro-textarea)
|
|
59
|
+
text-align right !important
|
|
60
|
+
|
|
61
|
+
.align-toolbar
|
|
62
|
+
display flex
|
|
63
|
+
justify-content flex-end
|
|
64
|
+
align-items center
|
|
65
|
+
gap 12PX
|
|
66
|
+
margin-top 4PX
|
|
67
|
+
|
|
68
|
+
.align-btn
|
|
69
|
+
padding 4PX
|
|
70
|
+
flexHVCenter()
|
|
71
|
+
|
|
72
|
+
.image-block
|
|
73
|
+
overflow hidden
|
|
74
|
+
border-radius 10PX
|
|
75
|
+
|
|
76
|
+
.image
|
|
77
|
+
display block
|
|
78
|
+
width 100%
|
|
79
|
+
height auto
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import React, { useCallback, useMemo } from 'react'
|
|
2
|
+
import { View, Textarea, Image, BaseEventOrig, ITouchEvent } from '@tarojs/components'
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../config'
|
|
5
|
+
import { formatClassNames } from '../../util/function'
|
|
6
|
+
import Icon from '../Icon'
|
|
7
|
+
|
|
8
|
+
import styles from './index.module.styl'
|
|
9
|
+
|
|
10
|
+
/** 文本对齐方式 */
|
|
11
|
+
export type RichTextAlign = 'left' | 'center' | 'right'
|
|
12
|
+
|
|
13
|
+
export type RichTextBlockType = 'text' | 'image'
|
|
14
|
+
|
|
15
|
+
interface RichTextBlockBase {
|
|
16
|
+
/** 可选唯一标识 ,便于后续排序等扩展;未传时用下标 */
|
|
17
|
+
id?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 文本块 */
|
|
21
|
+
export interface RichTextTextBlock extends RichTextBlockBase {
|
|
22
|
+
type: 'text'
|
|
23
|
+
/** 文本内容 */
|
|
24
|
+
content: string
|
|
25
|
+
/** 对齐方式,默认 left */
|
|
26
|
+
align?: RichTextAlign
|
|
27
|
+
placeholder?: string
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 图片块 */
|
|
31
|
+
export interface RichTextImageBlock extends RichTextBlockBase {
|
|
32
|
+
type: 'image'
|
|
33
|
+
/** 图片地址 */
|
|
34
|
+
url: string
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type RichTextBlock = RichTextTextBlock | RichTextImageBlock
|
|
38
|
+
|
|
39
|
+
export interface RichTextEditorProps {
|
|
40
|
+
/** 块列表(受控) */
|
|
41
|
+
value?: RichTextBlock[]
|
|
42
|
+
/** 内容变更 */
|
|
43
|
+
onChange?: (value: RichTextBlock[]) => void
|
|
44
|
+
/** 文本占位符 */
|
|
45
|
+
placeholder?: string
|
|
46
|
+
/** 自定义类名 */
|
|
47
|
+
className?: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const ALIGN_OPTIONS: RichTextAlign[] = ['left', 'center', 'right']
|
|
51
|
+
|
|
52
|
+
const RichTextEditor: React.FC<RichTextEditorProps> = (props) => {
|
|
53
|
+
const {
|
|
54
|
+
value = [],
|
|
55
|
+
onChange,
|
|
56
|
+
placeholder = '请输入内容',
|
|
57
|
+
className,
|
|
58
|
+
} = props
|
|
59
|
+
|
|
60
|
+
const { themeSelect } = useTheme()
|
|
61
|
+
|
|
62
|
+
const deleteBtnStyle = useMemo(() => ({
|
|
63
|
+
backgroundColor: themeSelect('rgba(0, 0, 0, 0.5)', 'rgba(255, 255, 255, 0.5)'),
|
|
64
|
+
}), [themeSelect])
|
|
65
|
+
|
|
66
|
+
const updateBlock = useCallback((index: number, patch: Partial<RichTextBlock>) => {
|
|
67
|
+
onChange?.(
|
|
68
|
+
value.map((block, i) => (i === index ? { ...block, ...patch } as RichTextBlock : block))
|
|
69
|
+
)
|
|
70
|
+
}, [value, onChange])
|
|
71
|
+
|
|
72
|
+
const handleDelete = useCallback((e: ITouchEvent, index: number) => {
|
|
73
|
+
e.stopPropagation()
|
|
74
|
+
onChange?.(value.filter((_, i) => i !== index))
|
|
75
|
+
}, [value, onChange])
|
|
76
|
+
|
|
77
|
+
const handleTextChange = useCallback((
|
|
78
|
+
index: number,
|
|
79
|
+
e: BaseEventOrig<{ value: string }>
|
|
80
|
+
) => {
|
|
81
|
+
updateBlock(index, { content: e.detail.value })
|
|
82
|
+
}, [updateBlock])
|
|
83
|
+
|
|
84
|
+
const handleAlignChange = useCallback((index: number, align: RichTextAlign) => {
|
|
85
|
+
updateBlock(index, { align })
|
|
86
|
+
}, [updateBlock])
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<View className={formatClassNames(styles['rich-text-editor'], className)}>
|
|
90
|
+
{value.map((block, index) => (
|
|
91
|
+
<View
|
|
92
|
+
key={block.id ?? index}
|
|
93
|
+
className={styles['block']}
|
|
94
|
+
>
|
|
95
|
+
<View
|
|
96
|
+
className={styles['delete-btn']}
|
|
97
|
+
style={deleteBtnStyle}
|
|
98
|
+
onClick={(e) => handleDelete(e, index)}
|
|
99
|
+
>
|
|
100
|
+
<Icon
|
|
101
|
+
name='close'
|
|
102
|
+
size={10}
|
|
103
|
+
color="var(--containerCard)"
|
|
104
|
+
className={styles['delete-icon']}
|
|
105
|
+
/>
|
|
106
|
+
</View>
|
|
107
|
+
|
|
108
|
+
{
|
|
109
|
+
block.type === 'text'
|
|
110
|
+
? (
|
|
111
|
+
<View className={styles['text-block']}>
|
|
112
|
+
<Textarea
|
|
113
|
+
className={formatClassNames(
|
|
114
|
+
styles['editor-textarea'],
|
|
115
|
+
styles[`is-align-${block.align || 'left'}`]
|
|
116
|
+
)}
|
|
117
|
+
value={block.content}
|
|
118
|
+
placeholder={block?.placeholder || placeholder}
|
|
119
|
+
maxlength={-1}
|
|
120
|
+
autoHeight
|
|
121
|
+
onInput={(e) => handleTextChange(index, e)}
|
|
122
|
+
/>
|
|
123
|
+
<View className={styles['align-toolbar']}>
|
|
124
|
+
{ALIGN_OPTIONS.map((align) => {
|
|
125
|
+
const active = (block.align || 'left') === align
|
|
126
|
+
return (
|
|
127
|
+
<View
|
|
128
|
+
key={align}
|
|
129
|
+
className={styles['align-btn']}
|
|
130
|
+
onClick={() => handleAlignChange(index, align)}
|
|
131
|
+
>
|
|
132
|
+
<Icon
|
|
133
|
+
name={`align-${align}`}
|
|
134
|
+
size={16}
|
|
135
|
+
color={active ? 'var(--textTitle)' : 'var(--textMuted)'}
|
|
136
|
+
/>
|
|
137
|
+
</View>
|
|
138
|
+
)
|
|
139
|
+
})}
|
|
140
|
+
</View>
|
|
141
|
+
</View>
|
|
142
|
+
)
|
|
143
|
+
: (
|
|
144
|
+
<View className={styles['image-block']}>
|
|
145
|
+
<Image
|
|
146
|
+
className={styles['image']}
|
|
147
|
+
src={block.url}
|
|
148
|
+
mode='widthFix'
|
|
149
|
+
/>
|
|
150
|
+
</View>
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
</View>
|
|
154
|
+
))}
|
|
155
|
+
</View>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export default React.memo(RichTextEditor)
|
package/src/index.ts
CHANGED
|
@@ -24,4 +24,14 @@ export {
|
|
|
24
24
|
default as Table,
|
|
25
25
|
type TableProps,
|
|
26
26
|
type TableColumn,
|
|
27
|
-
} from './components/Table'
|
|
27
|
+
} from './components/Table'
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
default as RichTextEditor,
|
|
31
|
+
type RichTextEditorProps,
|
|
32
|
+
type RichTextBlock,
|
|
33
|
+
type RichTextTextBlock,
|
|
34
|
+
type RichTextImageBlock,
|
|
35
|
+
type RichTextAlign,
|
|
36
|
+
type RichTextBlockType,
|
|
37
|
+
} from './components/RichTextEditor'
|
|
@@ -318,7 +318,7 @@ const ProductItem: React.FC<IProductCardProps> = (props) => {
|
|
|
318
318
|
</View>
|
|
319
319
|
</ScrollView>
|
|
320
320
|
)}
|
|
321
|
-
{(activityType || deliveryTags) && (
|
|
321
|
+
{(activityType || deliveryTags || customTags) && (
|
|
322
322
|
<View className={styles['tag-row']}>
|
|
323
323
|
{activityType && labels.activity_type && (
|
|
324
324
|
<View className={styles['activity-tag']}>
|