Skip to content

Commit 97afa07

Browse files
authored
refactor(ui): modal component reimplement
1 parent 241ade4 commit 97afa07

17 files changed

+844
-715
lines changed

docs/package-lock.json

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/src/structure.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,14 @@ export const structure = [
411411
type: 'group',
412412
name: 'Modals & Overlays',
413413
},
414+
{
415+
type: 'tabs',
416+
name: 'Modal',
417+
icon: 'dialog.svg',
418+
source: [
419+
'Modal',
420+
],
421+
},
414422
{
415423
type: 'tabs',
416424
name: 'Overflow Menu',
@@ -426,14 +434,6 @@ export const structure = [
426434
},
427435
],
428436
},
429-
{
430-
type: 'tabs',
431-
name: 'Modal',
432-
icon: 'dialog.svg',
433-
source: [
434-
'Modal',
435-
],
436-
},
437437
{
438438
type: 'tabs',
439439
name: 'Popover',

src/framework/theme/modal/modalPanel.component.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
StyleSheet,
55
ViewProps,
66
} from 'react-native';
7-
import { Modal } from '../../ui/modal/modal.component';
7+
import { ModalResolver } from './modalResolver.component';
88
import {
99
ModalService,
1010
ModalPresenting,
@@ -77,7 +77,7 @@ export class ModalPanel extends React.Component<ModalPanelProps, ModalPanelState
7777
.find(item => this.state.components.get(item) === modal);
7878
const closeOnBackdrop: boolean = this.state.backdrops.get(identifier);
7979
return (
80-
<Modal
80+
<ModalResolver
8181
{...modal.props}
8282
visible={true}
8383
isBackDropAllowed={closeOnBackdrop}
@@ -86,7 +86,7 @@ export class ModalPanel extends React.Component<ModalPanelProps, ModalPanelState
8686
onCloseModal={this.hide}
8787
>
8888
{modal}
89-
</Modal>
89+
</ModalResolver>
9090
);
9191
}
9292

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/**
2+
* @license
3+
* Copyright Akveo. All Rights Reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*/
6+
7+
import React from 'react';
8+
import {
9+
View,
10+
ViewProps,
11+
StyleSheet,
12+
TouchableOpacity,
13+
TouchableOpacityProps,
14+
} from 'react-native';
15+
16+
type ChildElement = React.ReactElement<any>;
17+
type ChildrenProp = ChildElement | ChildElement[];
18+
19+
interface ComponentProps {
20+
visible: boolean;
21+
children: ChildrenProp;
22+
isBackDropAllowed?: boolean;
23+
identifier?: string;
24+
onCloseModal?: (index: string) => void;
25+
}
26+
27+
export type ModalResolverProps = ViewProps & ComponentProps;
28+
29+
export class ModalResolver extends React.Component<ModalResolverProps> {
30+
31+
static defaultProps: Partial<ModalResolverProps> = {
32+
visible: false,
33+
isBackDropAllowed: false,
34+
};
35+
36+
private closeModal = (): void => {
37+
if (this.props.onCloseModal) {
38+
this.props.onCloseModal(this.props.identifier);
39+
}
40+
};
41+
42+
private closeOnBackdrop: () => void = () => {
43+
if (this.props.isBackDropAllowed) {
44+
this.closeModal();
45+
}
46+
};
47+
48+
private onStartShouldSetResponder = (): boolean => {
49+
return true;
50+
};
51+
52+
private onResponderRelease = (): void => {
53+
return;
54+
};
55+
56+
private onStartShouldSetResponderCapture = (): boolean => {
57+
return false;
58+
};
59+
60+
private renderComponentChild = (source: React.ReactElement<any>): React.ReactElement<any> => {
61+
return React.cloneElement(source, {
62+
onCloseModal: this.closeModal,
63+
style: [source.props.style, this.props.style],
64+
});
65+
};
66+
67+
private renderComponentChildren = (source: React.ReactNode): React.ReactElement<any>[] => {
68+
return React.Children.map(source, this.renderComponentChild);
69+
};
70+
71+
private renderWithBackDrop = (component: React.ReactElement<ViewProps>):
72+
React.ReactElement<TouchableOpacityProps> => {
73+
74+
return (
75+
<TouchableOpacity
76+
style={styles.container}
77+
onPress={this.closeOnBackdrop}
78+
activeOpacity={1}>
79+
{component}
80+
</TouchableOpacity>
81+
);
82+
};
83+
84+
private renderWithoutBackDrop = (component: React.ReactElement<ViewProps>): React.ReactElement<ViewProps> => {
85+
return (
86+
<View style={styles.notVisibleWrapper}>
87+
<View
88+
style={styles.container}
89+
pointerEvents='none'/>
90+
{component}
91+
</View>
92+
);
93+
};
94+
95+
private renderComponent = (): React.ReactElement<TouchableOpacityProps | ViewProps> => {
96+
const { children, isBackDropAllowed, ...derivedProps } = this.props;
97+
const componentChildren: React.ReactElement<any>[] = this.renderComponentChildren(children);
98+
99+
const dialog: React.ReactElement<ViewProps> =
100+
<View
101+
{...derivedProps}
102+
style={styles.contentWrapper}
103+
onStartShouldSetResponder={this.onStartShouldSetResponder}
104+
onResponderRelease={this.onResponderRelease}
105+
onStartShouldSetResponderCapture={this.onStartShouldSetResponderCapture}
106+
pointerEvents='box-none'>
107+
{componentChildren}
108+
</View>;
109+
110+
return isBackDropAllowed ?
111+
this.renderWithBackDrop(dialog) : this.renderWithoutBackDrop(dialog);
112+
};
113+
114+
public render(): React.ReactElement<ViewProps | TouchableOpacityProps> | null {
115+
return this.props.visible ? this.renderComponent() : null;
116+
}
117+
}
118+
119+
const styles = StyleSheet.create({
120+
container: StyleSheet.absoluteFillObject,
121+
notVisibleWrapper: {
122+
position: 'absolute',
123+
width: 0,
124+
height: 0,
125+
},
126+
contentWrapper: {
127+
alignSelf: 'flex-start',
128+
},
129+
});

0 commit comments

Comments
 (0)