已开启
feat: 新增react-native-selectable-text库 #677
feat: 新增react-native-selectable-text库 #677
已开启
sunkaiyang创建于 1月22日
共 6 个文件变更+498-2
M25P3_2/harmony/entry/oh-package.json5+2-1文件内容审核中,请稍后刷新重试
M25P3_2/harmony/entry/src/main/cpp/CMakeLists.txt+2-0文件内容审核中,请稍后刷新重试
M25P3_2/harmony/entry/src/main/cpp/PackageProvider.cpp+2-0文件内容审核中,请稍后刷新重试
M25P3_2/package.json+2-1文件内容审核中,请稍后刷新重试
@@ -0,0 +1,485 @@
1+import React, { useState } from 'react';
2+import { ScrollView, View, Text, StyleSheet, Alert } from 'react-native';
3+import { TestSuite, TestCase, Tester } from '@rnoh/testerino';
4+import { SelectableText } from 'react-native-selectable-text';
5+ 
6+// 自定义文本组件1:使用 value 属性接收文本,红色边框+粉色背景
7+const CustomTextWithValue = ({ value, style, ...props }: any) => (
8+ <View style={{ borderWidth: 2, borderColor: '#E91E63', backgroundColor: '#FCE4EC', borderRadius: 8, padding: 8 }}>
9+ <Text style={[style, { fontWeight: 'bold', color: '#C2185B' }]} {...props}>
10+ 📌 {value}
11+ </Text>
12+ </View>
13+);
14+ 
15+// 自定义文本组件2:使用 content 属性接收文本,蓝色边框+蓝色背景
16+const CustomTextWithContent = ({ content, style, ...props }: any) => (
17+ <View style={{ borderWidth: 2, borderColor: '#2196F3', backgroundColor: '#E3F2FD', borderRadius: 8, padding: 8 }}>
18+ <Text style={[style, { fontStyle: 'italic', color: '#1565C0' }]} {...props}>
19+ 🔷 {content}
20+ </Text>
21+ </View>
22+);
23+ 
24+// 自定义文本组件3:使用 textData 属性接收文本,绿色虚线框+绿色背景
25+const CustomTextWithData = ({ textData, style, ...props }: any) => (
26+ <View style={{ borderWidth: 2, borderColor: '#4CAF50', borderStyle: 'dashed', backgroundColor: '#E8F5E9', borderRadius: 12, padding: 10 }}>
27+ <Text style={[style, { fontFamily: 'monospace', color: '#2E7D32' }]} {...props}>
28+ ✅ [SUCCESS] {textData}
29+ </Text>
30+ </View>
31+);
32+ 
33+// 自定义文本组件4:使用 message 属性接收文本,暗黑风格+左侧黄色强调线
34+const CustomTextDark = ({ message, style, ...props }: any) => (
35+ <View style={{ backgroundColor: '#263238', padding: 12, borderLeftWidth: 5, borderLeftColor: '#FFC107', borderRadius: 4 }}>
36+ <Text style={[style, { color: '#ECEFF1', fontSize: 14 }]} {...props}>
37+ 💻 &gt; {message}
38+ </Text>
39+ </View>
40+);
41+ 
42+export default function SelectableTextTest() {
43+ const [lastEvent, setLastEvent] = useState<string>('');
44+ 
45+ const handleSelection = (event: any) => {
46+ setLastEvent(`${event.eventType}: "${event.content}"`);
47+ Alert.alert(event.eventType, `选中: "${event.content}"\n范围: [${event.selectionStart}, ${event.selectionEnd}]`);
48+ };
49+ 
50+ const handleHighlightPress = (id: string) => {
51+ Alert.alert('高亮点击', `ID: ${id}`);
52+ };
53+ 
54+ return (
55+ <ScrollView style={styles.container}>
56+ <Tester style={{ flex: 1 }}>
57+ 
58+ <TestSuite name="value (文本内容)">
59+ <TestCase itShould="显示中文文本">
60+ <SelectableText
61+ value="这是一段中文测试文本"
62+ selectable={true}
63+ menuItems={["复制"]}
64+ onSelection={handleSelection}
65+ style={styles.text}
66+ />
67+ </TestCase>
68+ <TestCase itShould="显示英文文本">
69+ <SelectableText
70+ value="This is English test text"
71+ selectable={true}
72+ menuItems={["Copy"]}
73+ onSelection={handleSelection}
74+ style={styles.text}
75+ />
76+ </TestCase>
77+ <TestCase itShould="显示特殊字符和表情">
78+ <SelectableText
79+ value="特殊字符 @#$% 表情: 😀🎉🔥"
80+ selectable={true}
81+ menuItems={["复制"]}
82+ onSelection={handleSelection}
83+ style={styles.text}
84+ />
85+ </TestCase>
86+ </TestSuite>
87+ 
88+ <TestSuite name="onSelection (选择回调)">
89+ <TestCase itShould="选中后点击菜单触发回调,弹出 Alert">
90+ <Text style={styles.hint}>最近回调: {lastEvent || '无'}</Text>
91+ <SelectableText
92+ value="长按选中文本后点击菜单项"
93+ selectable={true}
94+ menuItems={["测试回调"]}
95+ onSelection={handleSelection}
96+ style={styles.text}
97+ />
98+ </TestCase>
99+ <TestCase itShould="返回 eventType、content、selectionStart、selectionEnd">
100+ <SelectableText
101+ value="验证回调参数完整性"
102+ selectable={true}
103+ menuItems={["验证"]}
104+ onSelection={(e) => {
105+ Alert.alert('回调参数',
106+ `eventType: ${e.eventType}\ncontent: ${e.content}\nstart: ${e.selectionStart}\nend: ${e.selectionEnd}`
107+ );
108+ }}
109+ style={styles.text}
110+ />
111+ </TestCase>
112+ </TestSuite>
113+ 
114+ <TestSuite name="menuItems (菜单项)">
115+ <TestCase itShould="显示单个菜单项">
116+ <SelectableText
117+ value="只有一个菜单项"
118+ selectable={true}
119+ menuItems={["唯一"]}
120+ onSelection={handleSelection}
121+ style={styles.text}
122+ />
123+ </TestCase>
124+ <TestCase itShould="显示多个菜单项">
125+ <SelectableText
126+ value="多个菜单项测试"
127+ selectable={true}
128+ menuItems={["复制", "翻译", "搜索", "分享"]}
129+ onSelection={handleSelection}
130+ style={styles.text}
131+ />
132+ </TestCase>
133+ <TestCase itShould="空数组不显示菜单">
134+ <SelectableText
135+ value="空菜单项数组"
136+ selectable={true}
137+ menuItems={[]}
138+ onSelection={handleSelection}
139+ style={styles.text}
140+ />
141+ </TestCase>
142+ </TestSuite>
143+ 
144+ <TestSuite name="style (样式)">
145+ <TestCase itShould="fontSize: 12 (小字体)">
146+ <SelectableText
147+ value="小字体文本"
148+ selectable={true}
149+ menuItems={["复制"]}
150+ onSelection={handleSelection}
151+ style={[styles.text, { fontSize: 12 }]}
152+ />
153+ </TestCase>
154+ <TestCase itShould="fontSize: 24 (大字体)">
155+ <SelectableText
156+ value="大字体文本"
157+ selectable={true}
158+ menuItems={["复制"]}
159+ onSelection={handleSelection}
160+ style={[styles.text, { fontSize: 24 }]}
161+ />
162+ </TestCase>
163+ <TestCase itShould="color: red">
164+ <SelectableText
165+ value="红色文字"
166+ selectable={true}
167+ menuItems={["复制"]}
168+ onSelection={handleSelection}
169+ style={[styles.text, { color: '#E53935' }]}
170+ />
171+ </TestCase>
172+ <TestCase itShould="fontWeight: 'bold' (粗体)">
173+ <SelectableText
174+ value="粗体文本样式"
175+ selectable={true}
176+ menuItems={["复制"]}
177+ onSelection={handleSelection}
178+ style={[styles.text, { fontWeight: 'bold' }]}
179+ />
180+ </TestCase>
181+ <TestCase itShould="textDecorationLine: 'underline' (下划线)">
182+ <SelectableText
183+ value="带下划线的文本样式"
184+ selectable={true}
185+ menuItems={["复制"]}
186+ onSelection={handleSelection}
187+ style={[styles.text, { textDecorationLine: 'underline' }]}
188+ />
189+ </TestCase>
190+ </TestSuite>
191+ 
192+ <TestSuite name="highlights (预设高亮)">
193+ <TestCase itShould="单个高亮区域 (2-6)">
194+ <SelectableText
195+ value="这是一段带有高亮的文本"
196+ selectable={true}
197+ menuItems={["复制"]}
198+ highlights={[{ id: "h1", start: 2, end: 6 }]}
199+ highlightColor="#FFEB3B"
200+ onHighlightPress={handleHighlightPress}
201+ onSelection={handleSelection}
202+ style={styles.text}
203+ />
204+ </TestCase>
205+ <TestCase itShould="多个高亮区域">
206+ <SelectableText
207+ value="第一段第二段第三段其他"
208+ selectable={true}
209+ menuItems={["复制"]}
210+ highlights={[
211+ { id: "h1", start: 1, end: 3 },
212+ { id: "h2", start: 4, end: 6 },
213+ { id: "h3", start: 7, end: 9 },
214+ ]}
215+ highlightColor="#80DEEA"
216+ onHighlightPress={handleHighlightPress}
217+ onSelection={handleSelection}
218+ style={styles.text}
219+ />
220+ </TestCase>
221+ </TestSuite>
222+ 
223+ <TestSuite name="highlightColor (高亮颜色)">
224+ <TestCase itShould="Hex 格式: 黄色 #FFEB3B">
225+ <SelectableText
226+ value="Hex 黄色高亮文本"
227+ selectable={true}
228+ menuItems={["复制"]}
229+ highlights={[{ id: "hex", start: 0, end: 7 }]}
230+ highlightColor="#FFEB3B"
231+ onSelection={handleSelection}
232+ style={styles.text}
233+ />
234+ </TestCase>
235+ <TestCase itShould="RGBA 格式: 半透明蓝 rgba(0, 0, 255, 0.3)">
236+ <SelectableText
237+ value="RGBA 蓝色高亮文本"
238+ selectable={true}
239+ menuItems={["复制"]}
240+ highlights={[{ id: "rgba", start: 0, end: 8 }]}
241+ highlightColor="rgba(0, 0, 255, 0.3)"
242+ onSelection={handleSelection}
243+ style={styles.text}
244+ />
245+ </TestCase>
246+ <TestCase itShould="Color Name 格式: Orange (橙色)">
247+ <SelectableText
248+ value="Orange 橙色高亮文本"
249+ selectable={true}
250+ menuItems={["复制"]}
251+ highlights={[{ id: "name", start: 0, end: 10 }]}
252+ highlightColor="orange"
253+ onSelection={handleSelection}
254+ style={styles.text}
255+ />
256+ </TestCase>
257+ </TestSuite>
258+ 
259+ <TestSuite name="onHighlightPress (高亮点击)">
260+ <TestCase itShould="点击高亮区域触发回调">
261+ <SelectableText
262+ value="点击黄色区域触发回调"
263+ selectable={true}
264+ menuItems={["复制"]}
265+ highlights={[{ id: "click-test", start: 2, end: 8 }]}
266+ highlightColor="#FFD54F"
267+ onHighlightPress={handleHighlightPress}
268+ onSelection={handleSelection}
269+ style={styles.text}
270+ />
271+ </TestCase>
272+ </TestSuite>
273+ 
274+ <TestSuite name="appendToChildren (末行追加)">
275+ <TestCase itShould="追加文本元素">
276+ <SelectableText
277+ value="主文本内容"
278+ selectable={true}
279+ menuItems={["复制"]}
280+ appendToChildren={<Text style={{ color: '#E91E63', fontWeight: 'bold' }}> [追加文本]</Text>}
281+ onSelection={handleSelection}
282+ style={styles.text}
283+ />
284+ </TestCase>
285+ <TestCase itShould="追加文本emoji混合元素">
286+ <SelectableText
287+ value="主文本"
288+ selectable={true}
289+ menuItems={["复制"]}
290+ appendToChildren={<Text style={{ color: '#4CAF50' }}> 😀🎉🔥 已验证</Text>}
291+ onSelection={handleSelection}
292+ style={styles.text}
293+ />
294+ </TestCase>
295+ </TestSuite>
296+ 
297+ <TestSuite name="TextComponent (自定义文本组件)">
298+ <TestCase itShould="不设置 TextComponent → 默认普通样式">
299+ <SelectableText
300+ value="默认 Text 组件渲染"
301+ selectable={true}
302+ menuItems={["复制"]}
303+ onSelection={handleSelection}
304+ style={styles.text}
305+ />
306+ </TestCase>
307+ <TestCase itShould="TextComponent=红色组件 → 红色边框+粉色背景">
308+ <SelectableText
309+ value="自定义红色组件渲染"
310+ selectable={true}
311+ menuItems={["复制"]}
312+ TextComponent={CustomTextWithValue}
313+ textValueProp="value"
314+ onSelection={handleSelection}
315+ style={styles.text}
316+ />
317+ </TestCase>
318+ <TestCase itShould="TextComponent=蓝色组件 → 蓝色边框+蓝色背景">
319+ <SelectableText
320+ value="自定义蓝色组件渲染"
321+ selectable={true}
322+ menuItems={["复制"]}
323+ TextComponent={CustomTextWithContent}
324+ textValueProp="content"
325+ onSelection={handleSelection}
326+ style={styles.text}
327+ />
328+ </TestCase>
329+ <TestCase itShould="TextComponent=绿色组件 → 绿色虚线框+ValueProp='textData'">
330+ <SelectableText
331+ value="操作成功完成"
332+ selectable={true}
333+ menuItems={["复制"]}
334+ TextComponent={CustomTextWithData}
335+ textValueProp="textData"
336+ onSelection={handleSelection}
337+ style={styles.text}
338+ />
339+ </TestCase>
340+ <TestCase itShould="TextComponent=黑色组件 → 深色背景+ValueProp='message'">
341+ <SelectableText
342+ value="console.log('Hello World');"
343+ selectable={true}
344+ menuItems={["复制"]}
345+ TextComponent={CustomTextDark}
346+ textValueProp="message"
347+ onSelection={handleSelection}
348+ style={styles.text}
349+ />
350+ </TestCase>
351+ </TestSuite>
352+ 
353+ <TestSuite name="textValueProp (值属性名)">
354+ <Text style={styles.propDesc}>说明:textValueProp 决定文本通过什么属性名传给 TextComponent</Text>
355+ <TestCase itShould="属性名正确 → 红色组件显示'📌 测试文本'">
356+ <Text style={styles.hint}>红色组件期望 value 属性,设置 textValueProp="value" ✓</Text>
357+ <SelectableText
358+ value="测试文本"
359+ selectable={true}
360+ menuItems={["复制"]}
361+ TextComponent={CustomTextWithValue}
362+ textValueProp="value"
363+ onSelection={handleSelection}
364+ style={styles.text}
365+ />
366+ </TestCase>
367+ <TestCase itShould="属性名错误 → 红色组件只显示'📌',文本丢失!">
368+ <Text style={styles.hint}>红色组件期望 value,但设置 textValueProp="content" ✗</Text>
369+ <SelectableText
370+ value="这段文本不会显示"
371+ selectable={true}
372+ menuItems={["复制"]}
373+ TextComponent={CustomTextWithValue}
374+ textValueProp="content"
375+ onSelection={handleSelection}
376+ style={styles.text}
377+ />
378+ </TestCase>
379+ </TestSuite>
380+ 
381+ <TestSuite name="textComponentProps (额外属性)">
382+ <TestCase itShould="letterSpacing: 4">
383+ <SelectableText
384+ value="字间距测试文本"
385+ selectable={true}
386+ menuItems={["复制"]}
387+ textComponentProps={{ style: { letterSpacing: 4 } }}
388+ onSelection={handleSelection}
389+ style={styles.text}
390+ />
391+ </TestCase>
392+ <TestCase itShould="letterSpacing: 10">
393+ <SelectableText
394+ value="字间距测试文本"
395+ selectable={true}
396+ menuItems={["复制"]}
397+ textComponentProps={{ style: { letterSpacing: 10 } }}
398+ onSelection={handleSelection}
399+ style={styles.text}
400+ />
401+ </TestCase>
402+ <TestCase itShould="numberOfLines: 1">
403+ <SelectableText
404+ value="这是一段很长很长很很长很很长很很长很长很长的文本会被截断"
405+ selectable={true}
406+ menuItems={["复制"]}
407+ textComponentProps={{ numberOfLines: 1 }}
408+ onSelection={handleSelection}
409+ style={styles.text}
410+ />
411+ </TestCase>
412+ <TestCase itShould="numberOfLines: 2">
413+ <SelectableText
414+ value="这是一段很长很长很很长很很长很很长很长很长的文本会被截断"
415+ selectable={true}
416+ menuItems={["复制"]}
417+ textComponentProps={{ numberOfLines: 2 }}
418+ onSelection={handleSelection}
419+ style={styles.text}
420+ />
421+ </TestCase>
422+ <TestCase itShould="lineHeight: 20 (紧凑)">
423+ <SelectableText
424+ value="测试行高属性。这是一段很长很长很很长很很长很很长很长很长的文本"
425+ selectable={true}
426+ menuItems={["复制"]}
427+ textComponentProps={{ style: { lineHeight: 20 } }}
428+ onSelection={handleSelection}
429+ style={styles.text}
430+ />
431+ </TestCase>
432+ <TestCase itShould="lineHeight: 50 (宽松)">
433+ <SelectableText
434+ value="测试行高属性。这是一段很长很长很很长很很长很很长很长很长的文本"
435+ selectable={true}
436+ menuItems={["复制"]}
437+ textComponentProps={{ style: { lineHeight: 50 } }}
438+ onSelection={handleSelection}
439+ style={styles.text}
440+ />
441+ </TestCase>
442+ <TestCase itShould="decoration: underline (下划线)">
443+ <SelectableText
444+ value="这是一段带下划线的测试文本"
445+ selectable={true}
446+ menuItems={["复制"]}
447+ textComponentProps={{ style: { textDecorationLine: 'underline' } }}
448+ onSelection={handleSelection}
449+ style={styles.text}
450+ />
451+ </TestCase>
452+ <TestCase itShould="decoration: line-through (删除线)">
453+ <SelectableText
454+ value="这是一段带删除线的测试文本"
455+ selectable={true}
456+ menuItems={["复制"]}
457+ textComponentProps={{ style: { textDecorationLine: 'line-through' } }}
458+ onSelection={handleSelection}
459+ style={styles.text}
460+ />
461+ </TestCase>
462+ </TestSuite>
463+ </Tester>
464+ </ScrollView>
465+ );
466+}
467+ 
468+const styles = StyleSheet.create({
469+ container: { flex: 1, backgroundColor: '#F5F5F5' },
470+ text: { fontSize: 16, color: '#333', padding: 10, backgroundColor: '#FFF' },
471+ hint: { fontSize: 12, color: '#666', padding: 5, backgroundColor: '#E8F5E9' },
472+ propDesc: { fontSize: 12, color: '#1565C0', padding: 8, backgroundColor: '#BBDEFB', marginBottom: 8, borderRadius: 4 },
473+});
474+ 
475+export const displayName = 'SelectableTextTest';
476+export const framework = 'React';
477+export const category = 'Text';
478+export const title = 'SelectableText';
479+export const description = '长按选择文本弹出菜单库';
480+export const examples = [
481+ {
482+ title: 'SelectableText 属性测试',
483+ render: () => <SelectableTextTest />,
484+ },
485+];
M25P3_2/rn-tester/utils/RNTesterList.ts+5-0文件内容审核中,请稍后刷新重试