Skip to content
This repository was archived by the owner on Nov 3, 2025. It is now read-only.

Commit 8889cfa

Browse files
committed
🐛 (FullScreenPortal) fix full screen portal
1 parent 0f8ab46 commit 8889cfa

6 files changed

Lines changed: 93 additions & 33 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"@types/jest": "^24.0.11",
4444
"@types/react-native": "^0.60.0",
4545
"@types/react-test-renderer": "^16.8.1",
46+
"@types/recompose": "^0.30.6",
4647
"@typescript-eslint/eslint-plugin": "^1.12.0",
4748
"@typescript-eslint/parser": "^1.12.0",
4849
"babel-jest": "^24.7.0",

src/Canal.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { map, publish } from 'rxjs/operators';
88
import { ConnectableObservable } from 'rxjs';
99
import { BackContext } from './Navigation/BackContext';
1010
import { Screen, ScreenProps } from './Screen';
11+
import { Navigation } from './Navigation';
1112

1213
interface Props {
1314
children: ReactElement<ScreenProps, typeof Screen>[] | ReactElement<ScreenProps, typeof Screen>;
@@ -20,6 +21,8 @@ class CanalComponent extends Component<WithBackContext<Props>> {
2021
this.back$.connect();
2122
}
2223

24+
canalId: string = Date.now().toString();
25+
2326
static defaultProps = { style: StyleSheet.absoluteFill };
2427

2528
/**
@@ -42,6 +45,32 @@ class CanalComponent extends Component<WithBackContext<Props>> {
4245
publish()
4346
);
4447

48+
componentDidUpdate() {
49+
this.notifyFullScreenDelegate();
50+
}
51+
52+
componentDidMount() {
53+
this.notifyFullScreenDelegate();
54+
}
55+
56+
componentWillUnmount() {
57+
Navigation.instance.fullScreenDelegate.canalsFullScreenStackProperties$.next({
58+
canalId: this.canalId,
59+
fullScreenStack: [],
60+
});
61+
}
62+
63+
notifyFullScreenDelegate = () => {
64+
const { children: reactChildren } = this.props;
65+
const fullScreenChildren = arrayify<ReactElement<ScreenProps, typeof Screen>>(
66+
reactChildren
67+
).filter(child => child.props.isFullScreen);
68+
Navigation.instance.fullScreenDelegate.canalsFullScreenStackProperties$.next({
69+
canalId: this.canalId,
70+
fullScreenStack: fullScreenChildren,
71+
});
72+
};
73+
4574
render() {
4675
const { children: reactChildren } = this.props;
4776
const children = arrayify<ReactElement<ScreenProps, typeof Screen>>(reactChildren).filter(

src/FullScreenPortal.tsx

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,60 @@
1-
import React, { Component as ReactComponent, Fragment } from 'react';
1+
import React, { Component, Fragment } from 'react';
22
import { View, StyleSheet } from 'react-native';
3-
import { Observer } from 'mobx-react';
4-
import { fromStream } from 'mobx-utils';
3+
import { from } from 'rxjs';
4+
import { componentFromStreamWithConfig } from 'recompose';
5+
56
import { Navigation } from './Navigation';
7+
import { map, publish, withLatestFrom } from 'rxjs/operators';
8+
import { withBackContext, WithBackContext } from './withBackContext';
9+
import { BackContext } from './Navigation/BackContext';
10+
import { last } from './utils/Array.last';
11+
12+
class FullScreenPortalComponent extends Component<WithBackContext<{}>> {
13+
static FullScreenStack = componentFromStreamWithConfig({
14+
fromESObservable: from,
15+
toESObservable: stream => stream,
16+
})(() =>
17+
Navigation.instance.fullScreenDelegate.fullSceenStack$.pipe(
18+
map(fullScreenStack => <>{fullScreenStack}</>)
19+
)
20+
);
621

7-
export class FullScreenPortal extends ReactComponent {
8-
fullScreenStack = fromStream(Navigation.instance.fullScreenDelegate.fullSceenStack$);
22+
constructor(props: WithBackContext<{}>) {
23+
super(props);
24+
this.back$.connect();
25+
}
26+
27+
/**
28+
* @TODO Pipe operator cannot infer return type as ConnectableObservable.
29+
* See https://github.com/ReactiveX/rxjs/issues/2972.
30+
*/
31+
// @ts-ignore
32+
back$: ConnectableObservable<BackEvent> = this.props.backContext.back$.pipe(
33+
withLatestFrom(Navigation.instance.fullScreenDelegate.fullSceenStack$),
34+
map(([_, fullScreenStack]) => {
35+
const currentScreen = last(fullScreenStack.filter(screen => screen.props.visible));
36+
if (currentScreen) {
37+
return { target: currentScreen.props.name };
38+
}
39+
return { target: null };
40+
}),
41+
publish()
42+
);
943

1044
render() {
1145
return (
12-
<View style={StyleSheet.absoluteFill}>
13-
<Fragment>{this.props.children}</Fragment>
14-
<Observer>
15-
{() => {
16-
if (this.fullScreenStack.current) {
17-
return (
18-
<Fragment>
19-
{this.fullScreenStack.current &&
20-
this.fullScreenStack.current.map(({ Component, name, isAuthorized }) => (
21-
<Component isAuthorized={isAuthorized} key={name} />
22-
))}
23-
</Fragment>
24-
);
25-
}
26-
/**
27-
* @todo Improve typing of <Observer /> to accept null JSXElement.
28-
* Expected: `return null;`
29-
*/
30-
return <Fragment />;
31-
}}
32-
</Observer>
33-
</View>
46+
<BackContext.Provider
47+
value={{
48+
back$: this.back$,
49+
}}
50+
>
51+
<View style={StyleSheet.absoluteFill}>
52+
<Fragment>{this.props.children}</Fragment>
53+
<FullScreenPortalComponent.FullScreenStack />
54+
</View>
55+
</BackContext.Provider>
3456
);
3557
}
3658
}
59+
60+
export const FullScreenPortal = withBackContext(FullScreenPortalComponent);

