mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-01-15 09:42:27 +08:00
Compare commits
21 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f553c2ad1 | ||
|
|
10ad9154a2 | ||
|
|
fb1e8d4a07 | ||
|
|
5c7f892d77 | ||
|
|
10c6c3280f | ||
|
|
e5856dae79 | ||
|
|
db24639445 | ||
|
|
f10543f9fc | ||
|
|
a3e3fa2cfd | ||
|
|
ec25edd658 | ||
|
|
09d4bc24e9 | ||
|
|
8d0e0f48ad | ||
|
|
8411e6f764 | ||
|
|
dff6c3ee7c | ||
|
|
ffe3bddcb2 | ||
|
|
9b55493e76 | ||
|
|
ebe70f51fb | ||
|
|
256e5aec2a | ||
|
|
707bea3cba | ||
|
|
6bdc1e9e5f | ||
|
|
b3db099a00 |
@@ -8,7 +8,7 @@
|
|||||||
"ios": "expo start --ios"
|
"ios": "expo start --ios"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.11.0",
|
"@babel/runtime": "^7.12.1",
|
||||||
"@expo/vector-icons": "^10.0.0",
|
"@expo/vector-icons": "^10.0.0",
|
||||||
"@react-native-community/masked-view": "0.1.10",
|
"@react-native-community/masked-view": "0.1.10",
|
||||||
"expo": "^39.0.0",
|
"expo": "^39.0.0",
|
||||||
@@ -20,17 +20,17 @@
|
|||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.2",
|
"react-native": "~0.63.2",
|
||||||
"react-native-gesture-handler": "~1.7.0",
|
"react-native-gesture-handler": "~1.7.0",
|
||||||
"react-native-iphone-x-helper": "^1.2.1",
|
"react-native-iphone-x-helper": "^1.3.0",
|
||||||
"react-native-maps": "0.27.1",
|
"react-native-maps": "0.27.1",
|
||||||
"react-native-paper": "^4.0.1",
|
"react-native-paper": "^4.0.1",
|
||||||
"react-native-reanimated": "~1.13.0",
|
"react-native-reanimated": "~1.13.0",
|
||||||
"react-native-safe-area-context": "3.1.4",
|
"react-native-safe-area-context": "3.1.4",
|
||||||
"react-native-screens": "~2.10.1",
|
"react-native-screens": "~2.10.1",
|
||||||
"react-native-webview": "10.7.0",
|
"react-native-webview": "10.7.0",
|
||||||
"react-navigation-header-buttons": "^3.0.5"
|
"react-navigation-header-buttons": "^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-plugin-module-resolver": "^4.0.0",
|
"babel-plugin-module-resolver": "^4.0.0",
|
||||||
"expo-cli": "^3.27.8"
|
"expo-cli": "^3.28.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
package.json
20
package.json
@@ -25,21 +25,21 @@
|
|||||||
"example": "yarn --cwd example"
|
"example": "yarn --cwd example"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
|
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
|
||||||
"@babel/preset-env": "^7.11.0",
|
"@babel/preset-env": "^7.12.1",
|
||||||
"@babel/preset-react": "^7.10.4",
|
"@babel/preset-react": "^7.12.1",
|
||||||
"@babel/preset-typescript": "^7.10.4",
|
"@babel/preset-typescript": "^7.12.1",
|
||||||
"@babel/runtime": "^7.11.0",
|
"@babel/runtime": "^7.12.1",
|
||||||
"@commitlint/config-conventional": "^11.0.0",
|
"@commitlint/config-conventional": "^11.0.0",
|
||||||
"@types/jest": "^26.0.8",
|
"@types/jest": "^26.0.15",
|
||||||
"babel-jest": "^26.2.2",
|
"babel-jest": "^26.6.1",
|
||||||
"commitlint": "^11.0.0",
|
"commitlint": "^11.0.0",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"eslint": "^7.6.0",
|
"eslint": "^7.12.0",
|
||||||
"eslint-config-satya164": "^3.1.8",
|
"eslint-config-satya164": "^3.1.8",
|
||||||
"husky": "^4.2.5",
|
"husky": "^4.2.5",
|
||||||
"jest": "^26.2.2",
|
"jest": "^26.6.1",
|
||||||
"lerna": "^3.22.1",
|
"lerna": "^3.22.1",
|
||||||
"prettier": "^2.1.2",
|
"prettier": "^2.1.2",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [0.6.4](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.6.3...react-navigation-animated-switch@0.6.4) (2021-02-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-animated-switch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [0.6.3](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.6.2...react-navigation-animated-switch@0.6.3) (2020-10-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-animated-switch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [0.6.2](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.6.1...react-navigation-animated-switch@0.6.2) (2020-10-02)
|
## [0.6.2](https://github.com/react-navigation/react-navigation/compare/react-navigation-animated-switch@0.6.1...react-navigation-animated-switch@0.6.2) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package react-navigation-animated-switch
|
**Note:** Version bump only for package react-navigation-animated-switch
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation-animated-switch",
|
"name": "react-navigation-animated-switch",
|
||||||
"version": "0.6.2",
|
"version": "0.6.4",
|
||||||
"description": "Animated switch for React Navigation",
|
"description": "Animated switch for React Navigation",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "lib/module/index.js",
|
"react-native": "lib/module/index.js",
|
||||||
@@ -22,13 +22,13 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "0.16.2",
|
"@react-native-community/bob": "0.16.2",
|
||||||
"@types/react": "16.9.49",
|
"@types/react": "16.9.53",
|
||||||
"@types/react-native": "0.63.20",
|
"@types/react-native": "0.63.30",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.2",
|
"react-native": "~0.63.2",
|
||||||
"react-native-reanimated": "~1.13.0",
|
"react-native-reanimated": "~1.13.0",
|
||||||
"react-navigation": "^4.4.2",
|
"react-navigation": "^4.4.4",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -3,6 +3,14 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [3.7.9](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.8...@react-navigation/core@3.7.9) (2020-10-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/core
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [3.7.8](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.7...@react-navigation/core@3.7.8) (2020-10-02)
|
## [3.7.8](https://github.com/react-navigation/react-navigation-core/compare/@react-navigation/core@3.7.7...@react-navigation/core@3.7.8) (2020-10-02)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/core",
|
"name": "@react-navigation/core",
|
||||||
"version": "3.7.8",
|
"version": "3.7.9",
|
||||||
"description": "Core utilities for the react-navigation framework",
|
"description": "Core utilities for the react-navigation framework",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "lib/module/index.js",
|
"react-native": "lib/module/index.js",
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
"path-to-regexp": "^1.8.0",
|
"path-to-regexp": "^1.8.0",
|
||||||
"query-string": "^6.13.1",
|
"query-string": "^6.13.6",
|
||||||
"react-is": "^16.13.0"
|
"react-is": "^16.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import getChildrenNavigationCache from '../getChildrenNavigationCache';
|
||||||
|
|
||||||
|
it('should return empty table if navigation arg not provided', () => {
|
||||||
|
expect(getChildrenNavigationCache()._childrenNavigation).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should populate navigation._childrenNavigation as a side-effect', () => {
|
||||||
|
const navigation = {
|
||||||
|
state: {
|
||||||
|
routes: [{ key: 'one' }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const result = getChildrenNavigationCache(navigation);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(navigation._childrenNavigation).toBe(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete children cache keys that are no longer valid', () => {
|
||||||
|
const navigation = {
|
||||||
|
state: {
|
||||||
|
routes: [{ key: 'one' }, { key: 'two' }, { key: 'three' }],
|
||||||
|
},
|
||||||
|
_childrenNavigation: {
|
||||||
|
one: {},
|
||||||
|
two: {},
|
||||||
|
three: {},
|
||||||
|
four: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getChildrenNavigationCache(navigation);
|
||||||
|
expect(result).toEqual({
|
||||||
|
one: {},
|
||||||
|
two: {},
|
||||||
|
three: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not delete children cache keys if in transitioning state', () => {
|
||||||
|
const navigation = {
|
||||||
|
state: {
|
||||||
|
routes: [{ key: 'one' }, { key: 'two' }, { key: 'three' }],
|
||||||
|
isTransitioning: true,
|
||||||
|
},
|
||||||
|
_childrenNavigation: {
|
||||||
|
one: {},
|
||||||
|
two: {},
|
||||||
|
three: {},
|
||||||
|
four: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = getChildrenNavigationCache(navigation);
|
||||||
|
expect(result).toEqual({
|
||||||
|
one: {},
|
||||||
|
two: {},
|
||||||
|
three: {},
|
||||||
|
four: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
48
packages/core/src/__tests__/getEventManager.test.js
Normal file
48
packages/core/src/__tests__/getEventManager.test.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import getEventManager from '../getEventManager';
|
||||||
|
|
||||||
|
const TARGET = 'target';
|
||||||
|
|
||||||
|
it('calls listeners to emitted event', () => {
|
||||||
|
const eventManager = getEventManager(TARGET);
|
||||||
|
const callback = jest.fn();
|
||||||
|
eventManager.addListener('didFocus', callback);
|
||||||
|
|
||||||
|
eventManager.emit('didFocus');
|
||||||
|
|
||||||
|
expect(callback).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not call listeners connected to a different event', () => {
|
||||||
|
const eventManager = getEventManager(TARGET);
|
||||||
|
const callback = jest.fn();
|
||||||
|
eventManager.addListener('didFocus', callback);
|
||||||
|
|
||||||
|
eventManager.emit('didBlur');
|
||||||
|
|
||||||
|
expect(callback).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not call removed listeners', () => {
|
||||||
|
const eventManager = getEventManager(TARGET);
|
||||||
|
const callback = jest.fn();
|
||||||
|
const { remove } = eventManager.addListener('didFocus', callback);
|
||||||
|
|
||||||
|
eventManager.emit('didFocus');
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
|
||||||
|
remove();
|
||||||
|
|
||||||
|
eventManager.emit('didFocus');
|
||||||
|
expect(callback).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls the listeners with the given payload', () => {
|
||||||
|
const eventManager = getEventManager(TARGET);
|
||||||
|
const callback = jest.fn();
|
||||||
|
eventManager.addListener('didFocus', callback);
|
||||||
|
|
||||||
|
const payload = { foo: 0 };
|
||||||
|
eventManager.emit('didFocus', payload);
|
||||||
|
|
||||||
|
expect(callback).toHaveBeenCalledWith(payload);
|
||||||
|
});
|
||||||
307
packages/core/src/views/__tests__/NavigationFocusEvents.test.js
Normal file
307
packages/core/src/views/__tests__/NavigationFocusEvents.test.js
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
import NavigationFocusEvents from '../NavigationFocusEvents';
|
||||||
|
import getEventManager from '../../getEventManager';
|
||||||
|
import { NavigationActions, StackActions } from '@react-navigation/core';
|
||||||
|
|
||||||
|
const getNavigationMock = (mock = {}) => {
|
||||||
|
const { addListener, emit } = getEventManager('target');
|
||||||
|
|
||||||
|
return {
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{ key: 'a', routeName: 'foo' },
|
||||||
|
{ key: 'b', routeName: 'bar' },
|
||||||
|
],
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
isFocused: () => true,
|
||||||
|
addListener: jest.fn(addListener),
|
||||||
|
emit: emit,
|
||||||
|
dangerouslyGetParent: () => null,
|
||||||
|
...mock,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
it('emits refocus event with current route key on refocus', () => {
|
||||||
|
const navigation = getNavigationMock();
|
||||||
|
const onEvent = jest.fn();
|
||||||
|
|
||||||
|
renderer.create(
|
||||||
|
<NavigationFocusEvents navigation={navigation} onEvent={onEvent} />
|
||||||
|
);
|
||||||
|
|
||||||
|
navigation.emit('refocus');
|
||||||
|
|
||||||
|
expect(onEvent).toHaveBeenCalledTimes(1);
|
||||||
|
const key = navigation.state.routes[navigation.state.index].key;
|
||||||
|
expect(onEvent).toHaveBeenCalledWith(key, 'refocus');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('on navigation action emitted', () => {
|
||||||
|
it('does not emit if navigation is not focused', () => {
|
||||||
|
const navigation = getNavigationMock({
|
||||||
|
isFocused: () => false,
|
||||||
|
});
|
||||||
|
const onEvent = jest.fn();
|
||||||
|
|
||||||
|
renderer.create(
|
||||||
|
<NavigationFocusEvents navigation={navigation} onEvent={onEvent} />
|
||||||
|
);
|
||||||
|
|
||||||
|
navigation.emit('action', {
|
||||||
|
state: navigation.state,
|
||||||
|
action: NavigationActions.init(),
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(onEvent).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('emits only willFocus and willBlur if state is transitioning', () => {
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 1,
|
||||||
|
routeKeyHistory: ['First', 'Second'],
|
||||||
|
isTransitioning: true,
|
||||||
|
};
|
||||||
|
const action = NavigationActions.init();
|
||||||
|
|
||||||
|
const navigation = getNavigationMock({
|
||||||
|
state: state,
|
||||||
|
});
|
||||||
|
const onEvent = jest.fn();
|
||||||
|
|
||||||
|
renderer.create(
|
||||||
|
<NavigationFocusEvents navigation={navigation} onEvent={onEvent} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastState = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 0,
|
||||||
|
routeKeyHistory: ['First'],
|
||||||
|
};
|
||||||
|
navigation.emit('action', {
|
||||||
|
state,
|
||||||
|
lastState,
|
||||||
|
action,
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedPayload = {
|
||||||
|
action,
|
||||||
|
state: { key: 'Second', routeName: 'Second' },
|
||||||
|
lastState: { key: 'First', routeName: 'First' },
|
||||||
|
context: 'Second:Navigation/INIT_Root',
|
||||||
|
type: 'action',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(onEvent.mock.calls).toEqual([
|
||||||
|
['Second', 'willFocus', expectedPayload],
|
||||||
|
['First', 'willBlur', expectedPayload],
|
||||||
|
['Second', 'action', expectedPayload],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('emits didFocus after willFocus and didBlur after willBlur if no transitions', () => {
|
||||||
|
const state = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 1,
|
||||||
|
routeKeyHistory: ['First', 'Second'],
|
||||||
|
};
|
||||||
|
const action = NavigationActions.navigate({
|
||||||
|
routeName: 'Second',
|
||||||
|
});
|
||||||
|
|
||||||
|
const navigation = getNavigationMock({
|
||||||
|
state: state,
|
||||||
|
});
|
||||||
|
const onEvent = jest.fn();
|
||||||
|
|
||||||
|
renderer.create(
|
||||||
|
<NavigationFocusEvents navigation={navigation} onEvent={onEvent} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastState = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 0,
|
||||||
|
routeKeyHistory: ['First'],
|
||||||
|
};
|
||||||
|
navigation.emit('action', {
|
||||||
|
state,
|
||||||
|
lastState,
|
||||||
|
action,
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedPayload = {
|
||||||
|
action,
|
||||||
|
state: { key: 'Second', routeName: 'Second' },
|
||||||
|
lastState: { key: 'First', routeName: 'First' },
|
||||||
|
context: 'Second:Navigation/NAVIGATE_Root',
|
||||||
|
type: 'action',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(onEvent.mock.calls).toEqual([
|
||||||
|
['Second', 'willFocus', expectedPayload],
|
||||||
|
['Second', 'didFocus', expectedPayload],
|
||||||
|
['First', 'willBlur', expectedPayload],
|
||||||
|
['First', 'didBlur', expectedPayload],
|
||||||
|
['Second', 'action', expectedPayload],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('emits didBlur and didFocus when transition ends', () => {
|
||||||
|
const initialState = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 0,
|
||||||
|
routeKeyHistory: ['First'],
|
||||||
|
isTransitioning: true,
|
||||||
|
};
|
||||||
|
const intermediateState = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 1,
|
||||||
|
routeKeyHistory: ['First', 'Second'],
|
||||||
|
isTransitioning: true,
|
||||||
|
};
|
||||||
|
const finalState = {
|
||||||
|
routes: [
|
||||||
|
{ key: 'First', routeName: 'First' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 1,
|
||||||
|
routeKeyHistory: ['First', 'Second'],
|
||||||
|
isTransitioning: false,
|
||||||
|
};
|
||||||
|
const actionNavigate = NavigationActions.navigate({ routeName: 'Second' });
|
||||||
|
const actionEndTransition = StackActions.completeTransition({
|
||||||
|
key: 'Second',
|
||||||
|
});
|
||||||
|
|
||||||
|
const navigation = getNavigationMock({
|
||||||
|
state: intermediateState,
|
||||||
|
});
|
||||||
|
const onEvent = jest.fn();
|
||||||
|
|
||||||
|
renderer.create(
|
||||||
|
<NavigationFocusEvents navigation={navigation} onEvent={onEvent} />
|
||||||
|
);
|
||||||
|
|
||||||
|
navigation.emit('action', {
|
||||||
|
state: intermediateState,
|
||||||
|
lastState: initialState,
|
||||||
|
action: actionNavigate,
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedPayloadNavigate = {
|
||||||
|
action: actionNavigate,
|
||||||
|
state: { key: 'Second', routeName: 'Second' },
|
||||||
|
lastState: { key: 'First', routeName: 'First' },
|
||||||
|
context: 'Second:Navigation/NAVIGATE_Root',
|
||||||
|
type: 'action',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(onEvent.mock.calls).toEqual([
|
||||||
|
['Second', 'willFocus', expectedPayloadNavigate],
|
||||||
|
['First', 'willBlur', expectedPayloadNavigate],
|
||||||
|
['Second', 'action', expectedPayloadNavigate],
|
||||||
|
]);
|
||||||
|
onEvent.mockClear();
|
||||||
|
|
||||||
|
navigation.emit('action', {
|
||||||
|
state: finalState,
|
||||||
|
lastState: intermediateState,
|
||||||
|
action: actionEndTransition,
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedPayloadEndTransition = {
|
||||||
|
action: actionEndTransition,
|
||||||
|
state: { key: 'Second', routeName: 'Second' },
|
||||||
|
lastState: { key: 'Second', routeName: 'Second' },
|
||||||
|
context: 'Second:Navigation/COMPLETE_TRANSITION_Root',
|
||||||
|
type: 'action',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(onEvent.mock.calls).toEqual([
|
||||||
|
['First', 'didBlur', expectedPayloadEndTransition],
|
||||||
|
['Second', 'didFocus', expectedPayloadEndTransition],
|
||||||
|
['Second', 'action', expectedPayloadEndTransition],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('on willFocus emitted', () => {
|
||||||
|
it('emits didFocus after willFocus if no transition', () => {
|
||||||
|
const navigation = getNavigationMock({
|
||||||
|
state: {
|
||||||
|
routes: [
|
||||||
|
{ key: 'FirstLanding', routeName: 'FirstLanding' },
|
||||||
|
{ key: 'Second', routeName: 'Second' },
|
||||||
|
],
|
||||||
|
index: 0,
|
||||||
|
key: 'First',
|
||||||
|
routeName: 'First',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const onEvent = jest.fn();
|
||||||
|
|
||||||
|
renderer.create(
|
||||||
|
<NavigationFocusEvents navigation={navigation} onEvent={onEvent} />
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastState = { key: 'Third', routeName: 'Third' };
|
||||||
|
const action = NavigationActions.navigate({ routeName: 'First' });
|
||||||
|
|
||||||
|
navigation.emit('willFocus', {
|
||||||
|
lastState,
|
||||||
|
action,
|
||||||
|
context: 'First:Navigation/NAVIGATE_Root',
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
const expectedPayload = {
|
||||||
|
action,
|
||||||
|
state: { key: 'FirstLanding', routeName: 'FirstLanding' },
|
||||||
|
context:
|
||||||
|
'FirstLanding:Navigation/NAVIGATE_First:Navigation/NAVIGATE_Root',
|
||||||
|
type: 'action',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(onEvent.mock.calls).toEqual([
|
||||||
|
['FirstLanding', 'willFocus', expectedPayload],
|
||||||
|
['FirstLanding', 'didFocus', expectedPayload],
|
||||||
|
]);
|
||||||
|
|
||||||
|
onEvent.mockClear();
|
||||||
|
|
||||||
|
// the nested navigator might emit a didFocus that should be ignored
|
||||||
|
navigation.emit('didFocus', {
|
||||||
|
lastState,
|
||||||
|
action,
|
||||||
|
context: 'First:Navigation/NAVIGATE_Root',
|
||||||
|
type: 'action',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(onEvent).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -3,6 +3,28 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [2.7.0](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.6.0...react-navigation-drawer@2.7.0) (2021-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add activityState to other navigators ([5c7f892](https://github.com/react-navigation/drawer/commit/5c7f892d77298f5c89534fa78a1a6a59c7f35a60))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.6.0](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.5.2...react-navigation-drawer@2.6.0) (2020-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add detachInactiveScreens prop for bottom tabs and drawer ([#8816](https://github.com/react-navigation/drawer/issues/8816)) ([707bea3](https://github.com/react-navigation/drawer/commit/707bea3cba1aa1f7b1eb5884dd1d129dcc2bbdc2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.5.2](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.5.1...react-navigation-drawer@2.5.2) (2020-10-02)
|
## [2.5.2](https://github.com/react-navigation/drawer/compare/react-navigation-drawer@2.5.1...react-navigation-drawer@2.5.2) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package react-navigation-drawer
|
**Note:** Version bump only for package react-navigation-drawer
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation-drawer",
|
"name": "react-navigation-drawer",
|
||||||
"version": "2.5.2",
|
"version": "2.7.0",
|
||||||
"description": "Drawer navigator component for React Navigation",
|
"description": "Drawer navigator component for React Navigation",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "lib/module/index.js",
|
"react-native": "lib/module/index.js",
|
||||||
@@ -39,8 +39,8 @@
|
|||||||
"homepage": "https://github.com/react-navigation/drawer#readme",
|
"homepage": "https://github.com/react-navigation/drawer#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@types/react": "^16.9.44",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.4",
|
"@types/react-native": "^0.63.30",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-lifecycles-compat": "^3.0.4",
|
"react-lifecycles-compat": "^3.0.4",
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"react-native-reanimated": "~1.13.0",
|
"react-native-reanimated": "~1.13.0",
|
||||||
"react-native-screens": "~2.10.1",
|
"react-native-screens": "~2.10.1",
|
||||||
"react-native-testing-library": "^6.0.0",
|
"react-native-testing-library": "^6.0.0",
|
||||||
"react-navigation": "^4.4.2",
|
"react-navigation": "^4.4.4",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export type NavigationDrawerConfig = {
|
|||||||
drawerBackgroundColor?: ThemedColor;
|
drawerBackgroundColor?: ThemedColor;
|
||||||
overlayColor?: ThemedColor;
|
overlayColor?: ThemedColor;
|
||||||
screenContainerStyle?: StyleProp<ViewStyle>;
|
screenContainerStyle?: StyleProp<ViewStyle>;
|
||||||
|
detachInactiveScreens?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NavigationDrawerRouterConfig = {
|
export type NavigationDrawerRouterConfig = {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ type Props = {
|
|||||||
contentOptions?: object;
|
contentOptions?: object;
|
||||||
};
|
};
|
||||||
screenProps: unknown;
|
screenProps: unknown;
|
||||||
|
detachInactiveScreens: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -166,7 +167,7 @@ export default class DrawerView extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private renderContent = () => {
|
private renderContent = () => {
|
||||||
let { lazy, navigation } = this.props;
|
let { lazy, navigation, detachInactiveScreens = true } = this.props;
|
||||||
let { loaded } = this.state;
|
let { loaded } = this.state;
|
||||||
let { routes } = navigation.state;
|
let { routes } = navigation.state;
|
||||||
|
|
||||||
@@ -183,7 +184,8 @@ export default class DrawerView extends React.PureComponent<Props, State> {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer style={styles.content}>
|
// @ts-ignore
|
||||||
|
<ScreenContainer enabled={detachInactiveScreens} style={styles.content}>
|
||||||
{routes.map((route, index) => {
|
{routes.map((route, index) => {
|
||||||
if (lazy && !loaded.includes(index)) {
|
if (lazy && !loaded.includes(index)) {
|
||||||
// Don't render a screen if we've never navigated to it
|
// Don't render a screen if we've never navigated to it
|
||||||
@@ -201,6 +203,7 @@ export default class DrawerView extends React.PureComponent<Props, State> {
|
|||||||
{ opacity: isFocused ? 1 : 0 },
|
{ opacity: isFocused ? 1 : 0 },
|
||||||
]}
|
]}
|
||||||
isVisible={isFocused}
|
isVisible={isFocused}
|
||||||
|
enabled={detachInactiveScreens}
|
||||||
>
|
>
|
||||||
<SceneView
|
<SceneView
|
||||||
navigation={descriptor.navigation}
|
navigation={descriptor.navigation}
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Platform, StyleSheet, View } from 'react-native';
|
import { Platform, StyleSheet, View } from 'react-native';
|
||||||
import { Screen, screensEnabled } from 'react-native-screens';
|
import {
|
||||||
|
Screen,
|
||||||
|
screensEnabled,
|
||||||
|
// @ts-ignore
|
||||||
|
shouldUseActivityState,
|
||||||
|
} from 'react-native-screens';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
style?: any;
|
style?: any;
|
||||||
|
enabled: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
|
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
|
||||||
@@ -13,11 +19,20 @@ const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view
|
|||||||
export default class ResourceSavingScene extends React.Component<Props> {
|
export default class ResourceSavingScene extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
// react-native-screens is buggy on web
|
// react-native-screens is buggy on web
|
||||||
if (screensEnabled?.() && Platform.OS !== 'web') {
|
if (screensEnabled?.() && this.props.enabled && Platform.OS !== 'web') {
|
||||||
const { isVisible, ...rest } = this.props;
|
const { isVisible, ...rest } = this.props;
|
||||||
|
|
||||||
// @ts-ignore
|
if (shouldUseActivityState) {
|
||||||
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
return (
|
||||||
|
// @ts-expect-error: there was an `active` prop and no `activityState` in older version and stackPresentation was required
|
||||||
|
<Screen activityState={isVisible ? 2 : 0} {...rest} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
// @ts-expect-error: there was an `active` prop and no `activityState` in older version and stackPresentation was required
|
||||||
|
<Screen active={isVisible ? 1 : 0} {...rest} />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isVisible, children, style, ...rest } = this.props;
|
const { isVisible, children, style, ...rest } = this.props;
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.3.4](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.3.3...react-navigation-material-bottom-tabs@2.3.4) (2021-02-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.3.3](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.3.2...react-navigation-material-bottom-tabs@2.3.3) (2020-10-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.3.2](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.3.1...react-navigation-material-bottom-tabs@2.3.2) (2020-10-02)
|
## [2.3.2](https://github.com/react-navigation/react-navigation-material-bottom-tabs/compare/react-navigation-material-bottom-tabs@2.3.1...react-navigation-material-bottom-tabs@2.3.2) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package react-navigation-material-bottom-tabs
|
**Note:** Version bump only for package react-navigation-material-bottom-tabs
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation-material-bottom-tabs",
|
"name": "react-navigation-material-bottom-tabs",
|
||||||
"version": "2.3.2",
|
"version": "2.3.4",
|
||||||
"description": "Material Bottom Tab Navigation component for React Navigation",
|
"description": "Material Bottom Tab Navigation component for React Navigation",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
@@ -40,13 +40,13 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@types/hoist-non-react-statics": "^3.3.1",
|
"@types/hoist-non-react-statics": "^3.3.1",
|
||||||
"@types/react": "^16.9.44",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.4",
|
"@types/react-native": "^0.63.30",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.2",
|
"react-native": "~0.63.2",
|
||||||
"react-native-paper": "^4.2.0",
|
"react-native-paper": "^4.2.0",
|
||||||
"react-navigation": "^4.4.2",
|
"react-navigation": "^4.4.4",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -3,6 +3,25 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [3.8.4](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.8.3...@react-navigation/native@3.8.4) (2021-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* address breaking change in react-native for Linking ([fb1e8d4](https://github.com/react-navigation/react-navigation-native/commit/fb1e8d4a077cece663633408d279459df66033a4))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [3.8.3](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.8.2...@react-navigation/native@3.8.3) (2020-10-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [3.8.2](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.8.1...@react-navigation/native@3.8.2) (2020-10-02)
|
## [3.8.2](https://github.com/react-navigation/react-navigation-native/compare/@react-navigation/native@3.8.1...@react-navigation/native@3.8.2) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package @react-navigation/native
|
**Note:** Version bump only for package @react-navigation/native
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/native",
|
"name": "@react-navigation/native",
|
||||||
"version": "3.8.2",
|
"version": "3.8.4",
|
||||||
"description": "React Native support for React Navigation",
|
"description": "React Native support for React Navigation",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"react-native": "lib/module/index.js",
|
"react-native": "lib/module/index.js",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-navigation/core": "^3.7.8",
|
"@react-navigation/core": "^3.7.9",
|
||||||
"@types/react-test-renderer": "^16.9.3",
|
"@types/react-test-renderer": "^16.9.3",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ export default function createNavigationContainer(Component) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_statefulContainerCount++;
|
_statefulContainerCount++;
|
||||||
Linking.addEventListener('url', this._handleOpenURL);
|
this._linkingSub = Linking.addEventListener('url', this._handleOpenURL);
|
||||||
|
|
||||||
// Pull out anything that can impact state
|
// Pull out anything that can impact state
|
||||||
let parsedUrl = null;
|
let parsedUrl = null;
|
||||||
@@ -331,7 +331,14 @@ export default function createNavigationContainer(Component) {
|
|||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this._isMounted = false;
|
this._isMounted = false;
|
||||||
Linking.removeEventListener('url', this._handleOpenURL);
|
|
||||||
|
// https://github.com/facebook/react-native/commit/6d1aca806cee86ad76de771ed3a1cc62982ebcd7
|
||||||
|
if (this._linkingSub?.remove) {
|
||||||
|
this._linkingSub?.remove();
|
||||||
|
} else {
|
||||||
|
Linking.removeEventListener('url', this._handleOpenURL);
|
||||||
|
}
|
||||||
|
|
||||||
this.subs && this.subs.remove();
|
this.subs && this.subs.remove();
|
||||||
|
|
||||||
if (this._isStateful()) {
|
if (this._isStateful()) {
|
||||||
|
|||||||
@@ -3,6 +3,22 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [4.4.4](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.4.3...react-navigation@4.4.4) (2021-02-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [4.4.3](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.4.2...react-navigation@4.4.3) (2020-10-26)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [4.4.2](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.4.1...react-navigation@4.4.2) (2020-10-02)
|
## [4.4.2](https://github.com/react-navigation/react-navigation/compare/react-navigation@4.4.1...react-navigation@4.4.2) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package react-navigation
|
**Note:** Version bump only for package react-navigation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation",
|
"name": "react-navigation",
|
||||||
"version": "4.4.2",
|
"version": "4.4.4",
|
||||||
"description": "Routing and navigation for your React Native apps",
|
"description": "Routing and navigation for your React Native apps",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"types": "typescript/react-navigation.d.ts",
|
"types": "typescript/react-navigation.d.ts",
|
||||||
@@ -24,12 +24,12 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/core": "^3.7.8",
|
"@react-navigation/core": "^3.7.9",
|
||||||
"@react-navigation/native": "^3.8.2"
|
"@react-navigation/native": "^3.8.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^16.9.44",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.4",
|
"@types/react-native": "^0.63.30",
|
||||||
"@types/react-test-renderer": "^16.9.3",
|
"@types/react-test-renderer": "^16.9.3",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.2",
|
"react-native": "~0.63.2",
|
||||||
|
|||||||
@@ -3,6 +3,52 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.10.3](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.10.2...react-navigation-stack@2.10.3) (2021-02-21)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.10.2](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.10.1...react-navigation-stack@2.10.2) (2020-11-22)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.10.1](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.10.0...react-navigation-stack@2.10.1) (2020-11-04)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package react-navigation-stack
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.10.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.9.0...react-navigation-stack@2.10.0) (2020-10-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* enable react-native-screens in Stack by default on iOS ([8411e6f](https://github.com/react-navigation/react-navigation-stack/commit/8411e6f764b86341e747cb7ca1ff4a775b4a827a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.9.0](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.8.4...react-navigation-stack@2.9.0) (2020-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* sync latest stack ([6bdc1e9](https://github.com/react-navigation/react-navigation-stack/commit/6bdc1e9e5f6ca05e0494f6b9a1f7b9b60764628a))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.8.4](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.8.3...react-navigation-stack@2.8.4) (2020-10-02)
|
## [2.8.4](https://github.com/react-navigation/react-navigation-stack/compare/react-navigation-stack@2.8.3...react-navigation-stack@2.8.4) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package react-navigation-stack
|
**Note:** Version bump only for package react-navigation-stack
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ yarn example start
|
|||||||
|
|
||||||
The code in this repo uses the source from [`@react-navigation/stack`](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack) and patches it to make it usable in React Navigation 4. If you need to make changes, please send a pull request there.
|
The code in this repo uses the source from [`@react-navigation/stack`](https://github.com/react-navigation/navigation-ex/tree/master/packages/stack) and patches it to make it usable in React Navigation 4. If you need to make changes, please send a pull request there.
|
||||||
|
|
||||||
If the change is specifically related to React Navigation 4 integration, first run `yarn sync`, then change the files in `src/vendor` and then run `yarn patch` to update the patch file with the latest changes.
|
If the change is specifically related to React Navigation 4 integration, first run `yarn patch:apply`, then change the files in `src/vendor` to resolve any conflicts and then run `yarn patch:create` to update the patch file with the latest changes.
|
||||||
|
|
||||||
Make sure your code passes TypeScript and ESLint. Run the following to verify:
|
Make sure your code passes TypeScript and ESLint. Run the following to verify:
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation-stack",
|
"name": "react-navigation-stack",
|
||||||
"version": "2.8.4",
|
"version": "2.10.3",
|
||||||
"description": "Stack navigator component for React Navigation",
|
"description": "Stack navigator component for React Navigation",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "bob build",
|
"prepare": "bob build",
|
||||||
"clean": "del lib",
|
"clean": "del lib",
|
||||||
"sync": "bash scripts/sync-stack.sh",
|
"patch:apply": "bash scripts/sync-stack.sh",
|
||||||
"patch": "diff -Naur ../../node_modules/@react-navigation/stack/src src/vendor > scripts/stack.patch; printf ''"
|
"patch:create": "diff -Naur ../../node_modules/@react-navigation/stack/src src/vendor > scripts/stack.patch; printf ''"
|
||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
@@ -39,16 +39,16 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/react-navigation/react-navigation-stack#readme",
|
"homepage": "https://github.com/react-navigation/react-navigation-stack#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.3",
|
||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@react-native-community/masked-view": "0.1.10",
|
"@react-native-community/masked-view": "0.1.10",
|
||||||
"@react-navigation/stack": "^5.9.0",
|
"@react-navigation/stack": "^5.14.3",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/react": "^16.9.44",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.4",
|
"@types/react-native": "^0.63.30",
|
||||||
"@types/react-test-renderer": "^16.9.3",
|
"@types/react-test-renderer": "^16.9.3",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
"react-native-gesture-handler": "~1.7.0",
|
"react-native-gesture-handler": "~1.7.0",
|
||||||
"react-native-safe-area-context": "3.1.4",
|
"react-native-safe-area-context": "3.1.4",
|
||||||
"react-native-screens": "~2.10.1",
|
"react-native-screens": "~2.10.1",
|
||||||
"react-navigation": "^4.4.2",
|
"react-navigation": "^4.4.4",
|
||||||
"react-test-renderer": "~16.13.1",
|
"react-test-renderer": "~16.13.1",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/index.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/index.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/index.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/index.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/index.tsx 2020-06-24 23:16:17.000000000 +0200
|
+++ src/vendor/index.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -3,11 +3,6 @@
|
@@ -3,11 +3,6 @@
|
||||||
import * as TransitionSpecs from './TransitionConfigs/TransitionSpecs';
|
import * as TransitionSpecs from './TransitionConfigs/TransitionSpecs';
|
||||||
import * as TransitionPresets from './TransitionConfigs/TransitionPresets';
|
import * as TransitionPresets from './TransitionConfigs/TransitionPresets';
|
||||||
|
|
||||||
-/**
|
-/**
|
||||||
- * Navigators
|
- * Navigators
|
||||||
- */
|
- */
|
||||||
@@ -28,9 +28,9 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/index.tsx src/vendor/i
|
|||||||
StackHeaderLeftButtonProps,
|
StackHeaderLeftButtonProps,
|
||||||
StackHeaderTitleProps,
|
StackHeaderTitleProps,
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx src/vendor/navigators/createStackNavigator.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx src/vendor/navigators/createStackNavigator.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/navigators/createStackNavigator.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/navigators/createStackNavigator.tsx 1970-01-01 01:00:00.000000000 +0100
|
+++ src/vendor/navigators/createStackNavigator.tsx 1970-01-01 01:00:00.000000000 +0100
|
||||||
@@ -1,96 +0,0 @@
|
@@ -1,101 +0,0 @@
|
||||||
-import * as React from 'react';
|
-import * as React from 'react';
|
||||||
-import { Platform } from 'react-native';
|
-import { Platform } from 'react-native';
|
||||||
-import {
|
-import {
|
||||||
@@ -42,6 +42,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
|
|||||||
- StackRouterOptions,
|
- StackRouterOptions,
|
||||||
- StackNavigationState,
|
- StackNavigationState,
|
||||||
- StackActions,
|
- StackActions,
|
||||||
|
- ParamListBase,
|
||||||
|
- StackActionHelpers,
|
||||||
-} from '@react-navigation/native';
|
-} from '@react-navigation/native';
|
||||||
-import StackView from '../views/Stack/StackView';
|
-import StackView from '../views/Stack/StackView';
|
||||||
-import type {
|
-import type {
|
||||||
@@ -62,12 +64,16 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
|
|||||||
-}: Props) {
|
-}: Props) {
|
||||||
- const defaultOptions = {
|
- const defaultOptions = {
|
||||||
- gestureEnabled: Platform.OS === 'ios',
|
- gestureEnabled: Platform.OS === 'ios',
|
||||||
- animationEnabled: Platform.OS !== 'web',
|
- animationEnabled:
|
||||||
|
- Platform.OS !== 'web' &&
|
||||||
|
- Platform.OS !== 'windows' &&
|
||||||
|
- Platform.OS !== 'macos',
|
||||||
- };
|
- };
|
||||||
-
|
-
|
||||||
- const { state, descriptors, navigation } = useNavigationBuilder<
|
- const { state, descriptors, navigation } = useNavigationBuilder<
|
||||||
- StackNavigationState,
|
- StackNavigationState<ParamListBase>,
|
||||||
- StackRouterOptions,
|
- StackRouterOptions,
|
||||||
|
- StackActionHelpers<ParamListBase>,
|
||||||
- StackNavigationOptions,
|
- StackNavigationOptions,
|
||||||
- StackNavigationEventMap
|
- StackNavigationEventMap
|
||||||
- >(StackRouter, {
|
- >(StackRouter, {
|
||||||
@@ -87,8 +93,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
|
|||||||
-
|
-
|
||||||
- React.useEffect(
|
- React.useEffect(
|
||||||
- () =>
|
- () =>
|
||||||
- navigation.addListener &&
|
- navigation.addListener?.('tabPress', (e) => {
|
||||||
- navigation.addListener('tabPress', (e) => {
|
|
||||||
- const isFocused = navigation.isFocused();
|
- const isFocused = navigation.isFocused();
|
||||||
-
|
-
|
||||||
- // Run the operation in the next frame so we're sure all listeners have been run
|
- // Run the operation in the next frame so we're sure all listeners have been run
|
||||||
@@ -122,15 +127,15 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/navigators/createStack
|
|||||||
-}
|
-}
|
||||||
-
|
-
|
||||||
-export default createNavigatorFactory<
|
-export default createNavigatorFactory<
|
||||||
- StackNavigationState,
|
- StackNavigationState<ParamListBase>,
|
||||||
- StackNavigationOptions,
|
- StackNavigationOptions,
|
||||||
- StackNavigationEventMap,
|
- StackNavigationEventMap,
|
||||||
- typeof StackNavigator
|
- typeof StackNavigator
|
||||||
->(StackNavigator);
|
->(StackNavigator);
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/types.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/types.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/types.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/types.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/types.tsx 2020-06-24 23:18:40.000000000 +0200
|
+++ src/vendor/types.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -8,15 +8,28 @@
|
@@ -8,15 +8,29 @@
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
import type {
|
import type {
|
||||||
@@ -155,6 +160,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
|
|||||||
+} from 'react-navigation';
|
+} from 'react-navigation';
|
||||||
+
|
+
|
||||||
+// @ts-ignore
|
+// @ts-ignore
|
||||||
|
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
+export type Route<T extends string> = NavigationRoute;
|
+export type Route<T extends string> = NavigationRoute;
|
||||||
+
|
+
|
||||||
+export type NavigationStackState = NavigationState;
|
+export type NavigationStackState = NavigationState;
|
||||||
@@ -164,26 +170,27 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
|
|||||||
+ | 'didFocus'
|
+ | 'didFocus'
|
||||||
+ | 'willBlur'
|
+ | 'willBlur'
|
||||||
+ | 'didBlur';
|
+ | 'didBlur';
|
||||||
|
|
||||||
export type StackNavigationEventMap = {
|
export type StackNavigationEventMap = {
|
||||||
/**
|
/**
|
||||||
@@ -29,29 +42,28 @@
|
@@ -41,30 +55,29 @@
|
||||||
transitionEnd: { data: { closing: boolean } };
|
gestureCancel: { data: undefined };
|
||||||
};
|
};
|
||||||
|
|
||||||
-export type StackNavigationHelpers = NavigationHelpers<
|
-export type StackNavigationHelpers = NavigationHelpers<
|
||||||
- ParamListBase,
|
- ParamListBase,
|
||||||
- StackNavigationEventMap
|
- StackNavigationEventMap
|
||||||
->;
|
-> &
|
||||||
-
|
- StackActionHelpers<ParamListBase>;
|
||||||
+export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
|
+export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
|
||||||
|
|
||||||
export type StackNavigationProp<
|
export type StackNavigationProp<
|
||||||
- ParamList extends ParamListBase,
|
- ParamList extends ParamListBase,
|
||||||
- RouteName extends keyof ParamList = string
|
- RouteName extends keyof ParamList = string
|
||||||
-> = NavigationProp<
|
-> = NavigationProp<
|
||||||
- ParamList,
|
- ParamList,
|
||||||
- RouteName,
|
- RouteName,
|
||||||
- StackNavigationState,
|
- StackNavigationState<ParamList>,
|
||||||
- StackNavigationOptions,
|
- StackNavigationOptions,
|
||||||
- StackNavigationEventMap
|
- StackNavigationEventMap
|
||||||
-> &
|
-> &
|
||||||
@@ -216,9 +223,9 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
|
|||||||
+ callback: NavigationEventCallback
|
+ callback: NavigationEventCallback
|
||||||
+ ) => NavigationEventSubscription;
|
+ ) => NavigationEventSubscription;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Layout = { width: number; height: number };
|
export type Layout = { width: number; height: number };
|
||||||
@@ -228,24 +240,27 @@
|
@@ -245,24 +258,27 @@
|
||||||
/**
|
/**
|
||||||
* Navigation prop for the header.
|
* Navigation prop for the header.
|
||||||
*/
|
*/
|
||||||
@@ -229,22 +236,22 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
|
|||||||
*/
|
*/
|
||||||
styleInterpolator: StackHeaderStyleInterpolator;
|
styleInterpolator: StackHeaderStyleInterpolator;
|
||||||
};
|
};
|
||||||
|
|
||||||
-export type StackDescriptor = Descriptor<
|
-export type StackDescriptor = Descriptor<
|
||||||
- ParamListBase,
|
- ParamListBase,
|
||||||
- string,
|
- string,
|
||||||
- StackNavigationState,
|
- StackNavigationState<ParamListBase>,
|
||||||
- StackNavigationOptions
|
- StackNavigationOptions
|
||||||
+export type StackDescriptor = NavigationDescriptor<
|
+export type StackDescriptor = NavigationDescriptor<
|
||||||
+ NavigationParams,
|
+ NavigationParams,
|
||||||
+ StackNavigationOptions,
|
+ StackNavigationOptions,
|
||||||
+ StackNavigationProp
|
+ StackNavigationProp
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type StackDescriptorMap = {
|
export type StackDescriptorMap = {
|
||||||
[key: string]: StackDescriptor;
|
[key: string]: StackDescriptor;
|
||||||
};
|
};
|
||||||
|
|
||||||
+export type TransitionCallbackProps = {
|
+export type TransitionCallbackProps = {
|
||||||
+ closing: boolean;
|
+ closing: boolean;
|
||||||
+};
|
+};
|
||||||
@@ -252,29 +259,29 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/types.tsx src/vendor/t
|
|||||||
export type StackNavigationOptions = StackHeaderOptions &
|
export type StackNavigationOptions = StackHeaderOptions &
|
||||||
Partial<TransitionPreset> & {
|
Partial<TransitionPreset> & {
|
||||||
/**
|
/**
|
||||||
@@ -330,6 +345,8 @@
|
@@ -356,6 +372,8 @@
|
||||||
bottom?: number;
|
* Defaults to `false` for the last screen when mode='modal', otherwise `true`.
|
||||||
left?: number;
|
*/
|
||||||
};
|
detachPreviousScreen?: boolean;
|
||||||
+ onTransitionStart?: (props: TransitionCallbackProps) => void;
|
+ onTransitionStart?: (props: TransitionCallbackProps) => void;
|
||||||
+ onTransitionEnd?: (props: TransitionCallbackProps) => void;
|
+ onTransitionEnd?: (props: TransitionCallbackProps) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StackNavigationConfig = {
|
export type StackNavigationConfig = {
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/utils/PreviousSceneContext.tsx src/vendor/utils/PreviousSceneContext.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/utils/PreviousSceneContext.tsx src/vendor/utils/PreviousSceneContext.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/utils/PreviousSceneContext.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/utils/PreviousSceneContext.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/utils/PreviousSceneContext.tsx 2020-06-24 23:26:38.000000000 +0200
|
+++ src/vendor/utils/PreviousSceneContext.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -1,6 +1,5 @@
|
@@ -1,6 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
-import type { Route } from '@react-navigation/native';
|
-import type { Route } from '@react-navigation/native';
|
||||||
-import type { Scene } from '../types';
|
-import type { Scene } from '../types';
|
||||||
+import type { Route, Scene } from '../types';
|
+import type { Route, Scene } from '../types';
|
||||||
|
|
||||||
const PreviousSceneContext = React.createContext<
|
const PreviousSceneContext = React.createContext<
|
||||||
Scene<Route<string>> | undefined
|
Scene<Route<string>> | undefined
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx src/vendor/views/Header/Header.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx src/vendor/views/Header/Header.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Header/Header.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Header/Header.tsx 2020-06-25 03:01:13.000000000 +0200
|
+++ src/vendor/views/Header/Header.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -1,12 +1,15 @@
|
@@ -1,12 +1,15 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
-import { StackActions } from '@react-navigation/native';
|
-import { StackActions } from '@react-navigation/native';
|
||||||
@@ -283,12 +290,12 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
|
|||||||
+import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
+import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
||||||
+
|
+
|
||||||
+import HeaderSegment, { getDefaultHeaderHeight } from './HeaderSegment';
|
+import HeaderSegment, { getDefaultHeaderHeight } from './HeaderSegment';
|
||||||
|
|
||||||
-import HeaderSegment from './HeaderSegment';
|
-import HeaderSegment from './HeaderSegment';
|
||||||
import HeaderTitle from './HeaderTitle';
|
import HeaderTitle from './HeaderTitle';
|
||||||
import debounce from '../../utils/debounce';
|
import debounce from '../../utils/debounce';
|
||||||
import type { StackHeaderProps, StackHeaderTitleProps } from '../../types';
|
import type { StackHeaderProps, StackHeaderTitleProps } from '../../types';
|
||||||
|
|
||||||
-export default React.memo(function Header(props: StackHeaderProps) {
|
-export default React.memo(function Header(props: StackHeaderProps) {
|
||||||
+const Header = React.memo(function Header(props: StackHeaderProps) {
|
+const Header = React.memo(function Header(props: StackHeaderProps) {
|
||||||
const {
|
const {
|
||||||
@@ -300,9 +307,9 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
|
|||||||
? options.title
|
? options.title
|
||||||
- : scene.route.name;
|
- : scene.route.name;
|
||||||
+ : scene.route.routeName;
|
+ : scene.route.routeName;
|
||||||
|
|
||||||
let leftLabel;
|
let leftLabel;
|
||||||
|
|
||||||
@@ -38,17 +41,20 @@
|
@@ -38,17 +41,20 @@
|
||||||
? o.headerTitle
|
? o.headerTitle
|
||||||
: o.title !== undefined
|
: o.title !== undefined
|
||||||
@@ -310,7 +317,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
|
|||||||
- : previous.route.name;
|
- : previous.route.name;
|
||||||
+ : previous.route.routeName;
|
+ : previous.route.routeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
const goBack = React.useCallback(
|
const goBack = React.useCallback(
|
||||||
debounce(() => {
|
debounce(() => {
|
||||||
@@ -362,37 +369,37 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/Header.ts
|
|||||||
+
|
+
|
||||||
+export default Header;
|
+export default Header;
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx src/vendor/views/Header/HeaderBackButton.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx src/vendor/views/Header/HeaderBackButton.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackButton.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Header/HeaderBackButton.tsx 2020-06-24 23:21:49.000000000 +0200
|
+++ src/vendor/views/Header/HeaderBackButton.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -8,9 +8,9 @@
|
@@ -8,9 +8,9 @@
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
LayoutChangeEvent,
|
LayoutChangeEvent,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
-import { useTheme } from '@react-navigation/native';
|
-import { useTheme } from '@react-navigation/native';
|
||||||
import MaskedView from '../MaskedView';
|
import MaskedView from '../MaskedView';
|
||||||
import { TouchableItem } from '../TouchableItem';
|
import TouchableItem from '../TouchableItem';
|
||||||
+import useTheme from '../../../utils/useTheme';
|
+import useTheme from '../../../utils/useTheme';
|
||||||
import type { StackHeaderLeftButtonProps } from '../../types';
|
import type { StackHeaderLeftButtonProps } from '../../types';
|
||||||
|
|
||||||
type Props = StackHeaderLeftButtonProps;
|
type Props = StackHeaderLeftButtonProps;
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx src/vendor/views/Header/HeaderBackground.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx src/vendor/views/Header/HeaderBackground.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderBackground.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Header/HeaderBackground.tsx 2020-06-24 23:16:23.000000000 +0200
|
+++ src/vendor/views/Header/HeaderBackground.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -7,7 +7,7 @@
|
@@ -7,7 +7,7 @@
|
||||||
StyleProp,
|
StyleProp,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
-import { useTheme } from '@react-navigation/native';
|
-import { useTheme } from '@react-navigation/native';
|
||||||
+import useTheme from '../../../utils/useTheme';
|
+import useTheme from '../../../utils/useTheme';
|
||||||
|
|
||||||
type Props = ViewProps & {
|
type Props = ViewProps & {
|
||||||
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
|
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx src/vendor/views/Header/HeaderContainer.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx src/vendor/views/Header/HeaderContainer.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderContainer.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Header/HeaderContainer.tsx 2020-06-24 23:21:29.000000000 +0200
|
+++ src/vendor/views/Header/HeaderContainer.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -1,11 +1,6 @@
|
@@ -1,11 +1,6 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||||
-import {
|
-import {
|
||||||
- NavigationContext,
|
- NavigationContext,
|
||||||
- NavigationRouteContext,
|
- NavigationRouteContext,
|
||||||
@@ -401,9 +408,9 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
|
|||||||
-} from '@react-navigation/native';
|
-} from '@react-navigation/native';
|
||||||
+import { NavigationContext } from 'react-navigation';
|
+import { NavigationContext } from 'react-navigation';
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
@@ -19,6 +14,7 @@
|
@@ -18,6 +13,7 @@
|
||||||
import PreviousSceneContext from '../../utils/PreviousSceneContext';
|
import PreviousSceneContext from '../../utils/PreviousSceneContext';
|
||||||
import type {
|
import type {
|
||||||
Layout,
|
Layout,
|
||||||
@@ -411,7 +418,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
|
|||||||
Scene,
|
Scene,
|
||||||
StackHeaderStyleInterpolator,
|
StackHeaderStyleInterpolator,
|
||||||
StackNavigationProp,
|
StackNavigationProp,
|
||||||
@@ -109,9 +105,7 @@
|
@@ -99,9 +95,7 @@
|
||||||
insets,
|
insets,
|
||||||
scene,
|
scene,
|
||||||
previous,
|
previous,
|
||||||
@@ -422,7 +429,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
|
|||||||
styleInterpolator:
|
styleInterpolator:
|
||||||
mode === 'float'
|
mode === 'float'
|
||||||
? isHeaderStatic
|
? isHeaderStatic
|
||||||
@@ -130,7 +124,7 @@
|
@@ -120,7 +114,7 @@
|
||||||
key={scene.route.key}
|
key={scene.route.key}
|
||||||
value={scene.descriptor.navigation}
|
value={scene.descriptor.navigation}
|
||||||
>
|
>
|
||||||
@@ -431,7 +438,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
|
|||||||
<View
|
<View
|
||||||
onLayout={
|
onLayout={
|
||||||
onContentHeightChange
|
onContentHeightChange
|
||||||
@@ -156,7 +150,7 @@
|
@@ -149,7 +143,7 @@
|
||||||
>
|
>
|
||||||
{header !== undefined ? header(props) : <Header {...props} />}
|
{header !== undefined ? header(props) : <Header {...props} />}
|
||||||
</View>
|
</View>
|
||||||
@@ -441,8 +448,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderCon
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx src/vendor/views/Header/HeaderSegment.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx src/vendor/views/Header/HeaderSegment.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSegment.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Header/HeaderSegment.tsx 2020-06-24 23:20:58.000000000 +0200
|
+++ src/vendor/views/Header/HeaderSegment.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -8,7 +8,7 @@
|
@@ -8,7 +8,7 @@
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
@@ -451,8 +458,8 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSeg
|
|||||||
+import type { NavigationRoute } from 'react-navigation';
|
+import type { NavigationRoute } from 'react-navigation';
|
||||||
import HeaderBackButton from './HeaderBackButton';
|
import HeaderBackButton from './HeaderBackButton';
|
||||||
import HeaderBackground from './HeaderBackground';
|
import HeaderBackground from './HeaderBackground';
|
||||||
import memoize from '../../utils/memoize';
|
import HeaderShownContext from '../../utils/HeaderShownContext';
|
||||||
@@ -28,7 +28,7 @@
|
@@ -29,7 +29,7 @@
|
||||||
onGoBack?: () => void;
|
onGoBack?: () => void;
|
||||||
title?: string;
|
title?: string;
|
||||||
leftLabel?: string;
|
leftLabel?: string;
|
||||||
@@ -460,33 +467,34 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderSeg
|
|||||||
+ scene: Scene<NavigationRoute>;
|
+ scene: Scene<NavigationRoute>;
|
||||||
styleInterpolator: StackHeaderStyleInterpolator;
|
styleInterpolator: StackHeaderStyleInterpolator;
|
||||||
};
|
};
|
||||||
|
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx src/vendor/views/Header/HeaderTitle.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx src/vendor/views/Header/HeaderTitle.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Header/HeaderTitle.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Header/HeaderTitle.tsx 2020-06-24 23:16:23.000000000 +0200
|
+++ src/vendor/views/Header/HeaderTitle.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -1,6 +1,6 @@
|
@@ -7,7 +7,7 @@
|
||||||
import * as React from 'react';
|
StyleProp,
|
||||||
import { Animated, StyleSheet, Platform } from 'react-native';
|
TextStyle,
|
||||||
|
} from 'react-native';
|
||||||
-import { useTheme } from '@react-navigation/native';
|
-import { useTheme } from '@react-navigation/native';
|
||||||
+import useTheme from '../../../utils/useTheme';
|
+import useTheme from '../../../utils/useTheme';
|
||||||
|
|
||||||
type Props = Omit<React.ComponentProps<typeof Animated.Text>, 'key'> & {
|
type Props = Omit<TextProps, 'style'> & {
|
||||||
tintColor?: string;
|
tintColor?: string;
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx src/vendor/views/Stack/Card.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx src/vendor/views/Stack/Card.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Stack/Card.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Stack/Card.tsx 2020-06-24 23:16:23.000000000 +0200
|
+++ src/vendor/views/Stack/Card.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -146,7 +146,7 @@
|
@@ -162,7 +162,7 @@
|
||||||
|
|
||||||
private interactionHandle: number | undefined;
|
private interactionHandle: number | undefined;
|
||||||
|
|
||||||
- private pendingGestureCallback: number | undefined;
|
- private pendingGestureCallback: number | undefined;
|
||||||
+ private pendingGestureCallback: any;
|
+ private pendingGestureCallback: any;
|
||||||
|
|
||||||
private animate = ({
|
private lastToValue: number | undefined;
|
||||||
closing,
|
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx src/vendor/views/Stack/CardContainer.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx src/vendor/views/Stack/CardContainer.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardContainer.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Stack/CardContainer.tsx 2020-06-24 23:20:38.000000000 +0200
|
+++ src/vendor/views/Stack/CardContainer.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -1,12 +1,13 @@
|
@@ -1,12 +1,13 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||||
@@ -503,18 +511,22 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardContai
|
|||||||
Layout,
|
Layout,
|
||||||
StackHeaderMode,
|
StackHeaderMode,
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx src/vendor/views/Stack/CardStack.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx src/vendor/views/Stack/CardStack.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Stack/CardStack.tsx 2020-06-24 23:20:16.000000000 +0200
|
+++ src/vendor/views/Stack/CardStack.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -7,7 +7,7 @@
|
@@ -6,11 +6,7 @@
|
||||||
Platform,
|
Dimensions,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
-import type { Route, StackNavigationState } from '@react-navigation/native';
|
-import type {
|
||||||
|
- ParamListBase,
|
||||||
|
- Route,
|
||||||
|
- StackNavigationState,
|
||||||
|
-} from '@react-navigation/native';
|
||||||
+import type { NavigationState as StackNavigationState } from 'react-navigation';
|
+import type { NavigationState as StackNavigationState } from 'react-navigation';
|
||||||
|
|
||||||
import { MaybeScreenContainer, MaybeScreen } from '../Screens';
|
import {
|
||||||
import { getDefaultHeaderHeight } from '../Header/HeaderSegment';
|
MaybeScreenContainer,
|
||||||
@@ -25,6 +25,7 @@
|
@@ -31,6 +27,7 @@
|
||||||
Layout,
|
Layout,
|
||||||
StackHeaderMode,
|
StackHeaderMode,
|
||||||
StackCardMode,
|
StackCardMode,
|
||||||
@@ -522,10 +534,19 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/CardStack.
|
|||||||
Scene,
|
Scene,
|
||||||
StackDescriptorMap,
|
StackDescriptorMap,
|
||||||
StackNavigationOptions,
|
StackNavigationOptions,
|
||||||
|
@@ -44,7 +41,7 @@
|
||||||
|
type Props = {
|
||||||
|
mode: StackCardMode;
|
||||||
|
insets: EdgeInsets;
|
||||||
|
- state: StackNavigationState<ParamListBase>;
|
||||||
|
+ state: StackNavigationState;
|
||||||
|
descriptors: StackDescriptorMap;
|
||||||
|
routes: Route<string>[];
|
||||||
|
openingRouteKeys: string[];
|
||||||
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx src/vendor/views/Stack/StackView.tsx
|
diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx src/vendor/views/Stack/StackView.tsx
|
||||||
--- ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx 2020-06-25 01:58:50.000000000 +0200
|
--- ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.tsx 2020-11-10 21:02:55.000000000 +0100
|
||||||
+++ src/vendor/views/Stack/StackView.tsx 2020-06-24 23:19:46.000000000 +0200
|
+++ src/vendor/views/Stack/StackView.tsx 2020-11-10 21:04:07.000000000 +0100
|
||||||
@@ -2,11 +2,11 @@
|
@@ -2,12 +2,11 @@
|
||||||
import { View, Platform, StyleSheet } from 'react-native';
|
import { View, Platform, StyleSheet } from 'react-native';
|
||||||
import { SafeAreaConsumer, EdgeInsets } from 'react-native-safe-area-context';
|
import { SafeAreaConsumer, EdgeInsets } from 'react-native-safe-area-context';
|
||||||
import {
|
import {
|
||||||
@@ -533,15 +554,16 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
StackActions,
|
StackActions,
|
||||||
- StackNavigationState,
|
- StackNavigationState,
|
||||||
- Route,
|
- Route,
|
||||||
|
- ParamListBase,
|
||||||
-} from '@react-navigation/native';
|
-} from '@react-navigation/native';
|
||||||
+ NavigationState as StackNavigationState,
|
+ NavigationState as StackNavigationState,
|
||||||
+ NavigationActions,
|
+ NavigationActions,
|
||||||
+ SceneView,
|
+ SceneView,
|
||||||
+} from 'react-navigation';
|
+} from 'react-navigation';
|
||||||
|
|
||||||
import { GestureHandlerRootView } from '../GestureHandler';
|
import { GestureHandlerRootView } from '../GestureHandler';
|
||||||
import CardStack from './CardStack';
|
import CardStack from './CardStack';
|
||||||
@@ -16,6 +16,7 @@
|
@@ -17,6 +16,7 @@
|
||||||
} from '../Header/HeaderContainer';
|
} from '../Header/HeaderContainer';
|
||||||
import SafeAreaProviderCompat from '../SafeAreaProviderCompat';
|
import SafeAreaProviderCompat from '../SafeAreaProviderCompat';
|
||||||
import type {
|
import type {
|
||||||
@@ -549,29 +571,33 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
StackNavigationHelpers,
|
StackNavigationHelpers,
|
||||||
StackNavigationConfig,
|
StackNavigationConfig,
|
||||||
StackDescriptorMap,
|
StackDescriptorMap,
|
||||||
@@ -25,6 +26,7 @@
|
@@ -24,9 +24,10 @@
|
||||||
state: StackNavigationState;
|
import HeaderShownContext from '../../utils/HeaderShownContext';
|
||||||
|
|
||||||
|
type Props = StackNavigationConfig & {
|
||||||
|
- state: StackNavigationState<ParamListBase>;
|
||||||
|
+ state: StackNavigationState;
|
||||||
navigation: StackNavigationHelpers;
|
navigation: StackNavigationHelpers;
|
||||||
descriptors: StackDescriptorMap;
|
descriptors: StackDescriptorMap;
|
||||||
+ screenProps: unknown;
|
+ screenProps: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -293,7 +295,9 @@
|
@@ -295,7 +296,9 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
- return gestureEnabled !== false;
|
- return gestureEnabled !== false;
|
||||||
+ return gestureEnabled !== undefined
|
+ return gestureEnabled !== undefined
|
||||||
+ ? gestureEnabled
|
+ ? gestureEnabled
|
||||||
+ : Platform.OS !== 'android';
|
+ : Platform.OS !== 'android';
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -321,26 +325,49 @@
|
@@ -323,26 +326,49 @@
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
- return descriptor.render();
|
- return descriptor.render();
|
||||||
+ const { navigation, getComponent } = descriptor;
|
+ const { navigation, getComponent } = descriptor;
|
||||||
+ const SceneComponent = getComponent();
|
+ const SceneComponent = getComponent();
|
||||||
@@ -584,11 +610,11 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
+ />
|
+ />
|
||||||
+ );
|
+ );
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderHeader = (props: HeaderContainerProps) => {
|
private renderHeader = (props: HeaderContainerProps) => {
|
||||||
return <HeaderContainer {...props} />;
|
return <HeaderContainer {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
+ private handleTransitionComplete = () => {
|
+ private handleTransitionComplete = () => {
|
||||||
+ const { state, navigation } = this.props;
|
+ const { state, navigation } = this.props;
|
||||||
+
|
+
|
||||||
@@ -605,7 +631,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
private handleOpenRoute = ({ route }: { route: Route<string> }) => {
|
private handleOpenRoute = ({ route }: { route: Route<string> }) => {
|
||||||
const { state, navigation } = this.props;
|
const { state, navigation } = this.props;
|
||||||
const { closingRouteKeys, replacingRouteKeys } = this.state;
|
const { closingRouteKeys, replacingRouteKeys } = this.state;
|
||||||
|
|
||||||
+ this.handleTransitionComplete();
|
+ this.handleTransitionComplete();
|
||||||
+
|
+
|
||||||
if (
|
if (
|
||||||
@@ -621,7 +647,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
} else {
|
} else {
|
||||||
this.setState((state) => ({
|
this.setState((state) => ({
|
||||||
routes: state.replacingRouteKeys.length
|
routes: state.replacingRouteKeys.length
|
||||||
@@ -366,12 +393,11 @@
|
@@ -368,12 +394,11 @@
|
||||||
// If a route exists in state, trigger a pop
|
// If a route exists in state, trigger a pop
|
||||||
// This will happen in when the route was closed from the card component
|
// This will happen in when the route was closed from the card component
|
||||||
// e.g. When the close animation triggered from a gesture ends
|
// e.g. When the close animation triggered from a gesture ends
|
||||||
@@ -638,7 +664,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
// We need to clean up any state tracking the route and pop it immediately
|
// We need to clean up any state tracking the route and pop it immediately
|
||||||
this.setState((state) => ({
|
this.setState((state) => ({
|
||||||
routes: state.routes.filter((r) => r.key !== route.key),
|
routes: state.routes.filter((r) => r.key !== route.key),
|
||||||
@@ -388,26 +414,29 @@
|
@@ -390,47 +415,41 @@
|
||||||
private handleTransitionStart = (
|
private handleTransitionStart = (
|
||||||
{ route }: { route: Route<string> },
|
{ route }: { route: Route<string> },
|
||||||
closing: boolean
|
closing: boolean
|
||||||
@@ -655,7 +681,7 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
+
|
+
|
||||||
+ descriptor?.options.onTransitionStart?.({ closing });
|
+ descriptor?.options.onTransitionStart?.({ closing });
|
||||||
+ };
|
+ };
|
||||||
|
|
||||||
private handleTransitionEnd = (
|
private handleTransitionEnd = (
|
||||||
{ route }: { route: Route<string> },
|
{ route }: { route: Route<string> },
|
||||||
closing: boolean
|
closing: boolean
|
||||||
@@ -665,14 +691,46 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
- data: { closing },
|
- data: { closing },
|
||||||
- target: route.key,
|
- target: route.key,
|
||||||
- });
|
- });
|
||||||
|
-
|
||||||
|
- private handleGestureStart = ({ route }: { route: Route<string> }) => {
|
||||||
|
- this.props.navigation.emit({
|
||||||
|
- type: 'gestureStart',
|
||||||
|
- target: route.key,
|
||||||
|
- });
|
||||||
|
- };
|
||||||
|
-
|
||||||
|
- private handleGestureEnd = ({ route }: { route: Route<string> }) => {
|
||||||
|
- this.props.navigation.emit({
|
||||||
|
- type: 'gestureEnd',
|
||||||
|
- target: route.key,
|
||||||
|
- });
|
||||||
|
- };
|
||||||
|
-
|
||||||
|
- private handleGestureCancel = ({ route }: { route: Route<string> }) => {
|
||||||
|
- this.props.navigation.emit({
|
||||||
|
- type: 'gestureCancel',
|
||||||
|
- target: route.key,
|
||||||
|
- });
|
||||||
+ ) => {
|
+ ) => {
|
||||||
+ const { descriptors } = this.props;
|
+ const { descriptors } = this.props;
|
||||||
+ const descriptor =
|
+ const descriptor =
|
||||||
+ descriptors[route.key] || this.state.descriptors[route.key];
|
+ descriptors[route.key] || this.state.descriptors[route.key];
|
||||||
+
|
+
|
||||||
+ descriptor?.options.onTransitionEnd?.({ closing });
|
+ descriptor?.options.onTransitionStart?.({ closing });
|
||||||
+ };
|
+ };
|
||||||
|
+
|
||||||
|
+ private handleGestureStart = () => {
|
||||||
|
+ // Do nothing
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ private handleGestureEnd = () => {
|
||||||
|
+ // Do nothing
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ private handleGestureCancel = () => {
|
||||||
|
+ // Do nothing
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
state,
|
state,
|
||||||
@@ -680,16 +738,16 @@ diff -Naur ../../node_modules/@react-navigation/stack/src/views/Stack/StackView.
|
|||||||
navigation,
|
navigation,
|
||||||
keyboardHandlingEnabled,
|
keyboardHandlingEnabled,
|
||||||
mode = 'card',
|
mode = 'card',
|
||||||
@@ -427,7 +456,7 @@
|
@@ -450,7 +469,7 @@
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
- <NavigationHelpersContext.Provider value={navigation}>
|
- <NavigationHelpersContext.Provider value={navigation}>
|
||||||
+ <>
|
+ <>
|
||||||
<GestureHandlerWrapper style={styles.container}>
|
<GestureHandlerWrapper style={styles.container}>
|
||||||
<SafeAreaProviderCompat>
|
<SafeAreaProviderCompat>
|
||||||
<SafeAreaConsumer>
|
<SafeAreaConsumer>
|
||||||
@@ -460,7 +489,7 @@
|
@@ -491,7 +510,7 @@
|
||||||
</SafeAreaConsumer>
|
</SafeAreaConsumer>
|
||||||
</SafeAreaProviderCompat>
|
</SafeAreaProviderCompat>
|
||||||
</GestureHandlerWrapper>
|
</GestureHandlerWrapper>
|
||||||
|
|||||||
@@ -11,12 +11,9 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
<View
|
<View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Array [
|
Object {
|
||||||
Object {
|
"zIndex": 1,
|
||||||
"zIndex": 1,
|
}
|
||||||
},
|
|
||||||
false,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
@@ -155,16 +152,21 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
onGestureCanceled={[Function]}
|
onGestureCanceled={[Function]}
|
||||||
onGestureEnd={[Function]}
|
onGestureEnd={[Function]}
|
||||||
onOpen={[Function]}
|
onOpen={[Function]}
|
||||||
onTransitionStart={[Function]}
|
onTransition={[Function]}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Array [
|
||||||
"bottom": 0,
|
Object {
|
||||||
"left": 0,
|
"overflow": undefined,
|
||||||
"position": "absolute",
|
},
|
||||||
"right": 0,
|
Object {
|
||||||
"top": 0,
|
"bottom": 0,
|
||||||
}
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
transitionSpec={
|
transitionSpec={
|
||||||
Object {
|
Object {
|
||||||
@@ -194,6 +196,7 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
needsOffscreenAlphaCompositing={false}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
@@ -285,6 +288,112 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"zIndex": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
accessibilityElementsHidden={false}
|
||||||
|
importantForAccessibility="auto"
|
||||||
|
onLayout={[Function]}
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={null}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"bottom": 0,
|
||||||
|
"left": 0,
|
||||||
|
"opacity": 1,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
"zIndex": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"backgroundColor": "#fff",
|
||||||
|
"borderBottomColor": "#a7a7aa",
|
||||||
|
"flex": 1,
|
||||||
|
"shadowColor": "#a7a7aa",
|
||||||
|
"shadowOffset": Object {
|
||||||
|
"height": 0.5,
|
||||||
|
"width": 0,
|
||||||
|
},
|
||||||
|
"shadowOpacity": 0.85,
|
||||||
|
"shadowRadius": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"height": 44,
|
||||||
|
"maxHeight": undefined,
|
||||||
|
"minHeight": undefined,
|
||||||
|
"opacity": undefined,
|
||||||
|
"transform": undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
pointerEvents="none"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"height": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"alignItems": "center",
|
||||||
|
"flex": 1,
|
||||||
|
"flexDirection": "row",
|
||||||
|
"justifyContent": "center",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"marginHorizontal": 16,
|
||||||
|
"opacity": 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
accessibilityRole="header"
|
||||||
|
aria-level="1"
|
||||||
|
numberOfLines={1}
|
||||||
|
onLayout={[Function]}
|
||||||
|
style={
|
||||||
|
Object {
|
||||||
|
"color": "rgba(0, 0, 0, 0.9)",
|
||||||
|
"fontSize": 17,
|
||||||
|
"fontWeight": "600",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Home
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
<View
|
<View
|
||||||
onLayout={[Function]}
|
onLayout={[Function]}
|
||||||
style={
|
style={
|
||||||
@@ -323,16 +432,21 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
onGestureCanceled={[Function]}
|
onGestureCanceled={[Function]}
|
||||||
onGestureEnd={[Function]}
|
onGestureEnd={[Function]}
|
||||||
onOpen={[Function]}
|
onOpen={[Function]}
|
||||||
onTransitionStart={[Function]}
|
onTransition={[Function]}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Array [
|
||||||
"bottom": 0,
|
Object {
|
||||||
"left": 0,
|
"overflow": undefined,
|
||||||
"position": "absolute",
|
},
|
||||||
"right": 0,
|
Object {
|
||||||
"top": 0,
|
"bottom": 0,
|
||||||
}
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
transitionSpec={
|
transitionSpec={
|
||||||
Object {
|
Object {
|
||||||
@@ -362,11 +476,11 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
needsOffscreenAlphaCompositing={false}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
"flex": 1,
|
"flex": 1,
|
||||||
"marginTop": 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -455,22 +569,6 @@ exports[`Nested navigators renders succesfully as direct child 1`] = `
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View
|
|
||||||
pointerEvents="box-none"
|
|
||||||
style={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"zIndex": 1,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"left": 0,
|
|
||||||
"position": "absolute",
|
|
||||||
"right": 0,
|
|
||||||
"top": 0,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -11,12 +11,9 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
|
|||||||
<View
|
<View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Array [
|
Object {
|
||||||
Object {
|
"zIndex": 1,
|
||||||
"zIndex": 1,
|
}
|
||||||
},
|
|
||||||
false,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
@@ -172,16 +169,21 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
|
|||||||
onGestureCanceled={[Function]}
|
onGestureCanceled={[Function]}
|
||||||
onGestureEnd={[Function]}
|
onGestureEnd={[Function]}
|
||||||
onOpen={[Function]}
|
onOpen={[Function]}
|
||||||
onTransitionStart={[Function]}
|
onTransition={[Function]}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Array [
|
||||||
"bottom": 0,
|
Object {
|
||||||
"left": 0,
|
"overflow": undefined,
|
||||||
"position": "absolute",
|
},
|
||||||
"right": 0,
|
Object {
|
||||||
"top": 0,
|
"bottom": 0,
|
||||||
}
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
transitionSpec={
|
transitionSpec={
|
||||||
Object {
|
Object {
|
||||||
@@ -211,6 +213,7 @@ exports[`StackNavigator applies correct values when headerRight is present 1`] =
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
needsOffscreenAlphaCompositing={false}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
@@ -317,12 +320,9 @@ exports[`StackNavigator renders successfully 1`] = `
|
|||||||
<View
|
<View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Array [
|
Object {
|
||||||
Object {
|
"zIndex": 1,
|
||||||
"zIndex": 1,
|
}
|
||||||
},
|
|
||||||
false,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
@@ -462,16 +462,21 @@ exports[`StackNavigator renders successfully 1`] = `
|
|||||||
onGestureCanceled={[Function]}
|
onGestureCanceled={[Function]}
|
||||||
onGestureEnd={[Function]}
|
onGestureEnd={[Function]}
|
||||||
onOpen={[Function]}
|
onOpen={[Function]}
|
||||||
onTransitionStart={[Function]}
|
onTransition={[Function]}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Array [
|
||||||
"bottom": 0,
|
Object {
|
||||||
"left": 0,
|
"overflow": undefined,
|
||||||
"position": "absolute",
|
},
|
||||||
"right": 0,
|
Object {
|
||||||
"top": 0,
|
"bottom": 0,
|
||||||
}
|
"left": 0,
|
||||||
|
"position": "absolute",
|
||||||
|
"right": 0,
|
||||||
|
"top": 0,
|
||||||
|
},
|
||||||
|
]
|
||||||
}
|
}
|
||||||
transitionSpec={
|
transitionSpec={
|
||||||
Object {
|
Object {
|
||||||
@@ -501,6 +506,7 @@ exports[`StackNavigator renders successfully 1`] = `
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
|
needsOffscreenAlphaCompositing={false}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={
|
style={
|
||||||
Object {
|
Object {
|
||||||
|
|||||||
@@ -289,8 +289,8 @@ export function forScaleFromCenterAndroid({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const opacity = progress.interpolate({
|
const opacity = progress.interpolate({
|
||||||
inputRange: [0, 0.8, 1, 1.2, 2],
|
inputRange: [0, 0.75, 0.875, 1, 1.0825, 1.2075, 2],
|
||||||
outputRange: [0, 0.5, 1, 0.33, 0],
|
outputRange: [0, 0, 1, 1, 1, 1, 0],
|
||||||
});
|
});
|
||||||
|
|
||||||
const scale = conditional(
|
const scale = conditional(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
import type { TransitionPreset } from '../types';
|
import type { TransitionPreset } from '../types';
|
||||||
|
|
||||||
const ANDROID_VERSION_PIE = 28;
|
const ANDROID_VERSION_PIE = 28;
|
||||||
|
const ANDROID_VERSION_10 = 29;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard iOS navigation transition.
|
* Standard iOS navigation transition.
|
||||||
@@ -102,10 +103,13 @@ export const ScaleFromCenterAndroid: TransitionPreset = {
|
|||||||
*/
|
*/
|
||||||
export const DefaultTransition = Platform.select({
|
export const DefaultTransition = Platform.select({
|
||||||
ios: SlideFromRightIOS,
|
ios: SlideFromRightIOS,
|
||||||
default:
|
android:
|
||||||
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_PIE
|
Platform.Version >= ANDROID_VERSION_10
|
||||||
|
? ScaleFromCenterAndroid
|
||||||
|
: Platform.Version >= ANDROID_VERSION_PIE
|
||||||
? RevealFromBottomAndroid
|
? RevealFromBottomAndroid
|
||||||
: FadeFromBottomAndroid,
|
: FadeFromBottomAndroid,
|
||||||
|
default: ScaleFromCenterAndroid,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
1
packages/stack/src/vendor/index.tsx
vendored
1
packages/stack/src/vendor/index.tsx
vendored
@@ -57,4 +57,5 @@ export type {
|
|||||||
StackHeaderInterpolatedStyle,
|
StackHeaderInterpolatedStyle,
|
||||||
StackHeaderInterpolationProps,
|
StackHeaderInterpolationProps,
|
||||||
StackHeaderStyleInterpolator,
|
StackHeaderStyleInterpolator,
|
||||||
|
TransitionPreset,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|||||||
22
packages/stack/src/vendor/types.tsx
vendored
22
packages/stack/src/vendor/types.tsx
vendored
@@ -56,6 +56,7 @@ export type StackNavigationEventMap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
|
export type StackNavigationHelpers = NavigationProp<NavigationStackState>;
|
||||||
|
|
||||||
export type StackNavigationProp<
|
export type StackNavigationProp<
|
||||||
State = NavigationRoute,
|
State = NavigationRoute,
|
||||||
Params = NavigationParams
|
Params = NavigationParams
|
||||||
@@ -157,6 +158,10 @@ export type StackHeaderOptions = {
|
|||||||
* Whether back button title font should scale to respect Text Size accessibility settings. Defaults to `false`.
|
* Whether back button title font should scale to respect Text Size accessibility settings. Defaults to `false`.
|
||||||
*/
|
*/
|
||||||
headerBackAllowFontScaling?: boolean;
|
headerBackAllowFontScaling?: boolean;
|
||||||
|
/**
|
||||||
|
* Accessibility label for the header back button.
|
||||||
|
*/
|
||||||
|
headerBackAccessibilityLabel?: string;
|
||||||
/**
|
/**
|
||||||
* Title string used by the back button on iOS. Defaults to the previous scene's `headerTitle`.
|
* Title string used by the back button on iOS. Defaults to the previous scene's `headerTitle`.
|
||||||
* Use `headerBackTitleVisible: false` to hide it.
|
* Use `headerBackTitleVisible: false` to hide it.
|
||||||
@@ -336,11 +341,11 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|||||||
*/
|
*/
|
||||||
gestureResponseDistance?: {
|
gestureResponseDistance?: {
|
||||||
/**
|
/**
|
||||||
* Distance for horizontal direction. Defaults to 25.
|
* Distance for vertical direction. Defaults to 135.
|
||||||
*/
|
*/
|
||||||
vertical?: number;
|
vertical?: number;
|
||||||
/**
|
/**
|
||||||
* Distance for vertical direction. Defaults to 135.
|
* Distance for horizontal direction. Defaults to 25.
|
||||||
*/
|
*/
|
||||||
horizontal?: number;
|
horizontal?: number;
|
||||||
};
|
};
|
||||||
@@ -360,6 +365,13 @@ export type StackNavigationOptions = StackHeaderOptions &
|
|||||||
bottom?: number;
|
bottom?: number;
|
||||||
left?: number;
|
left?: number;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Whether to detach the previous screen from the view hierarchy to save memory.
|
||||||
|
* Set it to `false` if you need the previous screen to be seen through the active screen.
|
||||||
|
* Only applicable if `detachInactiveScreens` isn't set to `false`.
|
||||||
|
* Defaults to `false` for the last screen when mode='modal', otherwise `true`.
|
||||||
|
*/
|
||||||
|
detachPreviousScreen?: boolean;
|
||||||
onTransitionStart?: (props: TransitionCallbackProps) => void;
|
onTransitionStart?: (props: TransitionCallbackProps) => void;
|
||||||
onTransitionEnd?: (props: TransitionCallbackProps) => void;
|
onTransitionEnd?: (props: TransitionCallbackProps) => void;
|
||||||
};
|
};
|
||||||
@@ -372,6 +384,12 @@ export type StackNavigationConfig = {
|
|||||||
* Defaults to `true`.
|
* Defaults to `true`.
|
||||||
*/
|
*/
|
||||||
keyboardHandlingEnabled?: boolean;
|
keyboardHandlingEnabled?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether inactive screens should be detached from the view hierarchy to save memory.
|
||||||
|
* Make sure to call `enableScreens` from `react-native-screens` to make it work.
|
||||||
|
* Defaults to `true` on Android, depends on the version of `react-native-screens` on iOS.
|
||||||
|
*/
|
||||||
|
detachInactiveScreens?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StackHeaderLeftButtonProps = {
|
export type StackHeaderLeftButtonProps = {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { BaseButton } from 'react-native-gesture-handler';
|
|||||||
const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);
|
const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);
|
||||||
|
|
||||||
type Props = React.ComponentProps<typeof BaseButton> & {
|
type Props = React.ComponentProps<typeof BaseButton> & {
|
||||||
activeOpacity: number;
|
pressOpacity: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useNativeDriver = Platform.OS !== 'web';
|
const useNativeDriver = Platform.OS !== 'web';
|
||||||
@@ -27,7 +27,7 @@ export default class BorderlessButton extends React.Component<Props> {
|
|||||||
overshootClamping: true,
|
overshootClamping: true,
|
||||||
restDisplacementThreshold: 0.01,
|
restDisplacementThreshold: 0.01,
|
||||||
restSpeedThreshold: 0.01,
|
restSpeedThreshold: 0.01,
|
||||||
toValue: active ? this.props.activeOpacity : 1,
|
toValue: active ? this.props.pressOpacity : 1,
|
||||||
useNativeDriver,
|
useNativeDriver,
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import {
|
|||||||
StyleSheet,
|
StyleSheet,
|
||||||
LayoutChangeEvent,
|
LayoutChangeEvent,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import useTheme from '../../../utils/useTheme';
|
|
||||||
import MaskedView from '../MaskedView';
|
import MaskedView from '../MaskedView';
|
||||||
import TouchableItem from '../TouchableItem';
|
import TouchableItem from '../TouchableItem';
|
||||||
|
import useTheme from '../../../utils/useTheme';
|
||||||
import type { StackHeaderLeftButtonProps } from '../../types';
|
import type { StackHeaderLeftButtonProps } from '../../types';
|
||||||
|
|
||||||
type Props = StackHeaderLeftButtonProps;
|
type Props = StackHeaderLeftButtonProps;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||||
import { NavigationContext } from 'react-navigation';
|
import { NavigationContext } from 'react-navigation';
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
forNoAnimation,
|
forNoAnimation,
|
||||||
forSlideRight,
|
forSlideRight,
|
||||||
} from '../../TransitionConfigs/HeaderStyleInterpolators';
|
} from '../../TransitionConfigs/HeaderStyleInterpolators';
|
||||||
import HeaderShownContext from '../../utils/HeaderShownContext';
|
|
||||||
import PreviousSceneContext from '../../utils/PreviousSceneContext';
|
import PreviousSceneContext from '../../utils/PreviousSceneContext';
|
||||||
import type {
|
import type {
|
||||||
Layout,
|
Layout,
|
||||||
@@ -52,21 +51,17 @@ export default function HeaderContainer({
|
|||||||
style,
|
style,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const focusedRoute = getFocusedRoute();
|
const focusedRoute = getFocusedRoute();
|
||||||
const isParentHeaderShown = React.useContext(HeaderShownContext);
|
|
||||||
const parentPreviousScene = React.useContext(PreviousSceneContext);
|
const parentPreviousScene = React.useContext(PreviousSceneContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View pointerEvents="box-none" style={style}>
|
<Animated.View pointerEvents="box-none" style={style}>
|
||||||
{scenes.slice(-3).map((scene, i, self) => {
|
{scenes.slice(-3).map((scene, i, self) => {
|
||||||
if ((mode === 'screen' && i !== self.length - 1) || !scene) {
|
if ((mode === 'screen' && i !== self.length - 1) || !scene) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const { header, headerShown = true, headerTransparent } =
|
||||||
header,
|
scene.descriptor.options || {};
|
||||||
headerShown = isParentHeaderShown === false,
|
|
||||||
headerTransparent,
|
|
||||||
} = scene.descriptor.options || {};
|
|
||||||
|
|
||||||
if (!headerShown) {
|
if (!headerShown) {
|
||||||
return null;
|
return null;
|
||||||
@@ -81,11 +76,10 @@ export default function HeaderContainer({
|
|||||||
const previousScene = self[i - 1];
|
const previousScene = self[i - 1];
|
||||||
const nextScene = self[i + 1];
|
const nextScene = self[i + 1];
|
||||||
|
|
||||||
const {
|
const { headerShown: previousHeaderShown = true } =
|
||||||
headerShown: previousHeaderShown = isParentHeaderShown === false,
|
previousScene?.descriptor.options || {};
|
||||||
} = previousScene?.descriptor.options || {};
|
|
||||||
|
|
||||||
const { headerShown: nextHeaderShown = isParentHeaderShown === false } =
|
const { headerShown: nextHeaderShown = true } =
|
||||||
nextScene?.descriptor.options || {};
|
nextScene?.descriptor.options || {};
|
||||||
|
|
||||||
const isHeaderStatic =
|
const isHeaderStatic =
|
||||||
@@ -124,11 +118,14 @@ export default function HeaderContainer({
|
|||||||
<View
|
<View
|
||||||
onLayout={
|
onLayout={
|
||||||
onContentHeightChange
|
onContentHeightChange
|
||||||
? (e) =>
|
? (e) => {
|
||||||
|
const { height } = e.nativeEvent.layout;
|
||||||
|
|
||||||
onContentHeightChange({
|
onContentHeightChange({
|
||||||
route: scene.route,
|
route: scene.route,
|
||||||
height: e.nativeEvent.layout.height,
|
height,
|
||||||
})
|
});
|
||||||
|
}
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
pointerEvents={isFocused ? 'box-none' : 'none'}
|
pointerEvents={isFocused ? 'box-none' : 'none'}
|
||||||
@@ -150,7 +147,7 @@ export default function HeaderContainer({
|
|||||||
</NavigationContext.Provider>
|
</NavigationContext.Provider>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</View>
|
</Animated.View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,170 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { View, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
|
||||||
import {
|
|
||||||
NavigationContext,
|
|
||||||
NavigationRouteContext,
|
|
||||||
Route,
|
|
||||||
ParamListBase,
|
|
||||||
} from '@react-navigation/native';
|
|
||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
|
||||||
|
|
||||||
import Header from './Header';
|
|
||||||
import {
|
|
||||||
forSlideLeft,
|
|
||||||
forSlideUp,
|
|
||||||
forNoAnimation,
|
|
||||||
forSlideRight,
|
|
||||||
} from '../../TransitionConfigs/HeaderStyleInterpolators';
|
|
||||||
import HeaderShownContext from '../../utils/HeaderShownContext';
|
|
||||||
import PreviousSceneContext from '../../utils/PreviousSceneContext';
|
|
||||||
import type {
|
|
||||||
Layout,
|
|
||||||
Scene,
|
|
||||||
StackHeaderStyleInterpolator,
|
|
||||||
StackNavigationProp,
|
|
||||||
GestureDirection,
|
|
||||||
} from '../../types';
|
|
||||||
|
|
||||||
export type Props = {
|
|
||||||
mode: 'float' | 'screen';
|
|
||||||
layout: Layout;
|
|
||||||
insets: EdgeInsets;
|
|
||||||
scenes: (Scene<Route<string>> | undefined)[];
|
|
||||||
getPreviousScene: (props: {
|
|
||||||
route: Route<string>;
|
|
||||||
}) => Scene<Route<string>> | undefined;
|
|
||||||
getFocusedRoute: () => Route<string>;
|
|
||||||
onContentHeightChange?: (props: {
|
|
||||||
route: Route<string>;
|
|
||||||
height: number;
|
|
||||||
}) => void;
|
|
||||||
styleInterpolator: StackHeaderStyleInterpolator;
|
|
||||||
gestureDirection: GestureDirection;
|
|
||||||
style?: StyleProp<ViewStyle>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function HeaderContainer({
|
|
||||||
mode,
|
|
||||||
scenes,
|
|
||||||
layout,
|
|
||||||
insets,
|
|
||||||
getPreviousScene,
|
|
||||||
getFocusedRoute,
|
|
||||||
onContentHeightChange,
|
|
||||||
gestureDirection,
|
|
||||||
styleInterpolator,
|
|
||||||
style,
|
|
||||||
}: Props) {
|
|
||||||
const focusedRoute = getFocusedRoute();
|
|
||||||
const isParentHeaderShown = React.useContext(HeaderShownContext);
|
|
||||||
const parentPreviousScene = React.useContext(PreviousSceneContext);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View pointerEvents="box-none" style={style}>
|
|
||||||
{scenes.slice(-3).map((scene, i, self) => {
|
|
||||||
if ((mode === 'screen' && i !== self.length - 1) || !scene) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {
|
|
||||||
header,
|
|
||||||
headerShown = isParentHeaderShown === false,
|
|
||||||
headerTransparent,
|
|
||||||
} = scene.descriptor.options || {};
|
|
||||||
|
|
||||||
if (!headerShown) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isFocused = focusedRoute.key === scene.route.key;
|
|
||||||
const previous =
|
|
||||||
getPreviousScene({ route: scene.route }) ?? parentPreviousScene;
|
|
||||||
|
|
||||||
// If the screen is next to a headerless screen, we need to make the header appear static
|
|
||||||
// This makes the header look like it's moving with the screen
|
|
||||||
const previousScene = self[i - 1];
|
|
||||||
const nextScene = self[i + 1];
|
|
||||||
|
|
||||||
const {
|
|
||||||
headerShown: previousHeaderShown = isParentHeaderShown === false,
|
|
||||||
} = previousScene?.descriptor.options || {};
|
|
||||||
|
|
||||||
const { headerShown: nextHeaderShown = isParentHeaderShown === false } =
|
|
||||||
nextScene?.descriptor.options || {};
|
|
||||||
|
|
||||||
const isHeaderStatic =
|
|
||||||
(previousHeaderShown === false &&
|
|
||||||
// We still need to animate when coming back from next scene
|
|
||||||
// A hacky way to check this is if the next scene exists
|
|
||||||
!nextScene) ||
|
|
||||||
nextHeaderShown === false;
|
|
||||||
|
|
||||||
const props = {
|
|
||||||
mode,
|
|
||||||
layout,
|
|
||||||
insets,
|
|
||||||
scene,
|
|
||||||
previous,
|
|
||||||
navigation: scene.descriptor.navigation as StackNavigationProp<
|
|
||||||
ParamListBase
|
|
||||||
>,
|
|
||||||
styleInterpolator:
|
|
||||||
mode === 'float'
|
|
||||||
? isHeaderStatic
|
|
||||||
? gestureDirection === 'vertical' ||
|
|
||||||
gestureDirection === 'vertical-inverted'
|
|
||||||
? forSlideUp
|
|
||||||
: gestureDirection === 'horizontal-inverted'
|
|
||||||
? forSlideRight
|
|
||||||
: forSlideLeft
|
|
||||||
: styleInterpolator
|
|
||||||
: forNoAnimation,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NavigationContext.Provider
|
|
||||||
key={scene.route.key}
|
|
||||||
value={scene.descriptor.navigation}
|
|
||||||
>
|
|
||||||
<NavigationRouteContext.Provider value={scene.route}>
|
|
||||||
<View
|
|
||||||
onLayout={
|
|
||||||
onContentHeightChange
|
|
||||||
? (e) =>
|
|
||||||
onContentHeightChange({
|
|
||||||
route: scene.route,
|
|
||||||
height: e.nativeEvent.layout.height,
|
|
||||||
})
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
pointerEvents={isFocused ? 'box-none' : 'none'}
|
|
||||||
accessibilityElementsHidden={!isFocused}
|
|
||||||
importantForAccessibility={
|
|
||||||
isFocused ? 'auto' : 'no-hide-descendants'
|
|
||||||
}
|
|
||||||
style={
|
|
||||||
// Avoid positioning the focused header absolutely
|
|
||||||
// Otherwise accessibility tools don't seem to be able to find it
|
|
||||||
(mode === 'float' && !isFocused) || headerTransparent
|
|
||||||
? styles.header
|
|
||||||
: null
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{header !== undefined ? header(props) : <Header {...props} />}
|
|
||||||
</View>
|
|
||||||
</NavigationRouteContext.Provider>
|
|
||||||
</NavigationContext.Provider>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
header: {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -11,6 +11,7 @@ import type { EdgeInsets } from 'react-native-safe-area-context';
|
|||||||
import type { NavigationRoute } from 'react-navigation';
|
import type { NavigationRoute } from 'react-navigation';
|
||||||
import HeaderBackButton from './HeaderBackButton';
|
import HeaderBackButton from './HeaderBackButton';
|
||||||
import HeaderBackground from './HeaderBackground';
|
import HeaderBackground from './HeaderBackground';
|
||||||
|
import HeaderShownContext from '../../utils/HeaderShownContext';
|
||||||
import memoize from '../../utils/memoize';
|
import memoize from '../../utils/memoize';
|
||||||
import type {
|
import type {
|
||||||
Layout,
|
Layout,
|
||||||
@@ -32,11 +33,6 @@ type Props = StackHeaderOptions & {
|
|||||||
styleInterpolator: StackHeaderStyleInterpolator;
|
styleInterpolator: StackHeaderStyleInterpolator;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
|
||||||
titleLayout?: Layout;
|
|
||||||
leftLabelLayout?: Layout;
|
|
||||||
};
|
|
||||||
|
|
||||||
const warnIfHeaderStylesDefined = (styles: Record<string, any>) => {
|
const warnIfHeaderStylesDefined = (styles: Record<string, any>) => {
|
||||||
Object.keys(styles).forEach((styleProp) => {
|
Object.keys(styles).forEach((styleProp) => {
|
||||||
const value = styles[styleProp];
|
const value = styles[styleProp];
|
||||||
@@ -76,30 +72,35 @@ export const getDefaultHeaderHeight = (
|
|||||||
return headerHeight + statusBarHeight;
|
return headerHeight + statusBarHeight;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class HeaderSegment extends React.Component<Props, State> {
|
export default function HeaderSegment(props: Props) {
|
||||||
state: State = {};
|
const [leftLabelLayout, setLeftLabelLayout] = React.useState<
|
||||||
|
Layout | undefined
|
||||||
|
>(undefined);
|
||||||
|
|
||||||
private handleTitleLayout = (e: LayoutChangeEvent) => {
|
const [titleLayout, setTitleLayout] = React.useState<Layout | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
const isParentHeaderShown = React.useContext(HeaderShownContext);
|
||||||
|
|
||||||
|
const handleTitleLayout = (e: LayoutChangeEvent) => {
|
||||||
const { height, width } = e.nativeEvent.layout;
|
const { height, width } = e.nativeEvent.layout;
|
||||||
|
|
||||||
this.setState(({ titleLayout }) => {
|
setTitleLayout((titleLayout) => {
|
||||||
if (
|
if (
|
||||||
titleLayout &&
|
titleLayout &&
|
||||||
height === titleLayout.height &&
|
height === titleLayout.height &&
|
||||||
width === titleLayout.width
|
width === titleLayout.width
|
||||||
) {
|
) {
|
||||||
return null;
|
return titleLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { height, width };
|
||||||
titleLayout: { height, width },
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private handleLeftLabelLayout = (e: LayoutChangeEvent) => {
|
const handleLeftLabelLayout = (e: LayoutChangeEvent) => {
|
||||||
const { height, width } = e.nativeEvent.layout;
|
const { height, width } = e.nativeEvent.layout;
|
||||||
const { leftLabelLayout } = this.state;
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
leftLabelLayout &&
|
leftLabelLayout &&
|
||||||
@@ -109,10 +110,10 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ leftLabelLayout: { height, width } });
|
setLeftLabelLayout({ height, width });
|
||||||
};
|
};
|
||||||
|
|
||||||
private getInterpolatedStyle = memoize(
|
const getInterpolatedStyle = memoize(
|
||||||
(
|
(
|
||||||
styleInterpolator: StackHeaderStyleInterpolator,
|
styleInterpolator: StackHeaderStyleInterpolator,
|
||||||
layout: Layout,
|
layout: Layout,
|
||||||
@@ -137,258 +138,253 @@ export default class HeaderSegment extends React.Component<Props, State> {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
render() {
|
const {
|
||||||
const {
|
scene,
|
||||||
scene,
|
layout,
|
||||||
layout,
|
insets,
|
||||||
insets,
|
title: currentTitle,
|
||||||
title: currentTitle,
|
leftLabel: previousTitle,
|
||||||
leftLabel: previousTitle,
|
onGoBack,
|
||||||
onGoBack,
|
headerTitle,
|
||||||
headerTitle,
|
headerTitleAlign = Platform.select({
|
||||||
headerTitleAlign = Platform.select({
|
ios: 'center',
|
||||||
ios: 'center',
|
default: 'left',
|
||||||
default: 'left',
|
}),
|
||||||
}),
|
headerLeft: left = onGoBack
|
||||||
headerLeft: left = onGoBack
|
? (props: StackHeaderLeftButtonProps) => <HeaderBackButton {...props} />
|
||||||
? (props: StackHeaderLeftButtonProps) => <HeaderBackButton {...props} />
|
: undefined,
|
||||||
: undefined,
|
headerTransparent,
|
||||||
headerTransparent,
|
headerTintColor,
|
||||||
headerTintColor,
|
headerBackground,
|
||||||
headerBackground,
|
headerRight: right,
|
||||||
headerRight: right,
|
headerBackImage: backImage,
|
||||||
headerBackImage: backImage,
|
headerBackTitle: leftLabel,
|
||||||
headerBackTitle: leftLabel,
|
headerBackTitleVisible,
|
||||||
headerBackTitleVisible,
|
headerTruncatedBackTitle: truncatedLabel,
|
||||||
headerTruncatedBackTitle: truncatedLabel,
|
headerPressColorAndroid: pressColorAndroid,
|
||||||
headerPressColorAndroid: pressColorAndroid,
|
headerBackAccessibilityLabel: backAccessibilityLabel,
|
||||||
headerBackAllowFontScaling: backAllowFontScaling,
|
headerBackAllowFontScaling: backAllowFontScaling,
|
||||||
headerTitleAllowFontScaling: titleAllowFontScaling,
|
headerTitleAllowFontScaling: titleAllowFontScaling,
|
||||||
headerTitleStyle: customTitleStyle,
|
headerTitleStyle: customTitleStyle,
|
||||||
headerBackTitleStyle: customLeftLabelStyle,
|
headerBackTitleStyle: customLeftLabelStyle,
|
||||||
headerLeftContainerStyle: leftContainerStyle,
|
headerLeftContainerStyle: leftContainerStyle,
|
||||||
headerRightContainerStyle: rightContainerStyle,
|
headerRightContainerStyle: rightContainerStyle,
|
||||||
headerTitleContainerStyle: titleContainerStyle,
|
headerTitleContainerStyle: titleContainerStyle,
|
||||||
headerStyle: customHeaderStyle,
|
headerStyle: customHeaderStyle,
|
||||||
headerStatusBarHeight = insets.top,
|
headerStatusBarHeight = isParentHeaderShown ? 0 : insets.top,
|
||||||
styleInterpolator,
|
styleInterpolator,
|
||||||
} = this.props;
|
} = props;
|
||||||
|
|
||||||
const { leftLabelLayout, titleLayout } = this.state;
|
const defaultHeight = getDefaultHeaderHeight(layout, headerStatusBarHeight);
|
||||||
|
|
||||||
const defaultHeight = getDefaultHeaderHeight(layout, headerStatusBarHeight);
|
const {
|
||||||
|
height = defaultHeight,
|
||||||
|
minHeight,
|
||||||
|
maxHeight,
|
||||||
|
backgroundColor,
|
||||||
|
borderBottomColor,
|
||||||
|
borderBottomEndRadius,
|
||||||
|
borderBottomLeftRadius,
|
||||||
|
borderBottomRightRadius,
|
||||||
|
borderBottomStartRadius,
|
||||||
|
borderBottomWidth,
|
||||||
|
borderColor,
|
||||||
|
borderEndColor,
|
||||||
|
borderEndWidth,
|
||||||
|
borderLeftColor,
|
||||||
|
borderLeftWidth,
|
||||||
|
borderRadius,
|
||||||
|
borderRightColor,
|
||||||
|
borderRightWidth,
|
||||||
|
borderStartColor,
|
||||||
|
borderStartWidth,
|
||||||
|
borderStyle,
|
||||||
|
borderTopColor,
|
||||||
|
borderTopEndRadius,
|
||||||
|
borderTopLeftRadius,
|
||||||
|
borderTopRightRadius,
|
||||||
|
borderTopStartRadius,
|
||||||
|
borderTopWidth,
|
||||||
|
borderWidth,
|
||||||
|
// @ts-expect-error: web support for shadow
|
||||||
|
boxShadow,
|
||||||
|
elevation,
|
||||||
|
shadowColor,
|
||||||
|
shadowOffset,
|
||||||
|
shadowOpacity,
|
||||||
|
shadowRadius,
|
||||||
|
opacity,
|
||||||
|
transform,
|
||||||
|
...unsafeStyles
|
||||||
|
} = StyleSheet.flatten(customHeaderStyle || {}) as ViewStyle;
|
||||||
|
|
||||||
const {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
height = defaultHeight,
|
warnIfHeaderStylesDefined(unsafeStyles);
|
||||||
minHeight,
|
}
|
||||||
maxHeight,
|
|
||||||
backgroundColor,
|
|
||||||
borderBottomColor,
|
|
||||||
borderBottomEndRadius,
|
|
||||||
borderBottomLeftRadius,
|
|
||||||
borderBottomRightRadius,
|
|
||||||
borderBottomStartRadius,
|
|
||||||
borderBottomWidth,
|
|
||||||
borderColor,
|
|
||||||
borderEndColor,
|
|
||||||
borderEndWidth,
|
|
||||||
borderLeftColor,
|
|
||||||
borderLeftWidth,
|
|
||||||
borderRadius,
|
|
||||||
borderRightColor,
|
|
||||||
borderRightWidth,
|
|
||||||
borderStartColor,
|
|
||||||
borderStartWidth,
|
|
||||||
borderStyle,
|
|
||||||
borderTopColor,
|
|
||||||
borderTopEndRadius,
|
|
||||||
borderTopLeftRadius,
|
|
||||||
borderTopRightRadius,
|
|
||||||
borderTopStartRadius,
|
|
||||||
borderTopWidth,
|
|
||||||
borderWidth,
|
|
||||||
// @ts-expect-error: web support for shadow
|
|
||||||
boxShadow,
|
|
||||||
elevation,
|
|
||||||
shadowColor,
|
|
||||||
shadowOffset,
|
|
||||||
shadowOpacity,
|
|
||||||
shadowRadius,
|
|
||||||
opacity,
|
|
||||||
transform,
|
|
||||||
...unsafeStyles
|
|
||||||
} = StyleSheet.flatten(customHeaderStyle || {}) as ViewStyle;
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
const safeStyles: ViewStyle = {
|
||||||
warnIfHeaderStylesDefined(unsafeStyles);
|
backgroundColor,
|
||||||
|
borderBottomColor,
|
||||||
|
borderBottomEndRadius,
|
||||||
|
borderBottomLeftRadius,
|
||||||
|
borderBottomRightRadius,
|
||||||
|
borderBottomStartRadius,
|
||||||
|
borderBottomWidth,
|
||||||
|
borderColor,
|
||||||
|
borderEndColor,
|
||||||
|
borderEndWidth,
|
||||||
|
borderLeftColor,
|
||||||
|
borderLeftWidth,
|
||||||
|
borderRadius,
|
||||||
|
borderRightColor,
|
||||||
|
borderRightWidth,
|
||||||
|
borderStartColor,
|
||||||
|
borderStartWidth,
|
||||||
|
borderStyle,
|
||||||
|
borderTopColor,
|
||||||
|
borderTopEndRadius,
|
||||||
|
borderTopLeftRadius,
|
||||||
|
borderTopRightRadius,
|
||||||
|
borderTopStartRadius,
|
||||||
|
borderTopWidth,
|
||||||
|
borderWidth,
|
||||||
|
// @ts-expect-error: boxShadow is only for Web
|
||||||
|
boxShadow,
|
||||||
|
elevation,
|
||||||
|
shadowColor,
|
||||||
|
shadowOffset,
|
||||||
|
shadowOpacity,
|
||||||
|
shadowRadius,
|
||||||
|
opacity,
|
||||||
|
transform,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setting a property to undefined triggers default style
|
||||||
|
// So we need to filter them out
|
||||||
|
// Users can use `null` instead
|
||||||
|
for (const styleProp in safeStyles) {
|
||||||
|
// @ts-expect-error: typescript wrongly complains that styleProp cannot be used to index safeStyles
|
||||||
|
if (safeStyles[styleProp] === undefined) {
|
||||||
|
// @ts-expect-error
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
|
delete safeStyles[styleProp];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const safeStyles: ViewStyle = {
|
const {
|
||||||
backgroundColor,
|
titleStyle,
|
||||||
borderBottomColor,
|
leftButtonStyle,
|
||||||
borderBottomEndRadius,
|
leftLabelStyle,
|
||||||
borderBottomLeftRadius,
|
rightButtonStyle,
|
||||||
borderBottomRightRadius,
|
backgroundStyle,
|
||||||
borderBottomStartRadius,
|
} = getInterpolatedStyle(
|
||||||
borderBottomWidth,
|
styleInterpolator,
|
||||||
borderColor,
|
layout,
|
||||||
borderEndColor,
|
scene.progress.current,
|
||||||
borderEndWidth,
|
scene.progress.next,
|
||||||
borderLeftColor,
|
titleLayout,
|
||||||
borderLeftWidth,
|
previousTitle ? leftLabelLayout : undefined,
|
||||||
borderRadius,
|
typeof height === 'number' ? height : defaultHeight
|
||||||
borderRightColor,
|
);
|
||||||
borderRightWidth,
|
|
||||||
borderStartColor,
|
|
||||||
borderStartWidth,
|
|
||||||
borderStyle,
|
|
||||||
borderTopColor,
|
|
||||||
borderTopEndRadius,
|
|
||||||
borderTopLeftRadius,
|
|
||||||
borderTopRightRadius,
|
|
||||||
borderTopStartRadius,
|
|
||||||
borderTopWidth,
|
|
||||||
borderWidth,
|
|
||||||
// @ts-expect-error: boxShadow is only for Web
|
|
||||||
boxShadow,
|
|
||||||
elevation,
|
|
||||||
shadowColor,
|
|
||||||
shadowOffset,
|
|
||||||
shadowOpacity,
|
|
||||||
shadowRadius,
|
|
||||||
opacity,
|
|
||||||
transform,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Setting a property to undefined triggers default style
|
const leftButton = left
|
||||||
// So we need to filter them out
|
? left({
|
||||||
// Users can use `null` instead
|
backImage,
|
||||||
for (const styleProp in safeStyles) {
|
pressColorAndroid,
|
||||||
// @ts-expect-error: typescript wrongly complains that styleProp cannot be used to index safeStyles
|
accessibilityLabel: backAccessibilityLabel,
|
||||||
if (safeStyles[styleProp] === undefined) {
|
allowFontScaling: backAllowFontScaling,
|
||||||
// @ts-expect-error
|
onPress: onGoBack,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
labelVisible: headerBackTitleVisible,
|
||||||
delete safeStyles[styleProp];
|
label: leftLabel !== undefined ? leftLabel : previousTitle,
|
||||||
}
|
truncatedLabel,
|
||||||
}
|
labelStyle: [leftLabelStyle, customLeftLabelStyle],
|
||||||
|
onLabelLayout: handleLeftLabelLayout,
|
||||||
|
screenLayout: layout,
|
||||||
|
titleLayout,
|
||||||
|
tintColor: headerTintColor,
|
||||||
|
canGoBack: Boolean(onGoBack),
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
const {
|
const rightButton = right ? right({ tintColor: headerTintColor }) : null;
|
||||||
titleStyle,
|
|
||||||
leftButtonStyle,
|
|
||||||
leftLabelStyle,
|
|
||||||
rightButtonStyle,
|
|
||||||
backgroundStyle,
|
|
||||||
} = this.getInterpolatedStyle(
|
|
||||||
styleInterpolator,
|
|
||||||
layout,
|
|
||||||
scene.progress.current,
|
|
||||||
scene.progress.next,
|
|
||||||
titleLayout,
|
|
||||||
previousTitle ? leftLabelLayout : undefined,
|
|
||||||
typeof height === 'number' ? height : defaultHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
const leftButton = left
|
return (
|
||||||
? left({
|
<React.Fragment>
|
||||||
backImage,
|
<Animated.View
|
||||||
pressColorAndroid,
|
pointerEvents="box-none"
|
||||||
allowFontScaling: backAllowFontScaling,
|
style={[StyleSheet.absoluteFill, { zIndex: 0 }, backgroundStyle]}
|
||||||
onPress: onGoBack,
|
>
|
||||||
labelVisible: headerBackTitleVisible,
|
{headerBackground ? (
|
||||||
label: leftLabel !== undefined ? leftLabel : previousTitle,
|
headerBackground({ style: safeStyles })
|
||||||
truncatedLabel,
|
) : headerTransparent ? null : (
|
||||||
labelStyle: [leftLabelStyle, customLeftLabelStyle],
|
<HeaderBackground style={safeStyles} />
|
||||||
onLabelLayout: this.handleLeftLabelLayout,
|
)}
|
||||||
screenLayout: layout,
|
</Animated.View>
|
||||||
titleLayout,
|
<Animated.View
|
||||||
tintColor: headerTintColor,
|
pointerEvents="box-none"
|
||||||
canGoBack: Boolean(onGoBack),
|
style={[{ height, minHeight, maxHeight, opacity, transform }]}
|
||||||
})
|
>
|
||||||
: null;
|
<View pointerEvents="none" style={{ height: headerStatusBarHeight }} />
|
||||||
|
<View pointerEvents="box-none" style={styles.content}>
|
||||||
const rightButton = right ? right({ tintColor: headerTintColor }) : null;
|
{leftButton ? (
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
<Animated.View
|
|
||||||
pointerEvents="box-none"
|
|
||||||
style={[StyleSheet.absoluteFill, { zIndex: 0 }, backgroundStyle]}
|
|
||||||
>
|
|
||||||
{headerBackground ? (
|
|
||||||
headerBackground({ style: safeStyles })
|
|
||||||
) : headerTransparent ? null : (
|
|
||||||
<HeaderBackground style={safeStyles} />
|
|
||||||
)}
|
|
||||||
</Animated.View>
|
|
||||||
<Animated.View
|
|
||||||
pointerEvents="box-none"
|
|
||||||
style={[{ height, minHeight, maxHeight, opacity, transform }]}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
pointerEvents="none"
|
|
||||||
style={{ height: headerStatusBarHeight }}
|
|
||||||
/>
|
|
||||||
<View pointerEvents="box-none" style={styles.content}>
|
|
||||||
{leftButton ? (
|
|
||||||
<Animated.View
|
|
||||||
pointerEvents="box-none"
|
|
||||||
style={[
|
|
||||||
styles.left,
|
|
||||||
{ left: insets.left },
|
|
||||||
leftButtonStyle,
|
|
||||||
leftContainerStyle,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{leftButton}
|
|
||||||
</Animated.View>
|
|
||||||
) : null}
|
|
||||||
<Animated.View
|
<Animated.View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={[
|
style={[
|
||||||
headerTitleAlign === 'left'
|
styles.left,
|
||||||
? {
|
{ left: insets.left },
|
||||||
position: 'absolute',
|
leftButtonStyle,
|
||||||
left: (leftButton ? 72 : 16) + insets.left,
|
leftContainerStyle,
|
||||||
right: (rightButton ? 72 : 16) + insets.right,
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
marginHorizontal:
|
|
||||||
(leftButton ? 32 : 16) +
|
|
||||||
(leftButton && headerBackTitleVisible !== false
|
|
||||||
? 40
|
|
||||||
: 0) +
|
|
||||||
Math.max(insets.left, insets.right),
|
|
||||||
},
|
|
||||||
titleStyle,
|
|
||||||
titleContainerStyle,
|
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{headerTitle({
|
{leftButton}
|
||||||
children: currentTitle,
|
|
||||||
onLayout: this.handleTitleLayout,
|
|
||||||
allowFontScaling: titleAllowFontScaling,
|
|
||||||
tintColor: headerTintColor,
|
|
||||||
style: customTitleStyle,
|
|
||||||
})}
|
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
{rightButton ? (
|
) : null}
|
||||||
<Animated.View
|
<Animated.View
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
style={[
|
style={[
|
||||||
styles.right,
|
headerTitleAlign === 'left'
|
||||||
{ right: insets.right },
|
? {
|
||||||
rightButtonStyle,
|
position: 'absolute',
|
||||||
rightContainerStyle,
|
left: (leftButton ? 72 : 16) + insets.left,
|
||||||
]}
|
right: (rightButton ? 72 : 16) + insets.right,
|
||||||
>
|
}
|
||||||
{rightButton}
|
: {
|
||||||
</Animated.View>
|
marginHorizontal:
|
||||||
) : null}
|
(leftButton ? 32 : 16) +
|
||||||
</View>
|
(leftButton && headerBackTitleVisible !== false
|
||||||
</Animated.View>
|
? 40
|
||||||
</React.Fragment>
|
: 0) +
|
||||||
);
|
Math.max(insets.left, insets.right),
|
||||||
}
|
},
|
||||||
|
titleStyle,
|
||||||
|
titleContainerStyle,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{headerTitle({
|
||||||
|
children: currentTitle,
|
||||||
|
onLayout: handleTitleLayout,
|
||||||
|
allowFontScaling: titleAllowFontScaling,
|
||||||
|
tintColor: headerTintColor,
|
||||||
|
style: customTitleStyle,
|
||||||
|
})}
|
||||||
|
</Animated.View>
|
||||||
|
{rightButton ? (
|
||||||
|
<Animated.View
|
||||||
|
pointerEvents="box-none"
|
||||||
|
style={[
|
||||||
|
styles.right,
|
||||||
|
{ right: insets.right },
|
||||||
|
rightButtonStyle,
|
||||||
|
rightContainerStyle,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{rightButton}
|
||||||
|
</Animated.View>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
</Animated.View>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { TextInput, Platform, Keyboard } from 'react-native';
|
import { TextInput, Keyboard, HostComponent } from 'react-native';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
children: (props: {
|
children: (props: {
|
||||||
onPageChangeStart: () => void;
|
onPageChangeStart: () => void;
|
||||||
onPageChangeConfirm: () => void;
|
onPageChangeConfirm: (force: boolean) => void;
|
||||||
onPageChangeCancel: () => void;
|
onPageChangeCancel: () => void;
|
||||||
}) => React.ReactNode;
|
}) => React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type InputRef = React.ElementRef<HostComponent<unknown>> | undefined;
|
||||||
|
|
||||||
export default class KeyboardManager extends React.Component<Props> {
|
export default class KeyboardManager extends React.Component<Props> {
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
@@ -17,7 +19,7 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
|
|
||||||
// Numeric id of the previously focused text input
|
// Numeric id of the previously focused text input
|
||||||
// When a gesture didn't change the tab, we can restore the focused input with this
|
// When a gesture didn't change the tab, we can restore the focused input with this
|
||||||
private previouslyFocusedTextInput: any | null = null;
|
private previouslyFocusedTextInput: InputRef = undefined;
|
||||||
private startTimestamp: number = 0;
|
private startTimestamp: number = 0;
|
||||||
private keyboardTimeout: any;
|
private keyboardTimeout: any;
|
||||||
|
|
||||||
@@ -35,7 +37,8 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
|
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
|
|
||||||
const input: any = TextInput.State.currentlyFocusedInput
|
// @ts-expect-error: blurTextInput accepts both number and ref, but types say only ref
|
||||||
|
const input: InputRef = TextInput.State.currentlyFocusedInput
|
||||||
? TextInput.State.currentlyFocusedInput()
|
? TextInput.State.currentlyFocusedInput()
|
||||||
: TextInput.State.currentlyFocusedField();
|
: TextInput.State.currentlyFocusedField();
|
||||||
|
|
||||||
@@ -49,23 +52,30 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
this.startTimestamp = Date.now();
|
this.startTimestamp = Date.now();
|
||||||
};
|
};
|
||||||
|
|
||||||
private handlePageChangeConfirm = () => {
|
private handlePageChangeConfirm = (force: boolean) => {
|
||||||
if (!this.props.enabled) {
|
if (!this.props.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clearKeyboardTimeout();
|
this.clearKeyboardTimeout();
|
||||||
|
|
||||||
const input = this.previouslyFocusedTextInput;
|
if (force) {
|
||||||
|
// Always dismiss input, even if we don't have a ref to it
|
||||||
if (Platform.OS === 'android') {
|
// We might not have the ref if onPageChangeStart was never called
|
||||||
|
// This can happen if page change was not from a gesture
|
||||||
Keyboard.dismiss();
|
Keyboard.dismiss();
|
||||||
} else if (input) {
|
} else {
|
||||||
TextInput.State.blurTextInput(input);
|
const input = this.previouslyFocusedTextInput;
|
||||||
|
|
||||||
|
if (input) {
|
||||||
|
// Dismiss the keyboard only if an input was a focused before
|
||||||
|
// This makes sure we don't dismiss input on going back and focusing an input
|
||||||
|
TextInput.State.blurTextInput(input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup the ID on successful page change
|
// Cleanup the ID on successful page change
|
||||||
this.previouslyFocusedTextInput = null;
|
this.previouslyFocusedTextInput = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
private handlePageChangeCancel = () => {
|
private handlePageChangeCancel = () => {
|
||||||
@@ -89,11 +99,11 @@ export default class KeyboardManager extends React.Component<Props> {
|
|||||||
if (Date.now() - this.startTimestamp < 100) {
|
if (Date.now() - this.startTimestamp < 100) {
|
||||||
this.keyboardTimeout = setTimeout(() => {
|
this.keyboardTimeout = setTimeout(() => {
|
||||||
TextInput.State.focusTextInput(input);
|
TextInput.State.focusTextInput(input);
|
||||||
this.previouslyFocusedTextInput = null;
|
this.previouslyFocusedTextInput = undefined;
|
||||||
}, 100);
|
}, 100);
|
||||||
} else {
|
} else {
|
||||||
TextInput.State.focusTextInput(input);
|
TextInput.State.focusTextInput(input);
|
||||||
this.previouslyFocusedTextInput = null;
|
this.previouslyFocusedTextInput = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
27
packages/stack/src/vendor/views/Screens.tsx
vendored
27
packages/stack/src/vendor/views/Screens.tsx
vendored
@@ -34,6 +34,9 @@ class WebScreen extends React.Component<
|
|||||||
|
|
||||||
const AnimatedWebScreen = Animated.createAnimatedComponent(WebScreen);
|
const AnimatedWebScreen = Animated.createAnimatedComponent(WebScreen);
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export const shouldUseActivityState = Screens?.shouldUseActivityState;
|
||||||
|
|
||||||
export const MaybeScreenContainer = ({
|
export const MaybeScreenContainer = ({
|
||||||
enabled,
|
enabled,
|
||||||
...rest
|
...rest
|
||||||
@@ -41,8 +44,11 @@ export const MaybeScreenContainer = ({
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
if (enabled && Platform.OS !== 'web' && Screens && Screens.screensEnabled()) {
|
if (enabled && Platform.OS !== 'web' && Screens?.screensEnabled()) {
|
||||||
return <Screens.ScreenContainer {...rest} />;
|
return (
|
||||||
|
// @ts-ignore
|
||||||
|
<Screens.ScreenContainer enabled={enabled} {...rest} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <View {...rest} />;
|
return <View {...rest} />;
|
||||||
@@ -54,16 +60,25 @@ export const MaybeScreen = ({
|
|||||||
...rest
|
...rest
|
||||||
}: ViewProps & {
|
}: ViewProps & {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
active: 0 | 1 | Animated.AnimatedInterpolation;
|
active: 0 | 1 | 2 | Animated.AnimatedInterpolation;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
if (enabled && Platform.OS === 'web') {
|
if (enabled && Platform.OS === 'web') {
|
||||||
return <AnimatedWebScreen active={active} {...rest} />;
|
return <AnimatedWebScreen active={active} {...rest} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled && Screens && Screens.screensEnabled()) {
|
if (enabled && Screens?.screensEnabled()) {
|
||||||
// @ts-expect-error: stackPresentation is incorrectly marked as required
|
if (shouldUseActivityState) {
|
||||||
return <Screens.Screen active={active} {...rest} />;
|
return (
|
||||||
|
// @ts-expect-error: there was an `active` prop and no `activityState` in older version and stackPresentation was required
|
||||||
|
<Screens.Screen enabled={enabled} activityState={active} {...rest} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
// @ts-expect-error: there was an `active` prop and no `activityState` in older version and stackPresentation was required
|
||||||
|
<Screens.Screen enabled={enabled} active={active} {...rest} />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return <View {...rest} />;
|
return <View {...rest} />;
|
||||||
|
|||||||
16
packages/stack/src/vendor/views/Stack/Card.tsx
vendored
16
packages/stack/src/vendor/views/Stack/Card.tsx
vendored
@@ -41,7 +41,7 @@ type Props = ViewProps & {
|
|||||||
gestureDirection: GestureDirection;
|
gestureDirection: GestureDirection;
|
||||||
onOpen: () => void;
|
onOpen: () => void;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onTransitionStart?: (props: { closing: boolean }) => void;
|
onTransition?: (props: { closing: boolean; gesture: boolean }) => void;
|
||||||
onGestureBegin?: () => void;
|
onGestureBegin?: () => void;
|
||||||
onGestureCanceled?: () => void;
|
onGestureCanceled?: () => void;
|
||||||
onGestureEnd?: () => void;
|
onGestureEnd?: () => void;
|
||||||
@@ -79,6 +79,15 @@ const GESTURE_RESPONSE_DISTANCE_VERTICAL = 135;
|
|||||||
|
|
||||||
const useNativeDriver = Platform.OS !== 'web';
|
const useNativeDriver = Platform.OS !== 'web';
|
||||||
|
|
||||||
|
const hasOpacityStyle = (style: any) => {
|
||||||
|
if (style) {
|
||||||
|
const flattenedStyle = StyleSheet.flatten(style);
|
||||||
|
return flattenedStyle.opacity != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
export default class Card extends React.Component<Props> {
|
export default class Card extends React.Component<Props> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
overlayEnabled: Platform.OS !== 'ios',
|
overlayEnabled: Platform.OS !== 'ios',
|
||||||
@@ -169,7 +178,7 @@ export default class Card extends React.Component<Props> {
|
|||||||
transitionSpec,
|
transitionSpec,
|
||||||
onOpen,
|
onOpen,
|
||||||
onClose,
|
onClose,
|
||||||
onTransitionStart,
|
onTransition,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const toValue = this.getAnimateToValue({
|
const toValue = this.getAnimateToValue({
|
||||||
@@ -189,7 +198,7 @@ export default class Card extends React.Component<Props> {
|
|||||||
|
|
||||||
clearTimeout(this.pendingGestureCallback);
|
clearTimeout(this.pendingGestureCallback);
|
||||||
|
|
||||||
onTransitionStart?.({ closing });
|
onTransition?.({ closing, gesture: velocity !== undefined });
|
||||||
animation(gesture, {
|
animation(gesture, {
|
||||||
...spec.config,
|
...spec.config,
|
||||||
velocity,
|
velocity,
|
||||||
@@ -533,6 +542,7 @@ export default class Card extends React.Component<Props> {
|
|||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
<Animated.View
|
<Animated.View
|
||||||
|
needsOffscreenAlphaCompositing={hasOpacityStyle(containerStyle)}
|
||||||
style={[styles.container, containerStyle, customContainerStyle]}
|
style={[styles.container, containerStyle, customContainerStyle]}
|
||||||
pointerEvents="box-none"
|
pointerEvents="box-none"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ type Props = TransitionPreset & {
|
|||||||
) => void;
|
) => void;
|
||||||
onTransitionEnd?: (props: { route: Route<string> }, closing: boolean) => void;
|
onTransitionEnd?: (props: { route: Route<string> }, closing: boolean) => void;
|
||||||
onPageChangeStart?: () => void;
|
onPageChangeStart?: () => void;
|
||||||
onPageChangeConfirm?: () => void;
|
onPageChangeConfirm?: (force: boolean) => void;
|
||||||
onPageChangeCancel?: () => void;
|
onPageChangeCancel?: () => void;
|
||||||
onGestureStart?: (props: { route: Route<string> }) => void;
|
onGestureStart?: (props: { route: Route<string> }) => void;
|
||||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||||
@@ -67,6 +67,7 @@ type Props = TransitionPreset & {
|
|||||||
route: Route<string>;
|
route: Route<string>;
|
||||||
height: number;
|
height: number;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
isParentHeaderShown: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const EPSILON = 0.1;
|
const EPSILON = 0.1;
|
||||||
@@ -94,6 +95,7 @@ function CardContainer({
|
|||||||
hasAbsoluteHeader,
|
hasAbsoluteHeader,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
onHeaderHeightChange,
|
onHeaderHeightChange,
|
||||||
|
isParentHeaderShown,
|
||||||
index,
|
index,
|
||||||
layout,
|
layout,
|
||||||
onCloseRoute,
|
onCloseRoute,
|
||||||
@@ -115,42 +117,58 @@ function CardContainer({
|
|||||||
scene,
|
scene,
|
||||||
transitionSpec,
|
transitionSpec,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
React.useEffect(() => {
|
|
||||||
onPageChangeConfirm?.();
|
|
||||||
}, [active, onPageChangeConfirm]);
|
|
||||||
|
|
||||||
const handleOpen = () => {
|
const handleOpen = () => {
|
||||||
onTransitionEnd?.({ route: scene.route }, false);
|
const { route } = scene;
|
||||||
onOpenRoute({ route: scene.route });
|
|
||||||
|
onTransitionEnd?.({ route }, false);
|
||||||
|
onOpenRoute({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onTransitionEnd?.({ route: scene.route }, true);
|
const { route } = scene;
|
||||||
onCloseRoute({ route: scene.route });
|
|
||||||
|
onTransitionEnd?.({ route }, true);
|
||||||
|
onCloseRoute({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGestureBegin = () => {
|
const handleGestureBegin = () => {
|
||||||
|
const { route } = scene;
|
||||||
|
|
||||||
onPageChangeStart?.();
|
onPageChangeStart?.();
|
||||||
onGestureStart?.({ route: scene.route });
|
onGestureStart?.({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGestureCanceled = () => {
|
const handleGestureCanceled = () => {
|
||||||
|
const { route } = scene;
|
||||||
|
|
||||||
onPageChangeCancel?.();
|
onPageChangeCancel?.();
|
||||||
onGestureCancel?.({ route: scene.route });
|
onGestureCancel?.({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGestureEnd = () => {
|
const handleGestureEnd = () => {
|
||||||
onGestureEnd?.({ route: scene.route });
|
const { route } = scene;
|
||||||
|
|
||||||
|
onGestureEnd?.({ route });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTransitionStart = ({ closing }: { closing: boolean }) => {
|
const handleTransition = ({
|
||||||
if (active && closing) {
|
closing,
|
||||||
onPageChangeConfirm?.();
|
gesture,
|
||||||
|
}: {
|
||||||
|
closing: boolean;
|
||||||
|
gesture: boolean;
|
||||||
|
}) => {
|
||||||
|
const { route } = scene;
|
||||||
|
|
||||||
|
if (!gesture) {
|
||||||
|
onPageChangeConfirm?.(true);
|
||||||
|
} else if (active && closing) {
|
||||||
|
onPageChangeConfirm?.(false);
|
||||||
} else {
|
} else {
|
||||||
onPageChangeCancel?.();
|
onPageChangeCancel?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
onTransitionStart?.({ route: scene.route }, closing);
|
onTransitionStart?.({ route }, closing);
|
||||||
};
|
};
|
||||||
|
|
||||||
const insets = {
|
const insets = {
|
||||||
@@ -182,7 +200,6 @@ function CardContainer({
|
|||||||
};
|
};
|
||||||
}, [pointerEvents, scene.progress.next]);
|
}, [pointerEvents, scene.progress.next]);
|
||||||
|
|
||||||
const isParentHeaderShown = React.useContext(HeaderShownContext);
|
|
||||||
const isCurrentHeaderShown = headerMode !== 'none' && headerShown !== false;
|
const isCurrentHeaderShown = headerMode !== 'none' && headerShown !== false;
|
||||||
const previousScene = getPreviousScene({ route: scene.route });
|
const previousScene = getPreviousScene({ route: scene.route });
|
||||||
|
|
||||||
@@ -201,7 +218,7 @@ function CardContainer({
|
|||||||
overlay={cardOverlay}
|
overlay={cardOverlay}
|
||||||
overlayEnabled={cardOverlayEnabled}
|
overlayEnabled={cardOverlayEnabled}
|
||||||
shadowEnabled={cardShadowEnabled}
|
shadowEnabled={cardShadowEnabled}
|
||||||
onTransitionStart={handleTransitionStart}
|
onTransition={handleTransition}
|
||||||
onGestureBegin={handleGestureBegin}
|
onGestureBegin={handleGestureBegin}
|
||||||
onGestureCanceled={handleGestureCanceled}
|
onGestureCanceled={handleGestureCanceled}
|
||||||
onGestureEnd={handleGestureEnd}
|
onGestureEnd={handleGestureEnd}
|
||||||
@@ -216,7 +233,14 @@ function CardContainer({
|
|||||||
pageOverflowEnabled={headerMode === 'screen' && mode === 'card'}
|
pageOverflowEnabled={headerMode === 'screen' && mode === 'card'}
|
||||||
containerStyle={hasAbsoluteHeader ? { marginTop: headerHeight } : null}
|
containerStyle={hasAbsoluteHeader ? { marginTop: headerHeight } : null}
|
||||||
contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
|
contentStyle={[{ backgroundColor: colors.background }, cardStyle]}
|
||||||
style={StyleSheet.absoluteFill}
|
style={[
|
||||||
|
{
|
||||||
|
// This is necessary to avoid unfocused larger pages increasing scroll area
|
||||||
|
// The issue can be seen on the web when a smaller screen is pushed over a larger one
|
||||||
|
overflow: active ? undefined : 'hidden',
|
||||||
|
},
|
||||||
|
StyleSheet.absoluteFill,
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.scene}>
|
<View style={styles.scene}>
|
||||||
|
|||||||
458
packages/stack/src/vendor/views/Stack/CardStack.tsx
vendored
458
packages/stack/src/vendor/views/Stack/CardStack.tsx
vendored
@@ -9,7 +9,11 @@ import {
|
|||||||
import type { EdgeInsets } from 'react-native-safe-area-context';
|
import type { EdgeInsets } from 'react-native-safe-area-context';
|
||||||
import type { NavigationState as StackNavigationState } from 'react-navigation';
|
import type { NavigationState as StackNavigationState } from 'react-navigation';
|
||||||
|
|
||||||
import { MaybeScreenContainer, MaybeScreen } from '../Screens';
|
import {
|
||||||
|
MaybeScreenContainer,
|
||||||
|
MaybeScreen,
|
||||||
|
shouldUseActivityState,
|
||||||
|
} from '../Screens';
|
||||||
import { getDefaultHeaderHeight } from '../Header/HeaderSegment';
|
import { getDefaultHeaderHeight } from '../Header/HeaderSegment';
|
||||||
import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
|
import type { Props as HeaderContainerProps } from '../Header/HeaderContainer';
|
||||||
import CardContainer from './CardContainer';
|
import CardContainer from './CardContainer';
|
||||||
@@ -19,7 +23,6 @@ import {
|
|||||||
} from '../../TransitionConfigs/TransitionPresets';
|
} from '../../TransitionConfigs/TransitionPresets';
|
||||||
import { forNoAnimation as forNoAnimationHeader } from '../../TransitionConfigs/HeaderStyleInterpolators';
|
import { forNoAnimation as forNoAnimationHeader } from '../../TransitionConfigs/HeaderStyleInterpolators';
|
||||||
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
|
import { forNoAnimation as forNoAnimationCard } from '../../TransitionConfigs/CardStyleInterpolators';
|
||||||
import HeaderShownContext from '../../utils/HeaderShownContext';
|
|
||||||
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
import getDistanceForDirection from '../../utils/getDistanceForDirection';
|
||||||
import type {
|
import type {
|
||||||
Layout,
|
Layout,
|
||||||
@@ -53,17 +56,19 @@ type Props = {
|
|||||||
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
renderHeader: (props: HeaderContainerProps) => React.ReactNode;
|
||||||
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
renderScene: (props: { route: Route<string> }) => React.ReactNode;
|
||||||
headerMode: StackHeaderMode;
|
headerMode: StackHeaderMode;
|
||||||
|
isParentHeaderShown: boolean;
|
||||||
onTransitionStart: (
|
onTransitionStart: (
|
||||||
props: { route: Route<string> },
|
props: { route: Route<string> },
|
||||||
closing: boolean
|
closing: boolean
|
||||||
) => void;
|
) => void;
|
||||||
onTransitionEnd: (props: { route: Route<string> }, closing: boolean) => void;
|
onTransitionEnd: (props: { route: Route<string> }, closing: boolean) => void;
|
||||||
onPageChangeStart?: () => void;
|
onPageChangeStart?: () => void;
|
||||||
onPageChangeConfirm?: () => void;
|
onPageChangeConfirm?: (force: boolean) => void;
|
||||||
onPageChangeCancel?: () => void;
|
onPageChangeCancel?: () => void;
|
||||||
onGestureStart?: (props: { route: Route<string> }) => void;
|
onGestureStart?: (props: { route: Route<string> }) => void;
|
||||||
onGestureEnd?: (props: { route: Route<string> }) => void;
|
onGestureEnd?: (props: { route: Route<string> }) => void;
|
||||||
onGestureCancel?: (props: { route: Route<string> }) => void;
|
onGestureCancel?: (props: { route: Route<string> }) => void;
|
||||||
|
detachInactiveScreens?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -77,11 +82,16 @@ type State = {
|
|||||||
|
|
||||||
const EPSILON = 0.01;
|
const EPSILON = 0.01;
|
||||||
|
|
||||||
|
const STATE_INACTIVE = 0;
|
||||||
|
const STATE_TRANSITIONING_OR_BELOW_TOP = 1;
|
||||||
|
const STATE_ON_TOP = 2;
|
||||||
|
|
||||||
const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
|
const FALLBACK_DESCRIPTOR = Object.freeze({ options: {} });
|
||||||
|
|
||||||
const getHeaderHeights = (
|
const getHeaderHeights = (
|
||||||
routes: Route<string>[],
|
routes: Route<string>[],
|
||||||
insets: EdgeInsets,
|
insets: EdgeInsets,
|
||||||
|
isParentHeaderShown: boolean,
|
||||||
descriptors: StackDescriptorMap,
|
descriptors: StackDescriptorMap,
|
||||||
layout: Layout,
|
layout: Layout,
|
||||||
previous: Record<string, number>
|
previous: Record<string, number>
|
||||||
@@ -98,7 +108,9 @@ const getHeaderHeights = (
|
|||||||
...options.safeAreaInsets,
|
...options.safeAreaInsets,
|
||||||
};
|
};
|
||||||
|
|
||||||
const { headerStatusBarHeight = safeAreaInsets.top } = options;
|
const {
|
||||||
|
headerStatusBarHeight = isParentHeaderShown ? 0 : safeAreaInsets.top,
|
||||||
|
} = options;
|
||||||
|
|
||||||
acc[curr.key] =
|
acc[curr.key] =
|
||||||
typeof height === 'number'
|
typeof height === 'number'
|
||||||
@@ -261,6 +273,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
headerHeights: getHeaderHeights(
|
headerHeights: getHeaderHeights(
|
||||||
props.routes,
|
props.routes,
|
||||||
props.insets,
|
props.insets,
|
||||||
|
props.isParentHeaderShown,
|
||||||
state.descriptors,
|
state.descriptors,
|
||||||
state.layout,
|
state.layout,
|
||||||
state.headerHeights
|
state.headerHeights
|
||||||
@@ -303,6 +316,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
headerHeights: getHeaderHeights(
|
headerHeights: getHeaderHeights(
|
||||||
props.routes,
|
props.routes,
|
||||||
props.insets,
|
props.insets,
|
||||||
|
props.isParentHeaderShown,
|
||||||
state.descriptors,
|
state.descriptors,
|
||||||
layout,
|
layout,
|
||||||
state.headerHeights
|
state.headerHeights
|
||||||
@@ -371,6 +385,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
renderHeader,
|
renderHeader,
|
||||||
renderScene,
|
renderScene,
|
||||||
headerMode,
|
headerMode,
|
||||||
|
isParentHeaderShown,
|
||||||
onTransitionStart,
|
onTransitionStart,
|
||||||
onTransitionEnd,
|
onTransitionEnd,
|
||||||
onPageChangeStart,
|
onPageChangeStart,
|
||||||
@@ -379,6 +394,9 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
onGestureStart,
|
onGestureStart,
|
||||||
onGestureEnd,
|
onGestureEnd,
|
||||||
onGestureCancel,
|
onGestureCancel,
|
||||||
|
// Enable on new versions of `react-native-screens`
|
||||||
|
// On older versions of `react-native-screens`, there's an issue with screens not being responsive to user interaction.
|
||||||
|
detachInactiveScreens = Platform.OS === 'web' || shouldUseActivityState,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { scenes, layout, gestures, headerHeights } = this.state;
|
const { scenes, layout, gestures, headerHeights } = this.state;
|
||||||
@@ -386,6 +404,7 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
const focusedRoute = state.routes[state.index];
|
const focusedRoute = state.routes[state.index];
|
||||||
const focusedDescriptor = descriptors[focusedRoute.key];
|
const focusedDescriptor = descriptors[focusedRoute.key];
|
||||||
const focusedOptions = focusedDescriptor ? focusedDescriptor.options : {};
|
const focusedOptions = focusedDescriptor ? focusedDescriptor.options : {};
|
||||||
|
const focusedHeaderHeight = headerHeights[focusedRoute.key];
|
||||||
|
|
||||||
let defaultTransitionPreset =
|
let defaultTransitionPreset =
|
||||||
mode === 'modal' ? ModalTransition : DefaultTransition;
|
mode === 'modal' ? ModalTransition : DefaultTransition;
|
||||||
@@ -404,212 +423,247 @@ export default class CardStack extends React.Component<Props, State> {
|
|||||||
left = insets.left,
|
left = insets.left,
|
||||||
} = focusedOptions.safeAreaInsets || {};
|
} = focusedOptions.safeAreaInsets || {};
|
||||||
|
|
||||||
// Screens is buggy on iOS and web, so we only enable it on Android
|
let activeScreensLimit = 1;
|
||||||
// For modals, usually we want the screen underneath to be visible, so also disable it there
|
|
||||||
const isScreensEnabled = Platform.OS !== 'ios' && mode !== 'modal';
|
for (let i = scenes.length - 1; i >= 0; i--) {
|
||||||
|
const {
|
||||||
|
// By default, we don't want to detach the previous screen of the active one for modals
|
||||||
|
detachPreviousScreen = mode === 'modal'
|
||||||
|
? i !== scenes.length - 1
|
||||||
|
: true,
|
||||||
|
} = scenes[i].descriptor.options;
|
||||||
|
|
||||||
|
if (detachPreviousScreen === false) {
|
||||||
|
activeScreensLimit++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFloatHeaderAbsolute =
|
||||||
|
headerMode === 'float'
|
||||||
|
? this.state.scenes.slice(-2).some((scene) => {
|
||||||
|
const { descriptor } = scene;
|
||||||
|
const options = descriptor ? descriptor.options : {};
|
||||||
|
const { headerTransparent, headerShown = true } = options;
|
||||||
|
|
||||||
|
if (headerTransparent || headerShown === false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
: false;
|
||||||
|
|
||||||
|
const floatingHeader =
|
||||||
|
headerMode === 'float' ? (
|
||||||
|
<React.Fragment key="header">
|
||||||
|
{renderHeader({
|
||||||
|
mode: 'float',
|
||||||
|
layout,
|
||||||
|
insets: { top, right, bottom, left },
|
||||||
|
scenes,
|
||||||
|
getPreviousScene: this.getPreviousScene,
|
||||||
|
getFocusedRoute: this.getFocusedRoute,
|
||||||
|
onContentHeightChange: this.handleHeaderLayout,
|
||||||
|
gestureDirection:
|
||||||
|
focusedOptions.gestureDirection !== undefined
|
||||||
|
? focusedOptions.gestureDirection
|
||||||
|
: defaultTransitionPreset.gestureDirection,
|
||||||
|
styleInterpolator:
|
||||||
|
focusedOptions.headerStyleInterpolator !== undefined
|
||||||
|
? focusedOptions.headerStyleInterpolator
|
||||||
|
: defaultTransitionPreset.headerStyleInterpolator,
|
||||||
|
style: [
|
||||||
|
styles.floating,
|
||||||
|
isFloatHeaderAbsolute && [
|
||||||
|
// Without this, the header buttons won't be touchable on Android when headerTransparent: true
|
||||||
|
{ height: focusedHeaderHeight },
|
||||||
|
styles.absolute,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
})}
|
||||||
|
</React.Fragment>
|
||||||
|
) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HeaderShownContext.Consumer>
|
<React.Fragment>
|
||||||
{(isParentHeaderShown) => {
|
{isFloatHeaderAbsolute ? null : floatingHeader}
|
||||||
const isFloatHeaderAbsolute =
|
<MaybeScreenContainer
|
||||||
headerMode === 'float'
|
enabled={detachInactiveScreens}
|
||||||
? this.state.scenes.slice(-2).some((scene) => {
|
style={styles.container}
|
||||||
const { descriptor } = scene;
|
onLayout={this.handleLayout}
|
||||||
const options = descriptor ? descriptor.options : {};
|
>
|
||||||
const {
|
{routes.map((route, index, self) => {
|
||||||
headerTransparent,
|
const focused = focusedRoute.key === route.key;
|
||||||
headerShown = isParentHeaderShown === false,
|
const gesture = gestures[route.key];
|
||||||
} = options;
|
const scene = scenes[index];
|
||||||
|
|
||||||
if (headerTransparent || headerShown === false) {
|
// For the screens that shouldn't be active, the value is 0
|
||||||
return true;
|
// For those that should be active, but are not the top screen, the value is 1
|
||||||
}
|
// For those on top of the stack and with interaction enabled, the value is 2
|
||||||
|
// For the old implementation, it stays the same it was
|
||||||
|
let isScreenActive: Animated.AnimatedInterpolation | 2 | 1 | 0 = 1;
|
||||||
|
|
||||||
return false;
|
if (shouldUseActivityState || Platform.OS === 'web') {
|
||||||
})
|
if (index < self.length - activeScreensLimit - 1) {
|
||||||
: false;
|
// screen should be inactive because it is too deep in the stack
|
||||||
|
isScreenActive = STATE_INACTIVE;
|
||||||
|
} else {
|
||||||
|
const sceneForActivity = scenes[self.length - 1];
|
||||||
|
const outputValue =
|
||||||
|
index === self.length - 1
|
||||||
|
? STATE_ON_TOP // the screen is on top after the transition
|
||||||
|
: index >= self.length - activeScreensLimit
|
||||||
|
? STATE_TRANSITIONING_OR_BELOW_TOP // the screen should stay active after the transition, it is not on top but is in activeLimit
|
||||||
|
: STATE_INACTIVE; // the screen should be active only during the transition, it is at the edge of activeLimit
|
||||||
|
isScreenActive = sceneForActivity
|
||||||
|
? sceneForActivity.progress.current.interpolate({
|
||||||
|
inputRange: [0, 1 - EPSILON, 1],
|
||||||
|
outputRange: [1, 1, outputValue],
|
||||||
|
extrapolate: 'clamp',
|
||||||
|
})
|
||||||
|
: STATE_TRANSITIONING_OR_BELOW_TOP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isScreenActive = scene.progress.next
|
||||||
|
? scene.progress.next.interpolate({
|
||||||
|
inputRange: [0, 1 - EPSILON, 1],
|
||||||
|
outputRange: [1, 1, 0],
|
||||||
|
extrapolate: 'clamp',
|
||||||
|
})
|
||||||
|
: 1;
|
||||||
|
}
|
||||||
|
|
||||||
const floatingHeader =
|
const {
|
||||||
headerMode === 'float' ? (
|
safeAreaInsets,
|
||||||
<React.Fragment key="header">
|
headerShown = true,
|
||||||
{renderHeader({
|
headerTransparent,
|
||||||
mode: 'float',
|
cardShadowEnabled,
|
||||||
layout,
|
cardOverlayEnabled,
|
||||||
insets: { top, right, bottom, left },
|
cardOverlay,
|
||||||
scenes,
|
cardStyle,
|
||||||
getPreviousScene: this.getPreviousScene,
|
animationEnabled,
|
||||||
getFocusedRoute: this.getFocusedRoute,
|
gestureResponseDistance,
|
||||||
onContentHeightChange: this.handleHeaderLayout,
|
gestureVelocityImpact,
|
||||||
gestureDirection:
|
gestureDirection = defaultTransitionPreset.gestureDirection,
|
||||||
focusedOptions.gestureDirection !== undefined
|
transitionSpec = defaultTransitionPreset.transitionSpec,
|
||||||
? focusedOptions.gestureDirection
|
cardStyleInterpolator = animationEnabled === false
|
||||||
: defaultTransitionPreset.gestureDirection,
|
? forNoAnimationCard
|
||||||
styleInterpolator:
|
: defaultTransitionPreset.cardStyleInterpolator,
|
||||||
focusedOptions.headerStyleInterpolator !== undefined
|
headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
|
||||||
? focusedOptions.headerStyleInterpolator
|
} = scene.descriptor
|
||||||
: defaultTransitionPreset.headerStyleInterpolator,
|
? scene.descriptor.options
|
||||||
style: [
|
: ({} as StackNavigationOptions);
|
||||||
styles.floating,
|
|
||||||
isFloatHeaderAbsolute && styles.absolute,
|
|
||||||
],
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
) : null;
|
|
||||||
|
|
||||||
return (
|
let transitionConfig = {
|
||||||
<React.Fragment>
|
gestureDirection,
|
||||||
{isFloatHeaderAbsolute ? null : floatingHeader}
|
transitionSpec,
|
||||||
<MaybeScreenContainer
|
cardStyleInterpolator,
|
||||||
enabled={isScreensEnabled}
|
headerStyleInterpolator,
|
||||||
style={styles.container}
|
};
|
||||||
onLayout={this.handleLayout}
|
|
||||||
|
// When a screen is not the last, it should use next screen's transition config
|
||||||
|
// Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
|
||||||
|
// For example combining a slide and a modal transition would look wrong otherwise
|
||||||
|
// With this approach, combining different transition styles in the same navigator mostly looks right
|
||||||
|
// This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
|
||||||
|
// but majority of the transitions look alright
|
||||||
|
if (index !== self.length - 1) {
|
||||||
|
const nextScene = scenes[index + 1];
|
||||||
|
|
||||||
|
if (nextScene) {
|
||||||
|
const {
|
||||||
|
animationEnabled,
|
||||||
|
gestureDirection = defaultTransitionPreset.gestureDirection,
|
||||||
|
transitionSpec = defaultTransitionPreset.transitionSpec,
|
||||||
|
cardStyleInterpolator = animationEnabled === false
|
||||||
|
? forNoAnimationCard
|
||||||
|
: defaultTransitionPreset.cardStyleInterpolator,
|
||||||
|
headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
|
||||||
|
} = nextScene.descriptor
|
||||||
|
? nextScene.descriptor.options
|
||||||
|
: ({} as StackNavigationOptions);
|
||||||
|
|
||||||
|
transitionConfig = {
|
||||||
|
gestureDirection,
|
||||||
|
transitionSpec,
|
||||||
|
cardStyleInterpolator,
|
||||||
|
headerStyleInterpolator,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
top: safeAreaInsetTop = insets.top,
|
||||||
|
right: safeAreaInsetRight = insets.right,
|
||||||
|
bottom: safeAreaInsetBottom = insets.bottom,
|
||||||
|
left: safeAreaInsetLeft = insets.left,
|
||||||
|
} = safeAreaInsets || {};
|
||||||
|
|
||||||
|
const headerHeight =
|
||||||
|
headerMode !== 'none' && headerShown !== false
|
||||||
|
? headerHeights[route.key]
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MaybeScreen
|
||||||
|
key={route.key}
|
||||||
|
style={StyleSheet.absoluteFill}
|
||||||
|
enabled={detachInactiveScreens}
|
||||||
|
active={isScreenActive}
|
||||||
|
pointerEvents="box-none"
|
||||||
>
|
>
|
||||||
{routes.map((route, index, self) => {
|
<CardContainer
|
||||||
const focused = focusedRoute.key === route.key;
|
index={index}
|
||||||
const gesture = gestures[route.key];
|
active={index === self.length - 1}
|
||||||
const scene = scenes[index];
|
focused={focused}
|
||||||
|
closing={closingRouteKeys.includes(route.key)}
|
||||||
const isScreenActive = scene.progress.next
|
layout={layout}
|
||||||
? scene.progress.next.interpolate({
|
gesture={gesture}
|
||||||
inputRange: [0, 1 - EPSILON, 1],
|
scene={scene}
|
||||||
outputRange: [1, 1, 0],
|
safeAreaInsetTop={safeAreaInsetTop}
|
||||||
extrapolate: 'clamp',
|
safeAreaInsetRight={safeAreaInsetRight}
|
||||||
})
|
safeAreaInsetBottom={safeAreaInsetBottom}
|
||||||
: 1;
|
safeAreaInsetLeft={safeAreaInsetLeft}
|
||||||
|
cardOverlay={cardOverlay}
|
||||||
const {
|
cardOverlayEnabled={cardOverlayEnabled}
|
||||||
safeAreaInsets,
|
cardShadowEnabled={cardShadowEnabled}
|
||||||
headerShown = isParentHeaderShown === false,
|
cardStyle={cardStyle}
|
||||||
headerTransparent,
|
onPageChangeStart={onPageChangeStart}
|
||||||
cardShadowEnabled,
|
onPageChangeConfirm={onPageChangeConfirm}
|
||||||
cardOverlayEnabled,
|
onPageChangeCancel={onPageChangeCancel}
|
||||||
cardOverlay,
|
onGestureStart={onGestureStart}
|
||||||
cardStyle,
|
onGestureCancel={onGestureCancel}
|
||||||
animationEnabled,
|
onGestureEnd={onGestureEnd}
|
||||||
gestureResponseDistance,
|
gestureResponseDistance={gestureResponseDistance}
|
||||||
gestureVelocityImpact,
|
headerHeight={headerHeight}
|
||||||
gestureDirection = defaultTransitionPreset.gestureDirection,
|
isParentHeaderShown={isParentHeaderShown}
|
||||||
transitionSpec = defaultTransitionPreset.transitionSpec,
|
onHeaderHeightChange={this.handleHeaderLayout}
|
||||||
cardStyleInterpolator = animationEnabled === false
|
getPreviousScene={this.getPreviousScene}
|
||||||
? forNoAnimationCard
|
getFocusedRoute={this.getFocusedRoute}
|
||||||
: defaultTransitionPreset.cardStyleInterpolator,
|
mode={mode}
|
||||||
headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
|
headerMode={headerMode}
|
||||||
} = scene.descriptor
|
headerShown={headerShown}
|
||||||
? scene.descriptor.options
|
hasAbsoluteHeader={
|
||||||
: ({} as StackNavigationOptions);
|
isFloatHeaderAbsolute && !headerTransparent
|
||||||
|
|
||||||
let transitionConfig = {
|
|
||||||
gestureDirection,
|
|
||||||
transitionSpec,
|
|
||||||
cardStyleInterpolator,
|
|
||||||
headerStyleInterpolator,
|
|
||||||
};
|
|
||||||
|
|
||||||
// When a screen is not the last, it should use next screen's transition config
|
|
||||||
// Many transitions also animate the previous screen, so using 2 different transitions doesn't look right
|
|
||||||
// For example combining a slide and a modal transition would look wrong otherwise
|
|
||||||
// With this approach, combining different transition styles in the same navigator mostly looks right
|
|
||||||
// This will still be broken when 2 transitions have different idle state (e.g. modal presentation),
|
|
||||||
// but majority of the transitions look alright
|
|
||||||
if (index !== self.length - 1) {
|
|
||||||
const nextScene = scenes[index + 1];
|
|
||||||
|
|
||||||
if (nextScene) {
|
|
||||||
const {
|
|
||||||
animationEnabled,
|
|
||||||
gestureDirection = defaultTransitionPreset.gestureDirection,
|
|
||||||
transitionSpec = defaultTransitionPreset.transitionSpec,
|
|
||||||
cardStyleInterpolator = animationEnabled === false
|
|
||||||
? forNoAnimationCard
|
|
||||||
: defaultTransitionPreset.cardStyleInterpolator,
|
|
||||||
headerStyleInterpolator = defaultTransitionPreset.headerStyleInterpolator,
|
|
||||||
} = nextScene.descriptor
|
|
||||||
? nextScene.descriptor.options
|
|
||||||
: ({} as StackNavigationOptions);
|
|
||||||
|
|
||||||
transitionConfig = {
|
|
||||||
gestureDirection,
|
|
||||||
transitionSpec,
|
|
||||||
cardStyleInterpolator,
|
|
||||||
headerStyleInterpolator,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
renderHeader={renderHeader}
|
||||||
const {
|
renderScene={renderScene}
|
||||||
top: safeAreaInsetTop = insets.top,
|
onOpenRoute={onOpenRoute}
|
||||||
right: safeAreaInsetRight = insets.right,
|
onCloseRoute={onCloseRoute}
|
||||||
bottom: safeAreaInsetBottom = insets.bottom,
|
onTransitionStart={onTransitionStart}
|
||||||
left: safeAreaInsetLeft = insets.left,
|
onTransitionEnd={onTransitionEnd}
|
||||||
} = safeAreaInsets || {};
|
gestureEnabled={index !== 0 && getGesturesEnabled({ route })}
|
||||||
|
gestureVelocityImpact={gestureVelocityImpact}
|
||||||
const headerHeight =
|
{...transitionConfig}
|
||||||
headerMode !== 'none' && headerShown !== false
|
/>
|
||||||
? headerHeights[route.key]
|
</MaybeScreen>
|
||||||
: 0;
|
);
|
||||||
|
})}
|
||||||
return (
|
</MaybeScreenContainer>
|
||||||
<MaybeScreen
|
{isFloatHeaderAbsolute ? floatingHeader : null}
|
||||||
key={route.key}
|
</React.Fragment>
|
||||||
style={StyleSheet.absoluteFill}
|
|
||||||
enabled={isScreensEnabled}
|
|
||||||
active={isScreenActive}
|
|
||||||
pointerEvents="box-none"
|
|
||||||
>
|
|
||||||
<CardContainer
|
|
||||||
index={index}
|
|
||||||
active={index === self.length - 1}
|
|
||||||
focused={focused}
|
|
||||||
closing={closingRouteKeys.includes(route.key)}
|
|
||||||
layout={layout}
|
|
||||||
gesture={gesture}
|
|
||||||
scene={scene}
|
|
||||||
safeAreaInsetTop={safeAreaInsetTop}
|
|
||||||
safeAreaInsetRight={safeAreaInsetRight}
|
|
||||||
safeAreaInsetBottom={safeAreaInsetBottom}
|
|
||||||
safeAreaInsetLeft={safeAreaInsetLeft}
|
|
||||||
cardOverlay={cardOverlay}
|
|
||||||
cardOverlayEnabled={cardOverlayEnabled}
|
|
||||||
cardShadowEnabled={cardShadowEnabled}
|
|
||||||
cardStyle={cardStyle}
|
|
||||||
onPageChangeStart={onPageChangeStart}
|
|
||||||
onPageChangeConfirm={onPageChangeConfirm}
|
|
||||||
onPageChangeCancel={onPageChangeCancel}
|
|
||||||
onGestureStart={onGestureStart}
|
|
||||||
onGestureCancel={onGestureCancel}
|
|
||||||
onGestureEnd={onGestureEnd}
|
|
||||||
gestureResponseDistance={gestureResponseDistance}
|
|
||||||
headerHeight={headerHeight}
|
|
||||||
onHeaderHeightChange={this.handleHeaderLayout}
|
|
||||||
getPreviousScene={this.getPreviousScene}
|
|
||||||
getFocusedRoute={this.getFocusedRoute}
|
|
||||||
mode={mode}
|
|
||||||
headerMode={headerMode}
|
|
||||||
headerShown={headerShown}
|
|
||||||
hasAbsoluteHeader={
|
|
||||||
isFloatHeaderAbsolute && !headerTransparent
|
|
||||||
}
|
|
||||||
renderHeader={renderHeader}
|
|
||||||
renderScene={renderScene}
|
|
||||||
onOpenRoute={onOpenRoute}
|
|
||||||
onCloseRoute={onCloseRoute}
|
|
||||||
onTransitionStart={onTransitionStart}
|
|
||||||
onTransitionEnd={onTransitionEnd}
|
|
||||||
gestureEnabled={
|
|
||||||
index !== 0 && getGesturesEnabled({ route })
|
|
||||||
}
|
|
||||||
gestureVelocityImpact={gestureVelocityImpact}
|
|
||||||
{...transitionConfig}
|
|
||||||
/>
|
|
||||||
</MaybeScreen>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</MaybeScreenContainer>
|
|
||||||
{isFloatHeaderAbsolute ? floatingHeader : null}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</HeaderShownContext.Consumer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import type {
|
|||||||
StackNavigationConfig,
|
StackNavigationConfig,
|
||||||
StackDescriptorMap,
|
StackDescriptorMap,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
import HeaderShownContext from '../../utils/HeaderShownContext';
|
||||||
|
|
||||||
type Props = StackNavigationConfig & {
|
type Props = StackNavigationConfig & {
|
||||||
state: StackNavigationState;
|
state: StackNavigationState;
|
||||||
@@ -430,7 +431,7 @@ export default class StackView extends React.Component<Props, State> {
|
|||||||
const descriptor =
|
const descriptor =
|
||||||
descriptors[route.key] || this.state.descriptors[route.key];
|
descriptors[route.key] || this.state.descriptors[route.key];
|
||||||
|
|
||||||
descriptor?.options.onTransitionEnd?.({ closing });
|
descriptor?.options.onTransitionStart?.({ closing });
|
||||||
};
|
};
|
||||||
|
|
||||||
private handleGestureStart = () => {
|
private handleGestureStart = () => {
|
||||||
@@ -475,29 +476,34 @@ export default class StackView extends React.Component<Props, State> {
|
|||||||
{(insets) => (
|
{(insets) => (
|
||||||
<KeyboardManager enabled={keyboardHandlingEnabled !== false}>
|
<KeyboardManager enabled={keyboardHandlingEnabled !== false}>
|
||||||
{(props) => (
|
{(props) => (
|
||||||
<CardStack
|
<HeaderShownContext.Consumer>
|
||||||
mode={mode}
|
{(isParentHeaderShown) => (
|
||||||
insets={insets as EdgeInsets}
|
<CardStack
|
||||||
getPreviousRoute={this.getPreviousRoute}
|
mode={mode}
|
||||||
getGesturesEnabled={this.getGesturesEnabled}
|
insets={insets as EdgeInsets}
|
||||||
routes={routes}
|
isParentHeaderShown={isParentHeaderShown}
|
||||||
openingRouteKeys={openingRouteKeys}
|
getPreviousRoute={this.getPreviousRoute}
|
||||||
closingRouteKeys={closingRouteKeys}
|
getGesturesEnabled={this.getGesturesEnabled}
|
||||||
onOpenRoute={this.handleOpenRoute}
|
routes={routes}
|
||||||
onCloseRoute={this.handleCloseRoute}
|
openingRouteKeys={openingRouteKeys}
|
||||||
onTransitionStart={this.handleTransitionStart}
|
closingRouteKeys={closingRouteKeys}
|
||||||
onTransitionEnd={this.handleTransitionEnd}
|
onOpenRoute={this.handleOpenRoute}
|
||||||
renderHeader={this.renderHeader}
|
onCloseRoute={this.handleCloseRoute}
|
||||||
renderScene={this.renderScene}
|
onTransitionStart={this.handleTransitionStart}
|
||||||
headerMode={headerMode}
|
onTransitionEnd={this.handleTransitionEnd}
|
||||||
state={state}
|
renderHeader={this.renderHeader}
|
||||||
descriptors={descriptors}
|
renderScene={this.renderScene}
|
||||||
onGestureStart={this.handleGestureStart}
|
headerMode={headerMode}
|
||||||
onGestureEnd={this.handleGestureEnd}
|
state={state}
|
||||||
onGestureCancel={this.handleGestureCancel}
|
descriptors={descriptors}
|
||||||
{...rest}
|
onGestureStart={this.handleGestureStart}
|
||||||
{...props}
|
onGestureEnd={this.handleGestureEnd}
|
||||||
/>
|
onGestureCancel={this.handleGestureCancel}
|
||||||
|
{...rest}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</HeaderShownContext.Consumer>
|
||||||
)}
|
)}
|
||||||
</KeyboardManager>
|
</KeyboardManager>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { BaseButton } from 'react-native-gesture-handler';
|
|||||||
const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);
|
const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);
|
||||||
|
|
||||||
type Props = React.ComponentProps<typeof BaseButton> & {
|
type Props = React.ComponentProps<typeof BaseButton> & {
|
||||||
activeOpacity: number;
|
pressOpacity: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useNativeDriver = Platform.OS !== 'web';
|
const useNativeDriver = Platform.OS !== 'web';
|
||||||
@@ -27,7 +27,7 @@ export default class TouchableItem extends React.Component<Props> {
|
|||||||
overshootClamping: true,
|
overshootClamping: true,
|
||||||
restDisplacementThreshold: 0.01,
|
restDisplacementThreshold: 0.01,
|
||||||
restSpeedThreshold: 0.01,
|
restSpeedThreshold: 0.01,
|
||||||
toValue: active ? this.props.activeOpacity : 1,
|
toValue: active ? this.props.pressOpacity : 1,
|
||||||
useNativeDriver,
|
useNativeDriver,
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,44 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [2.11.0](https://github.com/react-navigation/tabs/compare/react-navigation-tabs@2.10.1...react-navigation-tabs@2.11.0) (2021-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add activityState to other navigators ([5c7f892](https://github.com/react-navigation/tabs/commit/5c7f892d77298f5c89534fa78a1a6a59c7f35a60))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2.10.1](https://github.com/react-navigation/tabs/compare/react-navigation-tabs@2.10.0...react-navigation-tabs@2.10.1) (2020-10-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add bottom insets to custom height for bottom tabs ([ffe3bdd](https://github.com/react-navigation/tabs/commit/ffe3bddcb27ecb3d663b13b433263d18f792ad4d))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [2.10.0](https://github.com/react-navigation/tabs/compare/react-navigation-tabs@2.9.2...react-navigation-tabs@2.10.0) (2020-10-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use react-native-iphone-x-helper in bottom-tabs navigator ([ebe70f5](https://github.com/react-navigation/tabs/commit/ebe70f51fbb8d892be9c44b0c226947684c24338))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add detachInactiveScreens prop for bottom tabs and drawer ([#8816](https://github.com/react-navigation/tabs/issues/8816)) ([707bea3](https://github.com/react-navigation/tabs/commit/707bea3cba1aa1f7b1eb5884dd1d129dcc2bbdc2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2.9.2](https://github.com/react-navigation/tabs/compare/react-navigation-tabs@2.9.1...react-navigation-tabs@2.9.2) (2020-10-02)
|
## [2.9.2](https://github.com/react-navigation/tabs/compare/react-navigation-tabs@2.9.1...react-navigation-tabs@2.9.2) (2020-10-02)
|
||||||
|
|
||||||
**Note:** Version bump only for package react-navigation-tabs
|
**Note:** Version bump only for package react-navigation-tabs
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "react-navigation-tabs",
|
"name": "react-navigation-tabs",
|
||||||
"version": "2.9.2",
|
"version": "2.11.0",
|
||||||
"description": "Tab Navigation components for React Navigation",
|
"description": "Tab Navigation components for React Navigation",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
"module": "lib/module/index.js",
|
"module": "lib/module/index.js",
|
||||||
@@ -42,21 +42,21 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
"react-lifecycles-compat": "^3.0.4",
|
"react-lifecycles-compat": "^3.0.4",
|
||||||
"react-native-safe-area-view": "^0.14.9",
|
"react-native-iphone-x-helper": "^1.3.0",
|
||||||
"react-native-tab-view": "^2.15.1"
|
"react-native-tab-view": "^2.15.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.16.2",
|
"@react-native-community/bob": "^0.16.2",
|
||||||
"@types/hoist-non-react-statics": "^3.3.1",
|
"@types/hoist-non-react-statics": "^3.3.1",
|
||||||
"@types/react": "^16.9.44",
|
"@types/react": "^16.9.53",
|
||||||
"@types/react-native": "^0.63.4",
|
"@types/react-native": "^0.63.30",
|
||||||
"del-cli": "^3.0.1",
|
"del-cli": "^3.0.1",
|
||||||
"react": "~16.13.1",
|
"react": "~16.13.1",
|
||||||
"react-native": "~0.63.2",
|
"react-native": "~0.63.2",
|
||||||
"react-native-gesture-handler": "~1.7.0",
|
"react-native-gesture-handler": "~1.7.0",
|
||||||
"react-native-reanimated": "~1.13.0",
|
"react-native-reanimated": "~1.13.0",
|
||||||
"react-native-tab-view": "^2.13.0",
|
"react-native-tab-view": "^2.13.0",
|
||||||
"react-navigation": "^4.4.2",
|
"react-navigation": "^4.4.4",
|
||||||
"typescript": "^4.0.3"
|
"typescript": "^4.0.3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ type Config = {
|
|||||||
lazy?: boolean;
|
lazy?: boolean;
|
||||||
tabBarComponent?: React.ComponentType<any>;
|
tabBarComponent?: React.ComponentType<any>;
|
||||||
tabBarOptions?: BottomTabBarOptions;
|
tabBarOptions?: BottomTabBarOptions;
|
||||||
|
detachInactiveScreens?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = NavigationViewProps &
|
type Props = NavigationViewProps &
|
||||||
@@ -131,13 +132,19 @@ class TabNavigationView extends React.PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { navigation, renderScene, lazy } = this.props;
|
const {
|
||||||
|
navigation,
|
||||||
|
renderScene,
|
||||||
|
lazy,
|
||||||
|
detachInactiveScreens = true,
|
||||||
|
} = this.props;
|
||||||
const { routes } = navigation.state;
|
const { routes } = navigation.state;
|
||||||
const { loaded } = this.state;
|
const { loaded } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<ScreenContainer style={styles.pages}>
|
{/* @ts-ignore */}
|
||||||
|
<ScreenContainer enabled={detachInactiveScreens} style={styles.pages}>
|
||||||
{routes.map((route, index) => {
|
{routes.map((route, index) => {
|
||||||
if (lazy && !loaded.includes(index)) {
|
if (lazy && !loaded.includes(index)) {
|
||||||
// Don't render a screen if we've never navigated to it
|
// Don't render a screen if we've never navigated to it
|
||||||
@@ -151,6 +158,7 @@ class TabNavigationView extends React.PureComponent<Props, State> {
|
|||||||
key={route.key}
|
key={route.key}
|
||||||
style={StyleSheet.absoluteFill}
|
style={StyleSheet.absoluteFill}
|
||||||
isVisible={isFocused}
|
isVisible={isFocused}
|
||||||
|
enabled={detachInactiveScreens}
|
||||||
>
|
>
|
||||||
{renderScene({ route })}
|
{renderScene({ route })}
|
||||||
</ResourceSavingScene>
|
</ResourceSavingScene>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
TextStyle,
|
TextStyle,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import SafeAreaView from 'react-native-safe-area-view';
|
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
import {
|
import {
|
||||||
NavigationRoute,
|
NavigationRoute,
|
||||||
@@ -94,7 +93,12 @@ export type BottomTabBarOptions = {
|
|||||||
| LabelPosition
|
| LabelPosition
|
||||||
| ((options: { deviceOrientation: Orientation }) => LabelPosition);
|
| ((options: { deviceOrientation: Orientation }) => LabelPosition);
|
||||||
adaptive?: boolean;
|
adaptive?: boolean;
|
||||||
safeAreaInset?: React.ComponentProps<typeof SafeAreaView>['forceInset'];
|
safeAreaInset?: {
|
||||||
|
top?: 'always' | 'never' | number;
|
||||||
|
right?: 'always' | 'never' | number;
|
||||||
|
bottom?: 'always' | 'never' | number;
|
||||||
|
left?: 'always' | 'never' | number;
|
||||||
|
};
|
||||||
style?: StyleProp<ViewStyle>;
|
style?: StyleProp<ViewStyle>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,6 +153,7 @@ export type BottomTabBarProps = BottomTabBarOptions & {
|
|||||||
isLandscape: boolean;
|
isLandscape: boolean;
|
||||||
jumpTo: (key: string) => void;
|
jumpTo: (key: string) => void;
|
||||||
screenProps: unknown;
|
screenProps: unknown;
|
||||||
|
detachInactiveScreens?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MaterialTabBarOptions = {
|
export type MaterialTabBarOptions = {
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import {
|
|||||||
Platform,
|
Platform,
|
||||||
LayoutChangeEvent,
|
LayoutChangeEvent,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import SafeAreaView from 'react-native-safe-area-view';
|
import {
|
||||||
|
getStatusBarHeight,
|
||||||
|
getBottomSpace,
|
||||||
|
} from 'react-native-iphone-x-helper';
|
||||||
import { ThemeColors, ThemeContext, NavigationRoute } from 'react-navigation';
|
import { ThemeColors, ThemeContext, NavigationRoute } from 'react-navigation';
|
||||||
|
|
||||||
import CrossFadeIcon from './CrossFadeIcon';
|
import CrossFadeIcon from './CrossFadeIcon';
|
||||||
@@ -30,6 +33,9 @@ const majorVersion = parseInt(Platform.Version as string, 10);
|
|||||||
const isIos = Platform.OS === 'ios';
|
const isIos = Platform.OS === 'ios';
|
||||||
const isIOS11 = majorVersion >= 11 && isIos;
|
const isIOS11 = majorVersion >= 11 && isIos;
|
||||||
|
|
||||||
|
const DEFAULT_HEIGHT = 49;
|
||||||
|
const COMPACT_HEIGHT = 29;
|
||||||
|
|
||||||
const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
|
const DEFAULT_MAX_TAB_ITEM_WIDTH = 125;
|
||||||
const DEFAULT_KEYBOARD_ANIMATION_CONFIG: KeyboardHidesTabBarAnimationConfig = {
|
const DEFAULT_KEYBOARD_ANIMATION_CONFIG: KeyboardHidesTabBarAnimationConfig = {
|
||||||
show: {
|
show: {
|
||||||
@@ -103,9 +109,7 @@ class TabBarBottom extends React.Component<BottomTabBarProps, State> {
|
|||||||
showIcon: true,
|
showIcon: true,
|
||||||
allowFontScaling: true,
|
allowFontScaling: true,
|
||||||
adaptive: isIOS11,
|
adaptive: isIOS11,
|
||||||
safeAreaInset: { bottom: 'always', top: 'never' } as React.ComponentProps<
|
safeAreaInset: { bottom: 'always', top: 'never' } as const,
|
||||||
typeof SafeAreaView
|
|
||||||
>['forceInset'],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line react/sort-comp
|
// eslint-disable-next-line react/sort-comp
|
||||||
@@ -394,6 +398,7 @@ class TabBarBottom extends React.Component<BottomTabBarProps, State> {
|
|||||||
keyboardHidesTabBar,
|
keyboardHidesTabBar,
|
||||||
onTabPress,
|
onTabPress,
|
||||||
onTabLongPress,
|
onTabLongPress,
|
||||||
|
isLandscape,
|
||||||
safeAreaInset,
|
safeAreaInset,
|
||||||
style,
|
style,
|
||||||
tabStyle,
|
tabStyle,
|
||||||
@@ -418,6 +423,7 @@ class TabBarBottom extends React.Component<BottomTabBarProps, State> {
|
|||||||
marginRight,
|
marginRight,
|
||||||
marginHorizontal,
|
marginHorizontal,
|
||||||
marginVertical,
|
marginVertical,
|
||||||
|
height,
|
||||||
...innerStyle
|
...innerStyle
|
||||||
} = StyleSheet.flatten(style || {});
|
} = StyleSheet.flatten(style || {});
|
||||||
|
|
||||||
@@ -436,13 +442,46 @@ class TabBarBottom extends React.Component<BottomTabBarProps, State> {
|
|||||||
marginVertical,
|
marginVertical,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const statusBarHeight = getStatusBarHeight(true);
|
||||||
|
const horizontalInset = isLandscape ? statusBarHeight : 0;
|
||||||
|
const insets = {
|
||||||
|
bottom:
|
||||||
|
typeof safeAreaInset?.bottom === 'number'
|
||||||
|
? safeAreaInset.bottom
|
||||||
|
: safeAreaInset?.bottom === 'never'
|
||||||
|
? 0
|
||||||
|
: getBottomSpace(),
|
||||||
|
left:
|
||||||
|
typeof safeAreaInset?.left === 'number'
|
||||||
|
? safeAreaInset.left
|
||||||
|
: safeAreaInset?.left === 'never'
|
||||||
|
? 0
|
||||||
|
: horizontalInset,
|
||||||
|
right:
|
||||||
|
typeof safeAreaInset?.right === 'number'
|
||||||
|
? safeAreaInset.right
|
||||||
|
: safeAreaInset?.right === 'never'
|
||||||
|
? 0
|
||||||
|
: horizontalInset,
|
||||||
|
};
|
||||||
|
|
||||||
const tabBarStyle = [
|
const tabBarStyle = [
|
||||||
|
{
|
||||||
|
height:
|
||||||
|
height != null
|
||||||
|
? typeof height === 'number'
|
||||||
|
? height + insets.bottom
|
||||||
|
: height
|
||||||
|
: // @ts-ignore: isPad exists in runtime but not available in type defs
|
||||||
|
(this._shouldUseHorizontalLabels() && !Platform.isPad
|
||||||
|
? COMPACT_HEIGHT
|
||||||
|
: DEFAULT_HEIGHT) + insets.bottom,
|
||||||
|
paddingBottom: insets.bottom,
|
||||||
|
paddingLeft: insets.left,
|
||||||
|
paddingRight: insets.right,
|
||||||
|
},
|
||||||
styles.tabBar,
|
styles.tabBar,
|
||||||
isDark ? styles.tabBarDark : styles.tabBarLight,
|
isDark ? styles.tabBarDark : styles.tabBarLight,
|
||||||
// @ts-ignore
|
|
||||||
this._shouldUseHorizontalLabels() && !Platform.isPad
|
|
||||||
? styles.tabBarCompact
|
|
||||||
: styles.tabBarRegular,
|
|
||||||
innerStyle,
|
innerStyle,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -473,7 +512,7 @@ class TabBarBottom extends React.Component<BottomTabBarProps, State> {
|
|||||||
}
|
}
|
||||||
onLayout={this._handleLayout}
|
onLayout={this._handleLayout}
|
||||||
>
|
>
|
||||||
<SafeAreaView style={tabBarStyle} forceInset={safeAreaInset}>
|
<View style={tabBarStyle}>
|
||||||
{routes.map((route, index) => {
|
{routes.map((route, index) => {
|
||||||
const focused = index === navigation.state.index;
|
const focused = index === navigation.state.index;
|
||||||
const scene = { route, focused };
|
const scene = { route, focused };
|
||||||
@@ -524,15 +563,12 @@ class TabBarBottom extends React.Component<BottomTabBarProps, State> {
|
|||||||
</ButtonComponent>
|
</ButtonComponent>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</SafeAreaView>
|
</View>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_HEIGHT = 49;
|
|
||||||
const COMPACT_HEIGHT = 29;
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
tabBar: {
|
tabBar: {
|
||||||
borderTopWidth: StyleSheet.hairlineWidth,
|
borderTopWidth: StyleSheet.hairlineWidth,
|
||||||
@@ -549,12 +585,6 @@ const styles = StyleSheet.create({
|
|||||||
container: {
|
container: {
|
||||||
elevation: 8,
|
elevation: 8,
|
||||||
},
|
},
|
||||||
tabBarCompact: {
|
|
||||||
height: COMPACT_HEIGHT,
|
|
||||||
},
|
|
||||||
tabBarRegular: {
|
|
||||||
height: DEFAULT_HEIGHT,
|
|
||||||
},
|
|
||||||
tab: {
|
tab: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: isIos ? 'center' : 'stretch',
|
alignItems: isIos ? 'center' : 'stretch',
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Platform, StyleSheet, View } from 'react-native';
|
import { Platform, StyleSheet, View } from 'react-native';
|
||||||
import { Screen, screensEnabled } from 'react-native-screens';
|
import {
|
||||||
|
Screen,
|
||||||
|
screensEnabled,
|
||||||
|
// @ts-ignore
|
||||||
|
shouldUseActivityState,
|
||||||
|
} from 'react-native-screens';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
style?: any;
|
style?: any;
|
||||||
|
enabled: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
|
const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view out of its container
|
||||||
@@ -13,11 +19,20 @@ const FAR_FAR_AWAY = 30000; // this should be big enough to move the whole view
|
|||||||
export default class ResourceSavingScene extends React.Component<Props> {
|
export default class ResourceSavingScene extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
// react-native-screens is buggy on web
|
// react-native-screens is buggy on web
|
||||||
if (screensEnabled?.() && Platform.OS !== 'web') {
|
if (screensEnabled?.() && this.props.enabled && Platform.OS !== 'web') {
|
||||||
const { isVisible, ...rest } = this.props;
|
const { isVisible, ...rest } = this.props;
|
||||||
|
|
||||||
// @ts-ignore
|
if (shouldUseActivityState) {
|
||||||
return <Screen active={isVisible ? 1 : 0} {...rest} />;
|
return (
|
||||||
|
// @ts-expect-error: there was an `active` prop and no `activityState` in older version and stackPresentation was required
|
||||||
|
<Screen activityState={isVisible ? 2 : 0} {...rest} />
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
// @ts-expect-error: there was an `active` prop and no `activityState` in older version and stackPresentation was required
|
||||||
|
<Screen active={isVisible ? 1 : 0} {...rest} />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { isVisible, children, style, ...rest } = this.props;
|
const { isVisible, children, style, ...rest } = this.props;
|
||||||
|
|||||||
Reference in New Issue
Block a user