Skip to content

Commit aaaf4c3

Browse files
authored
Feat/incubator dialog more props and fixes (wix#2251)
* Handle visible undefined * Change value to correspond for the new name * Support width and height in Dialog and a few more props in DialogHeader * Add center to the Dialog style * Better test for Header existence * Allow migrating ActionSheet to Incubator.Dialog * Allow Incubator.WheelPicker to be inside Incubator.Dialog * Migrate a couple of screens to Incubator.Dialog * Fix tests * Review fixes
1 parent f7e2c81 commit aaaf4c3

File tree

14 files changed

+197
-45
lines changed

14 files changed

+197
-45
lines changed

demo/src/screens/componentScreens/ActionSheetScreen.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export default class ActionSheetScreen extends Component {
6464
cancelButtonIndex={3}
6565
destructiveButtonIndex={0}
6666
useNativeIOS={false}
67+
migrateDialog
6768
options={[
6869
{label: 'option 1', onPress: () => this.pickOption('option 1')},
6970
{label: 'option 2', onPress: () => this.pickOption('option 2')},
@@ -79,6 +80,7 @@ export default class ActionSheetScreen extends Component {
7980
message={'Message of action sheet'}
8081
cancelButtonIndex={3}
8182
destructiveButtonIndex={0}
83+
migrateDialog
8284
options={[
8385
{label: 'option 1', onPress: () => this.pickOption('option 1'), iconSource: collectionsIcon},
8486
{label: 'option 2', onPress: () => this.pickOption('option 2'), iconSource: shareIcon},

demo/src/screens/componentScreens/ChipScreen.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import _ from 'lodash';
22
import React, {Component} from 'react';
33
import {Alert} from 'react-native';
4-
import {Chip, Colors, Spacings, Text, Typography, View, Dialog, WheelPickerDialog, Image} from 'react-native-ui-lib';
4+
import {Chip, Colors, Spacings, Text, Typography, View, Incubator, WheelPickerDialog, Image} from 'react-native-ui-lib';
55

66
const avatarImage = {
77
uri: 'https://randomuser.me/api/portraits/women/24.jpg'
@@ -72,9 +72,9 @@ export default class ChipScreen extends Component {
7272
const {showDialog} = this.state;
7373

7474
return (
75-
<Dialog visible={showDialog} useSafeArea bottom onDismiss={this.closeDialog}>
75+
<Incubator.Dialog visible={showDialog} useSafeArea bottom onDismiss={this.closeDialog}>
7676
{this.renderContent()}
77-
</Dialog>
77+
</Incubator.Dialog>
7878
);
7979
};
8080

@@ -90,7 +90,7 @@ export default class ChipScreen extends Component {
9090
render() {
9191
return (
9292
<View style={{padding: 20}}>
93-
{this.state.showDialog && this.renderPickerDialog()}
93+
{this.renderPickerDialog()}
9494
<Text marginB-20 text40 $textDefault>
9595
Chip
9696
</Text>

demo/src/screens/componentScreens/PickerScreen.tsx

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import _ from 'lodash';
22
import React, {Component} from 'react';
3-
import {ScrollView} from 'react-native';
3+
import {ScrollView} from 'react-native-gesture-handler';
44
import {
55
View,
66
Colors,
77
Icon,
8-
Dialog,
8+
Incubator,
99
Text,
1010
Picker,
1111
Avatar,
@@ -14,7 +14,6 @@ import {
1414
Typography,
1515
PickerProps,
1616
PickerMethods,
17-
DialogProps,
1817
Button
1918
} from 'react-native-ui-lib'; //eslint-disable-line
2019
import contactsData from '../../data/conversations';
@@ -61,20 +60,11 @@ export default class PickerScreen extends Component {
6160
contact: 0
6261
};
6362

64-
dialogHeader: DialogProps['renderPannableHeader'] = props => {
65-
const {title} = props;
66-
return (
67-
<Text margin-15 text60 $textDefault>
68-
{title}
69-
</Text>
70-
);
71-
};
72-
7363
renderDialog: PickerProps['renderCustomModal'] = modalProps => {
7464
const {visible, children, toggleModal, onDone} = modalProps;
7565

7666
return (
77-
<Dialog
67+
<Incubator.Dialog
7868
visible={visible}
7969
onDismiss={() => {
8070
onDone();
@@ -85,12 +75,11 @@ export default class PickerScreen extends Component {
8575
bottom
8676
useSafeArea
8777
containerStyle={{backgroundColor: Colors.$backgroundDefault}}
88-
renderPannableHeader={this.dialogHeader}
89-
panDirection={PanningProvider.Directions.DOWN}
90-
pannableHeaderProps={{title: 'Custom modal'}}
78+
direction={PanningProvider.Directions.DOWN}
79+
headerProps={{title: 'Custom modal'}}
9180
>
9281
<ScrollView>{children}</ScrollView>
93-
</Dialog>
82+
</Incubator.Dialog>
9483
);
9584
};
9685

demo/src/screens/incubatorScreens/WheelPickerScreen.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import _ from 'lodash';
22
import React, {useCallback, useState} from 'react';
3-
import {View, Text, Incubator, Colors, Typography, Button, Dialog} from 'react-native-ui-lib';
3+
import {View, Text, Incubator, Colors, Typography, Button} from 'react-native-ui-lib';
44

55
const monthItems = _.map([
66
'January',
@@ -88,9 +88,15 @@ export default () => {
8888
<View center marginT-40>
8989
<Text h3 marginB-20>Days</Text>
9090
<Button size="small" label={'Pick Days'} onPress={onPickDaysPress}/>
91-
<Dialog width={'90%'} height={260} bottom visible={showDialog} onDismiss={onDialogDismissed}>
91+
<Incubator.Dialog
92+
width={'90%'}
93+
bottom
94+
visible={showDialog}
95+
onDismiss={onDialogDismissed}
96+
headerProps={{showKnob: false, showDivider: false}}
97+
>
9298
<Incubator.WheelPicker initialValue={5} label={'Days'} items={dayItems}/>
93-
</Dialog>
99+
</Incubator.Dialog>
94100
</View>
95101
</View>
96102
);

jest-setup.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ jest.mock('react-native-reanimated', () => {
1616
return reactNativeReanimated;
1717
});
1818
global.__reanimatedWorkletInit = jest.fn();
19-
jest.mock('react-native-gesture-handler', () => {});
19+
jest.mock('react-native-gesture-handler',
20+
() => ({
21+
FlatList: require('react-native').FlatList
22+
}),
23+
{virtual: true});
2024
jest.mock('@react-native-picker/picker', () => ({Picker: {Item: {}}}));
2125
jest.mock('react-native', () => {
2226
const reactNative = jest.requireActual('react-native');

src/components/actionSheet/index.tsx

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ import Image from '../image';
1111
//@ts-ignore
1212
import ListItem from '../listItem';
1313
import PanningProvider from '../panningViews/panningProvider';
14+
import {Dialog as IncubatorDialog, DialogProps as IncubatorDialogProps} from '../../incubator';
15+
import {LogService} from '../../services';
1416

1517
const VERTICAL_PADDING = 8;
1618
type ActionSheetOnOptionPress = (index: number) => void;
1719

1820
type ActionSheetProps = {
21+
/**
22+
* Migrate to the Incubator.Dialog component
23+
*/
24+
migrateDialog?: boolean;
1925
/**
2026
* Whether to show the action sheet or not
2127
*/
@@ -76,6 +82,7 @@ type ActionSheetProps = {
7682
*/
7783
renderAction?: (option: ButtonProps, index: number, onOptionPress: ActionSheetOnOptionPress) => JSX.Element;
7884
/**
85+
* @deprecated
7986
* Called once the modal has been dismissed completely
8087
*/
8188
onModalDismissed?: DialogProps['onDialogDismissed'];
@@ -89,7 +96,7 @@ type ActionSheetProps = {
8996
dialogProps?: Omit<
9097
DialogProps,
9198
'useSafeArea' | 'testID' | 'containerStyle' | 'visible' | 'onDismiss' | 'onDialogDismissed'
92-
>;
99+
> | IncubatorDialogProps;
93100
/**
94101
* testID for e2e tests
95102
*/
@@ -213,7 +220,7 @@ class ActionSheet extends Component<ActionSheetProps> {
213220
);
214221
}
215222

216-
render() {
223+
renderOldDialog() {
217224
const {useNativeIOS, visible, onDismiss, dialogStyle, onModalDismissed, testID, useSafeArea, dialogProps} =
218225
this.props;
219226

@@ -239,6 +246,41 @@ class ActionSheet extends Component<ActionSheetProps> {
239246
</Dialog>
240247
);
241248
}
249+
250+
renderNewDialog() {
251+
const {visible, onDismiss, dialogStyle, onModalDismissed, testID, useSafeArea, dialogProps} = this.props;
252+
253+
if (onModalDismissed) {
254+
LogService.deprecationWarn({component: 'ActionSheet', oldProp: 'onModalDismissed', newProp: 'onDismiss'});
255+
}
256+
257+
return (
258+
// @ts-expect-error height might be null here
259+
<IncubatorDialog
260+
bottom
261+
centerH
262+
width="100%"
263+
direction={PanningProvider.Directions.DOWN}
264+
{...dialogProps}
265+
useSafeArea={useSafeArea}
266+
testID={testID}
267+
containerStyle={[styles.incubatorDialog, dialogStyle]}
268+
visible={visible}
269+
onDismiss={onDismiss}
270+
>
271+
{this.renderSheet()}
272+
</IncubatorDialog>
273+
);
274+
}
275+
276+
render() {
277+
const {migrateDialog} = this.props;
278+
if (migrateDialog) {
279+
return this.renderNewDialog();
280+
} else {
281+
return this.renderOldDialog();
282+
}
283+
}
242284
}
243285

244286
export default asBaseComponent<ActionSheetProps>(ActionSheet);
@@ -250,6 +292,10 @@ const styles = StyleSheet.create({
250292
dialog: {
251293
backgroundColor: Colors.white
252294
},
295+
incubatorDialog: {
296+
backgroundColor: Colors.white,
297+
marginBottom: 0
298+
},
253299
listWithTitle: {
254300
paddingBottom: VERTICAL_PADDING
255301
},

src/incubator/Dialog/DialogHeader.tsx

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {StyleSheet} from 'react-native';
44
import {asBaseComponent} from '../../commons/new';
55
import {Spacings, Colors, BorderRadiuses, Dividers} from 'style';
66
import View from '../../components/view';
7+
import TouchableOpacity from '../../components/touchableOpacity';
78
import Text from '../../components/text';
89
import {DialogHeaderProps} from './types';
910

@@ -18,6 +19,12 @@ const DialogHeader = (props: DialogHeaderProps = {}) => {
1819
renderContent,
1920
showKnob = true,
2021
showDivider = true,
22+
leadingAccessory,
23+
trailingAccessory,
24+
contentContainerStyle,
25+
onPress,
26+
bottomAccessory,
27+
style,
2128
...others
2229
} = props;
2330

@@ -32,9 +39,10 @@ const DialogHeader = (props: DialogHeaderProps = {}) => {
3239
return renderContent(props);
3340
}
3441

42+
const Container = onPress ? TouchableOpacity : View;
3543
if (!isEmpty(title) || !isEmpty(subtitle)) {
3644
return (
37-
<View marginH-s5 marginV-s1>
45+
<Container onPress={onPress} center flex>
3846
{title && (
3947
<Text $textDefault {...titleProps} marginB-s3 style={titleStyle}>
4048
{title}
@@ -45,25 +53,40 @@ const DialogHeader = (props: DialogHeaderProps = {}) => {
4553
{subtitle}
4654
</Text>
4755
)}
48-
</View>
56+
</Container>
4957
);
5058
}
5159

5260
return null;
5361
// eslint-disable-next-line react-hooks/exhaustive-deps
5462
}, [renderContent, title, titleStyle, titleProps, subtitle, subtitleStyle, subtitleProps]);
5563

64+
const content = useMemo(() => {
65+
if (headerContent || leadingAccessory || trailingAccessory) {
66+
return (
67+
<View marginH-s5 marginV-s1 style={contentContainerStyle} row spread>
68+
{leadingAccessory}
69+
{headerContent}
70+
{trailingAccessory}
71+
</View>
72+
);
73+
}
74+
75+
return null;
76+
}, [headerContent, leadingAccessory, trailingAccessory, contentContainerStyle]);
77+
5678
const divider = useMemo(() => {
5779
if (showDivider) {
5880
return <View style={Dividers.d10}/>;
5981
}
6082
}, [showDivider]);
6183

62-
if (!isEmpty(props)) {
84+
if (knob || content || bottomAccessory || divider) {
6385
return (
64-
<View {...others}>
86+
<View {...others} style={style}>
6587
{knob}
66-
{headerContent}
88+
{content}
89+
{bottomAccessory}
6790
{divider}
6891
</View>
6992
);
@@ -72,6 +95,8 @@ const DialogHeader = (props: DialogHeaderProps = {}) => {
7295
return null;
7396
};
7497

98+
DialogHeader.displayName = 'Incubator.Dialog.Header';
99+
75100
export default asBaseComponent<DialogHeaderProps>(DialogHeader);
76101

77102
const styles = StyleSheet.create({
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "Dialog.Header",
3+
"category": "incubator",
4+
"description": "Component for displaying the header of a popup dialog",
5+
"props": [
6+
{"name": "title", "type": "string", "description": "Title"},
7+
{"name": "titleStyle", "type": "StyleProp<TextStyle>", "description": "Title text style"},
8+
{"name": "titleProps", "type": "TextProps", "description": "Title extra props"},
9+
{"name": "subtitle", "type": "string", "description": "Subtitle"},
10+
{"name": "subtitleStyle", "type": "StyleProp<TextStyle>", "description": "Subtitle text style"},
11+
{"name": "subtitleProps", "type": "TextProps", "description": "Subtitle extra props"},
12+
{
13+
"name": "renderContent",
14+
"type": "(props: DialogHeaderProps) => React.ReactElement",
15+
"description": "Replace the header's default content (Dialog.Text)"
16+
},
17+
{"name": "showKnob", "type": "boolean", "description": "Show the header's knob", "default": "true"},
18+
{"name": "showDivider", "type": "boolean", "description": "Show the header's divider", "default": "true"},
19+
{"name": "leadingAccessory", "type": "ReactElement", "description": "Pass to render a leading element"},
20+
{"name": "trailingAccessory", "type": "ReactElement", "description": "Pass to render a trailing element"},
21+
{
22+
"name": "contentContainerStyle",
23+
"type": "ViewProps['style']",
24+
"description": "Style for the leading + content + trailing components (without the bottomAccessory)"
25+
},
26+
{
27+
"name": "onPress",
28+
"type": "() => void",
29+
"description": "onPress callback for the inner content"
30+
},
31+
{
32+
"name": "bottomAccessory",
33+
"type": "ReactElement",
34+
"description": "Pass to render a bottom element below the input"
35+
}
36+
]
37+
}

0 commit comments

Comments
 (0)