src/Navigation/FullScreenDelegate.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { Subject, Observable } from 'rxjs';
2-
import { mergeAll, map, scan } from 'rxjs/operators';
3-
import { StopInterface } from './Stop';
2+
import { map, scan } from 'rxjs/operators';
3+
import { ReactElement } from 'react';
4+
import { ScreenProps, Screen } from '../Screen';
45

5-
type Stack = StopInterface[];
6+
type Stack = ReactElement<ScreenProps, typeof Screen>[];
67

78
interface FullScreenStackProperties {
89
canalId: string;
@@ -14,10 +15,9 @@ interface FullScreenStackMap {
1415
}
1516

1617
export class FullScreenDelegate {
17-
canalsFullScreenStackProperties$ = new Subject<Observable<FullScreenStackProperties>>();
18+
canalsFullScreenStackProperties$ = new Subject<FullScreenStackProperties>();
1819

1920
fullSceenStack$: Observable<Stack> = this.canalsFullScreenStackProperties$.pipe(
20-
mergeAll(),
2121
scan(
2222
(
2323
fullScreenStackMap: FullScreenStackMap,

src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export { createCanal } from './createCanal';
21
export { FullScreenPortal } from './FullScreenPortal';
32
export { Screen } from './Screen';
43
export { Canal } from './Canal';

yarn.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,6 +1680,13 @@
16801680
"@types/prop-types" "*"
16811681
csstype "^2.2.0"
16821682

1683+
"@types/recompose@^0.30.6":
1684+
version "0.30.6"
1685+
resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.6.tgz#f6ffae2008b84df916ed6633751f9287f344ea3e"
1686+
integrity sha512-A9c880h07JMrvVe+PwyjVihrQRyKWp4/GFjfA9YE4NgxdEuQD74gSdDhInhUNctO/dkCcR66rexEXevzBy85cQ==
1687+
dependencies:
1688+
"@types/react" "*"
1689+
16831690
"@types/stack-utils@^1.0.1":
16841691
version "1.0.1"
16851692
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"

0 commit comments

Comments
 (0)