Skip to content

Commit 9dfe31a

Browse files
committed
Add text decoration.
1 parent fb3ad45 commit 9dfe31a

File tree

3 files changed

+266
-14
lines changed

3 files changed

+266
-14
lines changed

react-native/components/createTextComponent/index.tsx

+27-2
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,36 @@ import type { TextProps } from '../../types/TextProps'
1212
* @param multiLine When true, text will wrap across multiple lines when it does
1313
* not fit within the available width. When false, text will
1414
* be truncated with an ellipsis.
15+
* @param decoration When null, the text is not decorated. Otherwise, a
16+
* description of the decoration to apply.
1517
* @returns A new React component which can be used to render text.
1618
*/
1719
export const createTextComponent = (
1820
fontFamily: string,
1921
fontSize: number,
2022
color: ColorValue,
2123
alignment: 'left' | 'center' | 'right',
22-
multiLine: boolean
24+
multiLine: boolean,
25+
decoration: null | (({
26+
readonly underline: true
27+
readonly strikethrough: true
28+
} | {
29+
readonly underline: false
30+
readonly strikethrough: true
31+
} | {
32+
readonly underline: true
33+
readonly strikethrough: false
34+
}) & {
35+
/**
36+
* The style of the text decoration to apply.
37+
*/
38+
readonly style: 'solid' | 'double' | 'dotted' | 'dashed'
39+
40+
/**
41+
* The color of hte xt d
42+
*/
43+
readonly color: ColorValue
44+
})
2345
): React.FunctionComponent<TextProps> => {
2446
const styles = StyleSheet.create({
2547
text: {
@@ -28,7 +50,10 @@ export const createTextComponent = (
2850
lineHeight: fontSize * 1.4,
2951
color,
3052
textAlign: alignment,
31-
flexShrink: 1
53+
flexShrink: 1,
54+
textDecorationLine: decoration === null ? 'none' : (decoration.strikethrough ? (decoration.underline ? 'underline line-through' : 'line-through') : 'underline'),
55+
textDecorationColor: decoration === null ? undefined : decoration.color,
56+
textDecorationStyle: decoration === null ? undefined : decoration.style
3257
}
3358
})
3459

react-native/components/createTextComponent/readme.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Creates a new React component which can be used to render text.
77
```tsx
88
import { createTextComponent } from "react-native-app-helpers";
99

10-
const ExampleText = createTextComponent(`example`, `red`, 12, `left`, false);
10+
const ExampleText = createTextComponent(`example`, `red`, 12, `left`, false, null);
1111

1212
const ExampleScreen = () => (
1313
<ExampleText>
@@ -25,7 +25,7 @@ const ExampleScreen = () => (
2525
```tsx
2626
import { createTextComponent } from "react-native-app-helpers";
2727

28-
const ExampleText = createTextComponent(`example`, `red`, 12, `left`, true);
28+
const ExampleText = createTextComponent(`example`, `red`, 12, `left`, true, null);
2929

3030
const ExampleScreen = () => (
3131
<ExampleText>
@@ -39,3 +39,20 @@ const ExampleScreen = () => (
3939
</ExampleText>
4040
);
4141
```
42+
43+
```tsx
44+
import { createTextComponent } from "react-native-app-helpers";
45+
46+
const ExampleText = createTextComponent(`example`, `red`, 12, `left`, false, {
47+
underline: true,
48+
strikethrough: false,
49+
style: `solid`, // Also: double, dotted, dashed.
50+
color: `blue`,
51+
});
52+
53+
const ExampleScreen = () => (
54+
<ExampleText>
55+
This has text decorations applied to it as described above.
56+
</ExampleText>
57+
);
58+
```

react-native/components/createTextComponent/unit.tsx

+220-10
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ test('renders single-line', () => {
99
37,
1010
'#34AE17',
1111
'left',
12-
false
12+
false,
13+
null
1314
)
1415

1516
const rendered = <Component>Test Content</Component>
@@ -22,7 +23,10 @@ test('renders single-line', () => {
2223
lineHeight: 51.8,
2324
color: '#34AE17',
2425
textAlign: 'left',
25-
flexShrink: 1
26+
flexShrink: 1,
27+
textDecorationLine: 'none',
28+
textDecorationStyle: undefined,
29+
textDecorationColor: undefined
2630
}}
2731
numberOfLines={1}
2832
>
@@ -37,7 +41,8 @@ test('renders multi-line', () => {
3741
37,
3842
'#34AE17',
3943
'left',
40-
true
44+
true,
45+
null
4146
)
4247

4348
const rendered = <Component>Test Content</Component>
@@ -50,7 +55,10 @@ test('renders multi-line', () => {
5055
lineHeight: 51.8,
5156
color: '#34AE17',
5257
textAlign: 'left',
53-
flexShrink: 1
58+
flexShrink: 1,
59+
textDecorationLine: 'none',
60+
textDecorationStyle: undefined,
61+
textDecorationColor: undefined
5462
}}
5563
numberOfLines={0}
5664
>
@@ -59,13 +67,206 @@ test('renders multi-line', () => {
5967
)
6068
})
6169

70+
test('renders underlined', () => {
71+
const Component = createTextComponent(
72+
'Test Font Family',
73+
37,
74+
'#34AE17',
75+
'left',
76+
false,
77+
{ underline: true, strikethrough: false, style: 'solid', color: 'blue' }
78+
)
79+
80+
const rendered = <Component>Test Content</Component>
81+
82+
expect(unwrapRenderedFunctionComponent(rendered)).toEqual(
83+
<Text
84+
style={{
85+
fontFamily: 'Test Font Family',
86+
fontSize: 37,
87+
lineHeight: 51.8,
88+
color: '#34AE17',
89+
textAlign: 'left',
90+
flexShrink: 1,
91+
textDecorationLine: 'underline',
92+
textDecorationStyle: 'solid',
93+
textDecorationColor: 'blue'
94+
}}
95+
numberOfLines={1}
96+
>
97+
Test Content
98+
</Text>
99+
)
100+
})
101+
102+
test('renders strikethrough', () => {
103+
const Component = createTextComponent(
104+
'Test Font Family',
105+
37,
106+
'#34AE17',
107+
'left',
108+
false,
109+
{ underline: false, strikethrough: true, style: 'solid', color: 'blue' }
110+
)
111+
112+
const rendered = <Component>Test Content</Component>
113+
114+
expect(unwrapRenderedFunctionComponent(rendered)).toEqual(
115+
<Text
116+
style={{
117+
fontFamily: 'Test Font Family',
118+
fontSize: 37,
119+
lineHeight: 51.8,
120+
color: '#34AE17',
121+
textAlign: 'left',
122+
flexShrink: 1,
123+
textDecorationLine: 'line-through',
124+
textDecorationStyle: 'solid',
125+
textDecorationColor: 'blue'
126+
}}
127+
numberOfLines={1}
128+
>
129+
Test Content
130+
</Text>
131+
)
132+
})
133+
134+
test('renders underlined strikethrough', () => {
135+
const Component = createTextComponent(
136+
'Test Font Family',
137+
37,
138+
'#34AE17',
139+
'left',
140+
false,
141+
{ underline: true, strikethrough: true, style: 'solid', color: 'blue' }
142+
)
143+
144+
const rendered = <Component>Test Content</Component>
145+
146+
expect(unwrapRenderedFunctionComponent(rendered)).toEqual(
147+
<Text
148+
style={{
149+
fontFamily: 'Test Font Family',
150+
fontSize: 37,
151+
lineHeight: 51.8,
152+
color: '#34AE17',
153+
textAlign: 'left',
154+
flexShrink: 1,
155+
textDecorationLine: 'underline line-through',
156+
textDecorationStyle: 'solid',
157+
textDecorationColor: 'blue'
158+
}}
159+
numberOfLines={1}
160+
>
161+
Test Content
162+
</Text>
163+
)
164+
})
165+
166+
test('renders double', () => {
167+
const Component = createTextComponent(
168+
'Test Font Family',
169+
37,
170+
'#34AE17',
171+
'left',
172+
false,
173+
{ underline: true, strikethrough: false, style: 'double', color: 'blue' }
174+
)
175+
176+
const rendered = <Component>Test Content</Component>
177+
178+
expect(unwrapRenderedFunctionComponent(rendered)).toEqual(
179+
<Text
180+
style={{
181+
fontFamily: 'Test Font Family',
182+
fontSize: 37,
183+
lineHeight: 51.8,
184+
color: '#34AE17',
185+
textAlign: 'left',
186+
flexShrink: 1,
187+
textDecorationLine: 'underline',
188+
textDecorationStyle: 'double',
189+
textDecorationColor: 'blue'
190+
}}
191+
numberOfLines={1}
192+
>
193+
Test Content
194+
</Text>
195+
)
196+
})
197+
198+
test('renders dotted', () => {
199+
const Component = createTextComponent(
200+
'Test Font Family',
201+
37,
202+
'#34AE17',
203+
'left',
204+
false,
205+
{ underline: true, strikethrough: false, style: 'dotted', color: 'blue' }
206+
)
207+
208+
const rendered = <Component>Test Content</Component>
209+
210+
expect(unwrapRenderedFunctionComponent(rendered)).toEqual(
211+
<Text
212+
style={{
213+
fontFamily: 'Test Font Family',
214+
fontSize: 37,
215+
lineHeight: 51.8,
216+
color: '#34AE17',
217+
textAlign: 'left',
218+
flexShrink: 1,
219+
textDecorationLine: 'underline',
220+
textDecorationStyle: 'dotted',
221+
textDecorationColor: 'blue'
222+
}}
223+
numberOfLines={1}
224+
>
225+
Test Content
226+
</Text>
227+
)
228+
})
229+
230+
test('renders dashed', () => {
231+
const Component = createTextComponent(
232+
'Test Font Family',
233+
37,
234+
'#34AE17',
235+
'left',
236+
false,
237+
{ underline: true, strikethrough: false, style: 'dashed', color: 'blue' }
238+
)
239+
240+
const rendered = <Component>Test Content</Component>
241+
242+
expect(unwrapRenderedFunctionComponent(rendered)).toEqual(
243+
<Text
244+
style={{
245+
fontFamily: 'Test Font Family',
246+
fontSize: 37,
247+
lineHeight: 51.8,
248+
color: '#34AE17',
249+
textAlign: 'left',
250+
flexShrink: 1,
251+
textDecorationLine: 'underline',
252+
textDecorationStyle: 'dashed',
253+
textDecorationColor: 'blue'
254+
}}
255+
numberOfLines={1}
256+
>
257+
Test Content
258+
</Text>
259+
)
260+
})
261+
62262
test('renders with onPress undefined', () => {
63263
const Component = createTextComponent(
64264
'Test Font Family',
65265
37,
66266
'#34AE17',
67267
'left',
68-
false
268+
false,
269+
null
69270
)
70271

71272
const rendered = <Component onPress={undefined}>Test Content</Component>
@@ -78,7 +279,10 @@ test('renders with onPress undefined', () => {
78279
lineHeight: 51.8,
79280
color: '#34AE17',
80281
textAlign: 'left',
81-
flexShrink: 1
282+
flexShrink: 1,
283+
textDecorationLine: 'none',
284+
textDecorationStyle: undefined,
285+
textDecorationColor: undefined
82286
}}
83287
numberOfLines={1}
84288
>
@@ -93,7 +297,8 @@ test('renders with onPress set', () => {
93297
37,
94298
'#34AE17',
95299
'left',
96-
false
300+
false,
301+
null
97302
)
98303
const onPress = jest.fn()
99304

@@ -107,7 +312,10 @@ test('renders with onPress set', () => {
107312
lineHeight: 51.8,
108313
color: '#34AE17',
109314
textAlign: 'left',
110-
flexShrink: 1
315+
flexShrink: 1,
316+
textDecorationLine: 'none',
317+
textDecorationStyle: undefined,
318+
textDecorationColor: undefined
111319
}}
112320
numberOfLines={1}
113321
onPress={expect.any(Function)}
@@ -125,7 +333,8 @@ test('executes the press callback once when hitboxes are enabled', () => {
125333
37,
126334
'#34AE17',
127335
'left',
128-
false
336+
false,
337+
null
129338
)
130339
const onPress = jest.fn()
131340

@@ -149,7 +358,8 @@ test('does not execute the press callback when hitboxes are disabled', () => {
149358
37,
150359
'#34AE17',
151360
'left',
152-
false
361+
false,
362+
null
153363
)
154364
const onPress = jest.fn()
155365

0 commit comments

Comments
 (0)