Skip to content

Commit a2a03bc

Browse files
rigdernfacebook-github-bot
authored andcommitted
Add inline view examples to RNTester (#24814)
Summary: Now that inline views are supported on iOS and Android, we can add some examples to RNTester. I brought back examples from 0366349. I also added some new inline view examples in TextInlineView.js. Note that some examples are only supported on iOS because they rely on the inline view being able to size to content. Android's implementation requires that a width and height be specified on the inline view. Here are the known bugs illustrated by these examples: - ClippedByText - Expected: The image/view wraps to the next line (because it is too wide) and gets clipped vertically (because it is too tall). - iOS bug: The image/view does not get wrapped to the next line - Android bug: The view gets wrapped to the next line but doesn't get clipped vertically. The image appears to be positioned too low. - ChangeImageSize/ChangeViewSize: - Expected: The "Change Image/View Width" button causes the image/view to toggle between a width of 50 and 100. - iOS bug: First update works. Subsequent updates don't get rendered. - Android bug: No updates get rendered. - ChangeInnerViewSize: - Expected: The "Change Pink View Width" button causes the pink inner view to toggle between a width of 50 and 100. - iOS bug: First update works but second update **CRASHES** the app. - Android bug: No updates get rendered. [Internal] [Added] - Added inline view examples to RNTester Pull Request resolved: #24814 Differential Revision: D15318070 Pulled By: cpojer fbshipit-source-id: 35a4aaab88e477d627456eeb4208c509c42927df
1 parent 952e232 commit a2a03bc

File tree

3 files changed

+303
-5
lines changed

3 files changed

+303
-5
lines changed

RNTester/js/Shared/TextInlineView.js

+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @format
8+
* @flow
9+
*/
10+
11+
'use strict';
12+
13+
const React = require('react');
14+
const {Image, Text, TouchableHighlight, View} = require('react-native');
15+
16+
function Basic() {
17+
return (
18+
<Text>
19+
This text contains an inline blue view{' '}
20+
<View style={{width: 25, height: 25, backgroundColor: 'steelblue'}} /> and
21+
an inline image <Image source={require('../flux.png')} />. Neat, huh?
22+
</Text>
23+
);
24+
}
25+
26+
function ClippedByText() {
27+
return (
28+
<View>
29+
{/*
30+
* Inline View
31+
**/}
32+
<Text>
33+
The <Text style={{fontWeight: 'bold'}}>inline view</Text> below is
34+
taller than its Text parent and should be clipped.
35+
</Text>
36+
<Text
37+
style={{
38+
overflow: 'hidden',
39+
width: 150,
40+
height: 75,
41+
backgroundColor: 'lightgrey',
42+
}}>
43+
This is an inline view
44+
{/* Render a red border around the steelblue rectangle to make it clear how the inline view is being clipped */}
45+
<View style={{width: 50, height: 100, backgroundColor: 'red'}}>
46+
<View
47+
style={{
48+
width: 48,
49+
height: 98,
50+
left: 1,
51+
top: 1,
52+
backgroundColor: 'steelblue',
53+
}}
54+
/>
55+
</View>
56+
</Text>
57+
58+
{/*
59+
* Inline Image
60+
**/}
61+
<Text style={{marginTop: 10}}>
62+
The <Text style={{fontWeight: 'bold'}}>inline image</Text> below is
63+
taller than its Text parent and should be clipped.
64+
</Text>
65+
<Text
66+
style={{
67+
overflow: 'hidden',
68+
width: 175,
69+
height: 100,
70+
backgroundColor: 'lightgrey',
71+
}}>
72+
This is an inline image
73+
<Image
74+
source={{
75+
uri: 'https://picsum.photos/100',
76+
width: 50,
77+
height: 100,
78+
}}
79+
style={{
80+
width: 50,
81+
height: 100,
82+
}}
83+
/>
84+
</Text>
85+
</View>
86+
);
87+
}
88+
89+
type ChangeSizeState = {|
90+
width: number,
91+
|};
92+
93+
class ChangeImageSize extends React.Component<*, ChangeSizeState> {
94+
state = {
95+
width: 50,
96+
};
97+
98+
render() {
99+
return (
100+
<View>
101+
<TouchableHighlight
102+
onPress={() => {
103+
this.setState({width: this.state.width === 50 ? 100 : 50});
104+
}}>
105+
<Text style={{fontSize: 15}}>
106+
Change Image Width (width={this.state.width})
107+
</Text>
108+
</TouchableHighlight>
109+
<Text>
110+
This is an
111+
<Image
112+
source={{
113+
uri: 'https://picsum.photos/50',
114+
width: this.state.width,
115+
height: 50,
116+
}}
117+
style={{
118+
width: this.state.width,
119+
height: 50,
120+
}}
121+
/>
122+
inline image
123+
</Text>
124+
</View>
125+
);
126+
}
127+
}
128+
129+
class ChangeViewSize extends React.Component<*, ChangeSizeState> {
130+
state = {
131+
width: 50,
132+
};
133+
134+
render() {
135+
return (
136+
<View>
137+
<TouchableHighlight
138+
onPress={() => {
139+
this.setState({width: this.state.width === 50 ? 100 : 50});
140+
}}>
141+
<Text style={{fontSize: 15}}>
142+
Change View Width (width={this.state.width})
143+
</Text>
144+
</TouchableHighlight>
145+
<Text>
146+
This is an
147+
<View
148+
style={{
149+
width: this.state.width,
150+
height: 50,
151+
backgroundColor: 'steelblue',
152+
}}
153+
/>
154+
inline view
155+
</Text>
156+
</View>
157+
);
158+
}
159+
}
160+
161+
class ChangeInnerViewSize extends React.Component<*, ChangeSizeState> {
162+
state = {
163+
width: 50,
164+
};
165+
166+
render() {
167+
return (
168+
<View>
169+
<TouchableHighlight
170+
onPress={() => {
171+
this.setState({width: this.state.width === 50 ? 100 : 50});
172+
}}>
173+
{/* When updating `state.width`, it's important that the only thing that
174+
changes is the width of the pink inline view. When we do this, we
175+
demonstrate a bug in RN Android where the pink view doesn't get
176+
rerendered and remains at its old size. If other things change
177+
(e.g. we display `state.width` as text somewhere) it could circumvent
178+
the bug and cause the pink view to be rerendered at its new size. */}
179+
<Text style={{fontSize: 15}}>Change Pink View Width</Text>
180+
</TouchableHighlight>
181+
<Text>
182+
This is an
183+
<View style={{width: 125, height: 75, backgroundColor: 'steelblue'}}>
184+
<View
185+
style={{
186+
width: this.state.width,
187+
height: 50,
188+
backgroundColor: 'pink',
189+
}}
190+
/>
191+
</View>
192+
inline view
193+
</Text>
194+
</View>
195+
);
196+
}
197+
}
198+
199+
module.exports = {
200+
Basic,
201+
ClippedByText,
202+
ChangeImageSize,
203+
ChangeViewSize,
204+
ChangeInnerViewSize,
205+
};

RNTester/js/TextExample.android.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const React = require('react');
1616
const {Image, StyleSheet, Text, View} = require('react-native');
1717
const RNTesterBlock = require('./RNTesterBlock');
1818
const RNTesterPage = require('./RNTesterPage');
19+
const TextInlineView = require('./Shared/TextInlineView');
1920
const TextLegend = require('./Shared/TextLegend');
2021

2122
class Entity extends React.Component<{|children: React.Node|}> {
@@ -506,11 +507,20 @@ class TextExample extends React.Component<{}> {
506507
This text will have a orange highlight on selection.
507508
</Text>
508509
</RNTesterBlock>
509-
<RNTesterBlock title="Inline images">
510-
<Text>
511-
This text contains an inline image{' '}
512-
<Image source={require('./flux.png')} />. Neat, huh?
513-
</Text>
510+
<RNTesterBlock title="Inline views">
511+
<TextInlineView.Basic />
512+
</RNTesterBlock>
513+
<RNTesterBlock title="Inline image/view clipped by <Text>">
514+
<TextInlineView.ClippedByText />
515+
</RNTesterBlock>
516+
<RNTesterBlock title="Relayout inline image">
517+
<TextInlineView.ChangeImageSize />
518+
</RNTesterBlock>
519+
<RNTesterBlock title="Relayout inline view">
520+
<TextInlineView.ChangeViewSize />
521+
</RNTesterBlock>
522+
<RNTesterBlock title="Relayout nested inline view">
523+
<TextInlineView.ChangeInnerViewSize />
514524
</RNTesterBlock>
515525
<RNTesterBlock title="Text shadow">
516526
<Text

RNTester/js/TextExample.ios.js

+83
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,21 @@ const {
1919
TextInput,
2020
View,
2121
} = require('react-native');
22+
const TextAncestor = require('TextAncestor');
23+
const TextInlineView = require('./Shared/TextInlineView');
2224
const TextLegend = require('./Shared/TextLegend');
2325

26+
// TODO: Is there a cleaner way to flip the TextAncestor value to false? I
27+
// suspect apps won't even be able to leverage this workaround because
28+
// TextAncestor is not public.
29+
function InlineView(props) {
30+
return (
31+
<TextAncestor.Provider value={false}>
32+
<View {...props} />
33+
</TextAncestor.Provider>
34+
);
35+
}
36+
2437
type TextAlignExampleRTLState = {|
2538
isRTL: boolean,
2639
|};
@@ -274,6 +287,28 @@ class TextBaseLineLayoutExample extends React.Component<*, *> {
274287
{marker}
275288
</View>
276289

290+
{/* iOS-only because it relies on inline views being able to size to content.
291+
* Android's implementation requires that a width and height be specified
292+
* on the inline view. */}
293+
<Text style={subtitleStyle}>{'Interleaving <View> and <Text>:'}</Text>
294+
<View style={{flexDirection: 'row', alignItems: 'baseline'}}>
295+
{marker}
296+
<Text selectable={true}>
297+
Some text.
298+
<View
299+
style={{
300+
flexDirection: 'row',
301+
alignItems: 'baseline',
302+
backgroundColor: '#eee',
303+
}}>
304+
{marker}
305+
<Text>Text inside View.</Text>
306+
{marker}
307+
</View>
308+
</Text>
309+
{marker}
310+
</View>
311+
277312
<Text style={subtitleStyle}>{'<TextInput/>:'}</Text>
278313
<View style={{flexDirection: 'row', alignItems: 'baseline'}}>
279314
{marker}
@@ -914,6 +949,26 @@ exports.examples = [
914949
);
915950
},
916951
},
952+
{
953+
title: 'Inline views',
954+
render: () => <TextInlineView.Basic />,
955+
},
956+
{
957+
title: 'Inline image/view clipped by <Text>',
958+
render: () => <TextInlineView.ClippedByText />,
959+
},
960+
{
961+
title: 'Relayout inline image',
962+
render: () => <TextInlineView.ChangeImageSize />,
963+
},
964+
{
965+
title: 'Relayout inline view',
966+
render: () => <TextInlineView.ChangeViewSize />,
967+
},
968+
{
969+
title: 'Relayout nested inline view',
970+
render: () => <TextInlineView.ChangeInnerViewSize />,
971+
},
917972
{
918973
title: 'Text shadow',
919974
render: function() {
@@ -987,6 +1042,34 @@ exports.examples = [
9871042
);
9881043
},
9891044
},
1045+
{
1046+
title: 'Nested content',
1047+
render: function() {
1048+
// iOS-only because it relies on inline views being able to size to content.
1049+
// Android's implementation requires that a width and height be specified
1050+
// on the inline view.
1051+
return (
1052+
<Text>
1053+
This text has a view
1054+
<InlineView style={{borderColor: 'red', borderWidth: 1}}>
1055+
<Text style={{borderColor: 'blue', borderWidth: 1}}>which has</Text>
1056+
<Text style={{borderColor: 'green', borderWidth: 1}}>
1057+
another text inside.
1058+
</Text>
1059+
<Text style={{borderColor: 'yellow', borderWidth: 1}}>
1060+
And moreover, it has another view
1061+
<InlineView style={{borderColor: 'red', borderWidth: 1}}>
1062+
<Text style={{borderColor: 'blue', borderWidth: 1}}>
1063+
with another text inside!
1064+
</Text>
1065+
</InlineView>
1066+
</Text>
1067+
</InlineView>
1068+
Because we need to go deeper.
1069+
</Text>
1070+
);
1071+
},
1072+
},
9901073
{
9911074
title: 'Dynamic Font Size Adjustment',
9921075
render: function(): React.Element<any> {

0 commit comments

Comments
 (0)