Skip to content

Commit a2b64f2

Browse files
authored
Feat/hint pressable target (#1630)
* Add settings icon to demo app assets * Add support to targetRef prop * add renderMultipleSegmentOptions API to Example screen presenter * Refactor Hint example screen * trigger build * Revert prev change * Use measureInWindow when user pass onBackgroundPress callback * Support target press while hint is shown * Clean leftovers
1 parent bae106c commit a2b64f2

File tree

4 files changed

+186
-118
lines changed

4 files changed

+186
-118
lines changed

demo/src/screens/ExampleScreenPresenter.js

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import _ from 'lodash';
22
import React from 'react';
33
import {StyleSheet} from 'react-native';
4-
import {Checkbox, Switch, ColorPalette, Colors, RadioButton, RadioGroup, Slider, Text, View} from 'react-native-ui-lib';
4+
import {
5+
Checkbox,
6+
Switch,
7+
ColorPalette,
8+
Colors,
9+
RadioButton,
10+
RadioGroup,
11+
Slider,
12+
SegmentedControl,
13+
Text,
14+
View
15+
} from 'react-native-ui-lib';
516

617
export function renderHeader(title, others) {
718
return (
@@ -15,7 +26,7 @@ export function renderBooleanOption(title, key) {
1526
const value = this.state[key];
1627
return (
1728
<View row centerV spread marginB-s4 key={key}>
18-
<Text text70 style={{flex: 1}}>
29+
<Text flex>
1930
{title}
2031
</Text>
2132
<Switch
@@ -63,9 +74,11 @@ export function renderRadioGroup(title, key, options, {isRow, afterValueChanged,
6374
const value = this.state[key];
6475
return (
6576
<View marginB-s2>
66-
{!_.isUndefined(title) && <Text text70M marginB-s2>
67-
{title}
68-
</Text>}
77+
{!_.isUndefined(title) && (
78+
<Text text70M marginB-s2>
79+
{title}
80+
</Text>
81+
)}
6982
<RadioGroup
7083
row={isRow}
7184
style={isRow && styles.rowWrap}
@@ -132,6 +145,22 @@ export function renderSliderOption(title, key, {min = 0, max = 10, step = 1, ini
132145
);
133146
}
134147

148+
export function renderMultipleSegmentOptions(title, key, options) {
149+
const value = this.state[key];
150+
const index = _.findIndex(options, {value});
151+
152+
return (
153+
<View row centerV spread marginB-s4 key={key}>
154+
<Text marginR-s2>{title}</Text>
155+
<SegmentedControl
156+
initialIndex={index}
157+
segments={options}
158+
onChangeIndex={index => this.setState({[key]: options[index].value})}
159+
/>
160+
</View>
161+
);
162+
}
163+
135164
const styles = StyleSheet.create({
136165
rowWrap: {
137166
flexWrap: 'wrap'

demo/src/screens/componentScreens/HintsScreen.tsx

Lines changed: 97 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,34 @@
11
import _ from 'lodash';
22
import React, {Component} from 'react';
33
import {Alert} from 'react-native';
4-
import {Colors, View, Text, Hint, Button, RadioGroup, RadioButton, Switch} from 'react-native-ui-lib';
4+
import {Colors, View, Text, Hint, Button, Assets, Incubator} from 'react-native-ui-lib';
5+
// @ts-expect-error
6+
import {renderMultipleSegmentOptions, renderBooleanOption} from '../ExampleScreenPresenter';
57

68
const settingsIcon = require('../../assets/icons/settings.png');
79
const reactions = ['❤️', '😮', '😔', '😂', '😡'];
810

911
type HintScreenProps = {};
10-
type HintScreenState = {
11-
showHint: boolean;
12-
useShortMessage: boolean;
13-
showBottomHint: boolean;
14-
showIcon: boolean;
15-
targetPosition: string;
16-
useTargetFrame?: boolean;
17-
useSideTip?: boolean;
18-
showCustomContent?: boolean;
19-
showReactionStrip?: boolean;
20-
enableShadow?: boolean;
21-
};
22-
23-
export default class HintsScreen extends Component<HintScreenProps, HintScreenState> {
24-
constructor(props: HintScreenProps) {
25-
super(props);
26-
27-
this.state = {
28-
showHint: true,
29-
useShortMessage: false,
30-
showBottomHint: false,
31-
showIcon: false,
32-
targetPosition: 'flex-start',
33-
// useTargetFrame: true,
34-
useSideTip: false,
35-
showCustomContent: false,
36-
showReactionStrip: false,
37-
enableShadow: false
38-
};
39-
}
12+
13+
export default class HintsScreen extends Component<HintScreenProps> {
14+
15+
state = {
16+
showHint: true,
17+
useShortMessage: false,
18+
showBottomHint: false,
19+
showIcon: false,
20+
targetPosition: 'flex-start',
21+
useBackdrop: true,
22+
useTargetFrame: false,
23+
useSideTip: false,
24+
showCustomContent: false,
25+
showReactionStrip: false,
26+
enableShadow: false
27+
};
28+
29+
toggleHint = () => {
30+
this.setState({showHint: !this.state.showHint});
31+
};
4032

4133
toggleHintPosition = () => {
4234
this.setState({
@@ -74,12 +66,64 @@ export default class HintsScreen extends Component<HintScreenProps, HintScreenSt
7466
);
7567
}
7668

69+
renderOptionsFAB() {
70+
return (
71+
<View absR absB padding-page style={{zIndex: 10}}>
72+
<Incubator.ExpandableOverlay
73+
useDialog
74+
expandableContent={this.renderScreenOptions()}
75+
dialogProps={{bottom: true}}
76+
>
77+
<Button round iconSource={Assets.icons.demo.settings} white/>
78+
</Incubator.ExpandableOverlay>
79+
</View>
80+
);
81+
}
82+
83+
renderScreenOptions() {
84+
return (
85+
<View bg-white br20 padding-20 collapsable={false}>
86+
<Text h2 marginB-s4>
87+
Hint Options
88+
</Text>
89+
{renderMultipleSegmentOptions.call(this, 'Button Position', 'targetPosition', [
90+
{label: 'Left', value: 'flex-start'},
91+
{label: 'Center', value: 'center'},
92+
{label: 'Right', value: 'flex-end'}
93+
])}
94+
95+
{renderMultipleSegmentOptions.call(this, 'Tip Position', 'useSideTip', [
96+
{label: 'Side Tip', value: true},
97+
{label: 'Middle Top', value: false}
98+
])}
99+
100+
{renderMultipleSegmentOptions.call(this, 'Hint Position', 'showBottomHint', [
101+
{label: 'Above', value: false},
102+
{label: 'Under', value: true}
103+
])}
104+
105+
{renderMultipleSegmentOptions.call(this, 'Message Length', 'useShortMessage', [
106+
{label: 'Short', value: true},
107+
{label: 'Long', value: false}
108+
])}
109+
110+
{renderBooleanOption.call(this, 'With backdrop', 'useBackdrop')}
111+
{renderBooleanOption.call(this, 'With icon', 'showIcon')}
112+
{renderBooleanOption.call(this, 'With shadow', 'enableShadow')}
113+
{renderBooleanOption.call(this, 'Use random position', 'useTargetFrame')}
114+
{renderBooleanOption.call(this, 'Show custom content', 'showCustomContent')}
115+
{renderBooleanOption.call(this, 'Show reaction strip', 'showReactionStrip')}
116+
</View>
117+
);
118+
}
119+
77120
render() {
78121
const {
79122
showHint,
80123
showBottomHint,
81124
showIcon,
82125
targetPosition,
126+
useBackdrop,
83127
useShortMessage,
84128
useSideTip,
85129
useTargetFrame,
@@ -126,7 +170,8 @@ export default class HintsScreen extends Component<HintScreenProps, HintScreenSt
126170
targetFrame={useTargetFrame ? targetFrame : undefined}
127171
// borderRadius={BorderRadiuses.br40}
128172
// edgeMargins={30}
129-
// onBackgroundPress={() => this.setState({showHint: !showHint})}
173+
onBackgroundPress={useBackdrop && !useTargetFrame ? this.toggleHint : undefined}
174+
backdropColor={Colors.rgba(Colors.grey10, 0.3)}
130175
customContent={
131176
showCustomContent
132177
? this.renderCustomContent()
@@ -142,93 +187,38 @@ export default class HintsScreen extends Component<HintScreenProps, HintScreenSt
142187
{!useTargetFrame && (
143188
<Button
144189
label={showHint ? 'Hide' : 'Show'}
145-
onPress={() => this.setState({showHint: !showHint})}
190+
onPress={this.toggleHint}
146191
style={{alignSelf: targetPosition}}
147192
testID={'Hint.button'}
193+
/* Change layout and position to test various cases */
194+
// marginT-150
148195
// style={{alignSelf: targetPosition, marginLeft: 30}}
149196
// style={{alignSelf: targetPosition, position: 'absolute', top: 160, left: 100}}
150197
/>
151198
)}
152199
</Hint>
153200

154201
{useTargetFrame && (
155-
<View
156-
bg-red50
157-
style={{
158-
position: 'absolute',
159-
top: targetFrame.y,
160-
left: targetFrame.x,
161-
width: targetFrame.width,
162-
height: targetFrame.height
163-
}}
164-
/>
202+
<>
203+
<View
204+
bg-red50
205+
style={{
206+
position: 'absolute',
207+
top: targetFrame.y,
208+
left: targetFrame.x,
209+
width: targetFrame.width,
210+
height: targetFrame.height
211+
}}
212+
/>
213+
214+
<View absL absB margin-page>
215+
<Button label="Show Hint" onPress={this.toggleHint}/>
216+
</View>
217+
</>
165218
)}
166219
</View>
167220

168-
<View padding-20 collapsable={false}>
169-
<RadioGroup
170-
row
171-
centerV
172-
marginB-20
173-
initialValue={targetPosition}
174-
onValueChange={(value: string) => this.setState({targetPosition: value})}
175-
>
176-
<Text marginR-10>Button Position:</Text>
177-
<RadioButton value={'flex-start'} label={'Left'} marginR-10/>
178-
<RadioButton value={'center'} label={'Center'} marginR-10/>
179-
<RadioButton value={'flex-end'} label={'Right'} marginR-10/>
180-
</RadioGroup>
181-
182-
<RadioGroup
183-
row
184-
centerV
185-
marginB-20
186-
initialValue={useSideTip}
187-
onValueChange={(value: boolean) => this.setState({useSideTip: value})}
188-
>
189-
<Text marginR-10>Tip:</Text>
190-
<RadioButton value label={'Side Tip'} marginR-10/>
191-
<RadioButton value={false} label={'Middle Tip'} marginR-10/>
192-
</RadioGroup>
193-
194-
<View row centerV marginV-10>
195-
<Switch value={showBottomHint} onValueChange={this.toggleHintPosition}/>
196-
<Text marginL-10>Toggle Hint Position</Text>
197-
</View>
198-
199-
<View row centerV marginV-10>
200-
<Switch value={useShortMessage} onValueChange={() => this.setState({useShortMessage: !useShortMessage})}/>
201-
<Text marginL-10>Toggle Message</Text>
202-
</View>
203-
204-
<View row centerV marginV-10>
205-
<Switch value={showIcon} onValueChange={value => this.setState({showIcon: value})}/>
206-
<Text marginL-10>Toggle Icon</Text>
207-
</View>
208-
209-
<View row centerV marginV-10>
210-
<Switch value={enableShadow} onValueChange={value => this.setState({enableShadow: value})}/>
211-
<Text marginL-10>Toggle shadow</Text>
212-
</View>
213-
214-
<View row centerV marginV-10>
215-
<Switch value={useTargetFrame} onValueChange={value => this.setState({useTargetFrame: value})}/>
216-
<Text marginL-10>Use random position</Text>
217-
</View>
218-
219-
<View row centerV marginV-10>
220-
<Switch value={showCustomContent} onValueChange={value => this.setState({showCustomContent: value})}/>
221-
<Text marginL-10>Show custom content</Text>
222-
</View>
223-
224-
<View row centerV marginV-10>
225-
<Switch
226-
value={showReactionStrip}
227-
onValueChange={value => this.setState({showReactionStrip: value, enableShadow: true})}
228-
/>
229-
<Text marginL-10>Show reaction strip</Text>
230-
</View>
231-
</View>
221+
{this.renderOptionsFAB()}
232222
</View>
233223
);
234224
}

generatedTypes/src/components/hint/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export interface HintProps {
7575
* Callback for the background press
7676
*/
7777
onBackgroundPress?: (event: GestureResponderEvent) => void;
78+
/**
79+
* Color for background overlay (require onBackgroundPress)
80+
*/
81+
backdropColor?: string;
7882
/**
7983
* The hint container width
8084
*/
@@ -165,6 +169,7 @@ declare class Hint extends Component<HintProps, HintState> {
165169
renderContent(): JSX.Element;
166170
renderHint(): JSX.Element | undefined;
167171
renderHintContainer(): JSX.Element;
172+
renderMockChildren(): JSX.Element | undefined;
168173
renderChildren(): React.ReactElement<any, string | React.JSXElementConstructor<any>> | undefined;
169174
render(): {} | null;
170175
}

0 commit comments

Comments
 (0)