Skip to content

Commit 64f658c

Browse files
authored
Merge branch 'master' into master
2 parents 6ba26d0 + 32dd354 commit 64f658c

File tree

13 files changed

+121
-57
lines changed

13 files changed

+121
-57
lines changed

.github/workflows/require-label.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ jobs:
88
enforce-label:
99
runs-on: ubuntu-latest
1010
steps:
11-
- uses: yogevbd/enforce-label-action@2.0.0
11+
- uses: yogevbd/enforce-label-action@2.2.1
1212
with:
1313
REQUIRED_LABELS_ANY: "type: accepted/bug,type: accepted/enhancement,Infrastructure,type: documentation"

.vscode/settings.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@
33
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
44
"eslint.enable": true,
55
"typescript.tsdk": "node_modules/typescript/lib",
6-
"editor.formatOnSaveMode": "modifications"
76
}

e2e/Buttons.test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ describe('Buttons', () => {
3232

3333
it('custom button is clickable', async () => {
3434
await elementByLabel('Two').tap();
35-
await expect(elementByLabel('Thanks for that :)')).toExist();
35+
await expect(elementByLabel('Times created: 1')).toExist();
3636
});
3737

38-
it(':ios: Reseting buttons should unmount button react view', async () => {
38+
it(':ios: Resetting buttons should unmount button react view', async () => {
3939
await elementById(TestIDs.SHOW_LIFECYCLE_BTN).tap();
4040
await elementById(TestIDs.RESET_BUTTONS).tap();
4141
await expect(elementByLabel('Button component unmounted')).toBeVisible();
@@ -56,4 +56,10 @@ describe('Buttons', () => {
5656
await elementById(TestIDs.ADD_BUTTON).tap();
5757
await elementById(TestIDs.BUTTON_THREE).tap();
5858
});
59+
60+
it('Button component is not recreated if it has a predefined componentId', async () => {
61+
await elementById(TestIDs.ADD_BUTTON).tap();
62+
await elementById(TestIDs.ROUND_BUTTON).tap();
63+
await expect(elementByLabel('Times created: 1')).toBeVisible();
64+
});
5965
});

lib/android/app/src/main/java/com/reactnativenavigation/options/FadeAnimation.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import org.json.JSONObject;
55

66
public class FadeAnimation extends NestedAnimationsOptions {
7-
public FadeAnimation() {
7+
public FadeAnimation(boolean reversed) {
88
try {
99
JSONObject alpha = new JSONObject();
10-
alpha.put("from", 0);
11-
alpha.put("to", 1);
10+
alpha.put("from", reversed ? 1 : 0);
11+
alpha.put("to", reversed ? 0 : 1);
1212
alpha.put("duration", 300);
1313

1414
JSONObject content = new JSONObject();
@@ -21,4 +21,8 @@ public FadeAnimation() {
2121
e.printStackTrace();
2222
}
2323
}
24+
25+
public FadeAnimation() {
26+
this(false);
27+
}
2428
}

lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/stack/StackAnimator.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ open class StackAnimator @JvmOverloads constructor(
7373
}
7474

7575
private suspend fun popWithElementTransitions(appearing: ViewController<*>, disappearing: ViewController<*>, pop: NestedAnimationsOptions, set: AnimatorSet) {
76-
val fade = if (pop.content.isFadeAnimation()) pop else FadeAnimation()
76+
val fade = if (pop.content.isFadeAnimation()) pop else FadeAnimation(true)
7777
val transitionAnimators = transitionAnimatorCreator.create(pop, fade.content, disappearing, appearing)
7878
set.playTogether(fade.content.getAnimation(disappearing.view), transitionAnimators)
7979
transitionAnimators.listeners.forEach { listener: Animator.AnimatorListener -> set.addListener(listener) }

lib/ios/RNNLayoutManager.m

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
21
#import "RNNLayoutManager.h"
32
#import "RNNLayoutProtocol.h"
43
#import "UIViewController+LayoutProtocol.h"
54

65
@implementation RNNLayoutManager
76

87
+ (UIViewController *)findComponentForId:(NSString *)componentId {
9-
for (UIWindow* window in UIApplication.sharedApplication.windows) {
10-
UIViewController* result = [self findChildComponentForParent:window.rootViewController ForId:componentId];
8+
for (UIWindow *window in UIApplication.sharedApplication.windows) {
9+
UIViewController *result = [self findChildComponentForParent:window.rootViewController forId:componentId];
1110
if (result) {
1211
return result;
1312
}
@@ -16,25 +15,20 @@ + (UIViewController *)findComponentForId:(NSString *)componentId {
1615
return nil;
1716
}
1817

19-
+ (UIViewController *)findChildComponentForParent:(UIViewController *)parentViewController ForId:(NSString *)componentId {
18+
+ (UIViewController *)findChildComponentForParent:(UIViewController *)parentViewController forId:(NSString *)componentId {
2019
if ([parentViewController.layoutInfo.componentId isEqualToString:componentId]) {
2120
return parentViewController;
2221
}
2322

2423
if (parentViewController.presentedViewController) {
25-
if ([parentViewController.presentedViewController.layoutInfo.componentId isEqualToString:componentId]) {
26-
return parentViewController.presentedViewController;
27-
}
28-
29-
UIViewController* modalResult = [self findChildComponentForParent:parentViewController.presentedViewController ForId:componentId];
24+
UIViewController *modalResult = [self findChildComponentForParent:parentViewController.presentedViewController forId:componentId];
3025
if (modalResult) {
3126
return modalResult;
3227
}
33-
3428
}
3529

36-
for (UIViewController* childVC in parentViewController.childViewControllers) {
37-
UIViewController* result = [self findChildComponentForParent:childVC ForId:componentId];
30+
for (UIViewController *childVC in parentViewController.childViewControllers) {
31+
UIViewController *result = [self findChildComponentForParent:childVC forId:componentId];
3832
if (result) {
3933
return result;
4034
}
@@ -43,5 +37,4 @@ + (UIViewController *)findChildComponentForParent:(UIViewController *)parentView
4337
return nil;
4438
}
4539

46-
4740
@end

lib/src/commands/OptionsProcessor.test.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { UniqueIdProvider } from '../adapters/UniqueIdProvider';
33
import { Store } from '../components/Store';
44
import { OptionProcessorsStore } from '../processors/OptionProcessorsStore';
55
import { Options, OptionsModalPresentationStyle } from '../interfaces/Options';
6-
import { mock, when, anyString, instance, anyNumber, verify } from 'ts-mockito';
6+
import { mock, when, instance, anyNumber, verify } from 'ts-mockito';
77
import { ColorService } from '../adapters/ColorService';
88
import { AssetService } from '../adapters/AssetResolver';
99
import { Deprecations } from './Deprecations';
@@ -25,7 +25,9 @@ describe('navigation options', () => {
2525
const assetService = instance(mockedAssetService);
2626

2727
const mockedColorService = mock(ColorService) as ColorService;
28-
when(mockedColorService.toNativeColor(anyString())).thenReturn(666);
28+
when(mockedColorService.toNativeColor('red')).thenReturn(0xffff0000);
29+
when(mockedColorService.toNativeColor('green')).thenReturn(0xff00ff00);
30+
when(mockedColorService.toNativeColor('blue')).thenReturn(0xff0000ff);
2931
const colorService = instance(mockedColorService);
3032
optionProcessorsRegistry = new OptionProcessorsStore();
3133
uut = new OptionsProcessor(
@@ -172,8 +174,8 @@ describe('navigation options', () => {
172174
};
173175
uut.processOptions(options, CommandName.SetRoot);
174176
expect(options).toEqual({
175-
statusBar: { backgroundColor: 666 },
176-
topBar: { background: { color: 666 } },
177+
statusBar: { backgroundColor: 0xffff0000 },
178+
topBar: { background: { color: 0xff0000ff } },
177179
});
178180
});
179181

@@ -279,4 +281,41 @@ describe('navigation options', () => {
279281
}
280282
);
281283
});
284+
285+
it('transform searchBar bool to object', () => {
286+
const options = { topBar: { searchBar: true as any } };
287+
uut.processOptions(options, CommandName.SetRoot);
288+
expect(options.topBar.searchBar).toStrictEqual({
289+
visible: true,
290+
hideOnScroll: false,
291+
hideTopBarOnFocus: false,
292+
obscuresBackgroundDuringPresentation: false,
293+
backgroundColor: null,
294+
tintColor: null,
295+
placeholder: '',
296+
});
297+
});
298+
299+
it('transform searchBar bool to object and merges in deprecated values', () => {
300+
const options = {
301+
topBar: {
302+
searchBar: true as any,
303+
searchBarHiddenWhenScrolling: true,
304+
hideNavBarOnFocusSearchBar: true,
305+
searchBarBackgroundColor: 'red',
306+
searchBarTintColor: 'green',
307+
searchBarPlaceholder: 'foo',
308+
},
309+
};
310+
uut.processOptions(options, CommandName.SetRoot);
311+
expect(options.topBar.searchBar).toStrictEqual({
312+
visible: true,
313+
hideOnScroll: true,
314+
hideTopBarOnFocus: true,
315+
obscuresBackgroundDuringPresentation: false,
316+
backgroundColor: 0xffff0000,
317+
tintColor: 0xff00ff00,
318+
placeholder: 'foo',
319+
});
320+
});
282321
});

lib/src/commands/OptionsProcessor.ts

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Store } from '../components/Store';
1010
import { UniqueIdProvider } from '../adapters/UniqueIdProvider';
1111
import { ColorService } from '../adapters/ColorService';
1212
import { AssetService } from '../adapters/AssetResolver';
13-
import { Options } from '../interfaces/Options';
13+
import { Options, OptionsSearchBar, OptionsTopBar } from '../interfaces/Options';
1414
import { Deprecations } from './Deprecations';
1515
import { OptionProcessorsStore } from '../processors/OptionProcessorsStore';
1616
import { CommandName } from '../interfaces/CommandName';
@@ -49,7 +49,7 @@ export class OptionsProcessor {
4949
}
5050

5151
private processObject(
52-
objectToProcess: object,
52+
objectToProcess: Record<string, any>,
5353
parentOptions: object,
5454
onProcess: (key: string, parentOptions: object) => void,
5555
commandName: CommandName,
@@ -72,8 +72,9 @@ export class OptionsProcessor {
7272

7373
onProcess(key, parentOptions);
7474

75-
if (!isEqual(key, 'passProps') && (isObject(value) || isArray(value))) {
76-
this.processObject(value, parentOptions, onProcess, commandName, objectPath);
75+
const processedValue = objectToProcess[key];
76+
if (!isEqual(key, 'passProps') && (isObject(processedValue) || isArray(processedValue))) {
77+
this.processObject(processedValue, parentOptions, onProcess, commandName, objectPath);
7778
}
7879
});
7980
}
@@ -138,30 +139,34 @@ export class OptionsProcessor {
138139
}
139140
}
140141

141-
private processSearchBar(key: string, value: any, options: Record<string, any>) {
142-
if (isEqual(key, 'searchBar')) {
143-
typeof value === 'boolean' && this.deprecations.onProcessOptions(key, options, '');
142+
private processSearchBar(key: string, value: OptionsSearchBar | boolean, options: OptionsTopBar) {
143+
if (key !== 'searchBar') {
144+
return;
145+
}
146+
147+
const deprecatedSearchBarOptions: OptionsSearchBar = {
148+
visible: false,
149+
hideOnScroll: options.searchBarHiddenWhenScrolling ?? false,
150+
hideTopBarOnFocus: options.hideNavBarOnFocusSearchBar ?? false,
151+
obscuresBackgroundDuringPresentation: false,
152+
backgroundColor: options.searchBarBackgroundColor,
153+
tintColor: options.searchBarTintColor,
154+
placeholder: options.searchBarPlaceholder ?? '',
155+
};
156+
157+
if (typeof value === 'boolean') {
158+
// Deprecated
159+
this.deprecations.onProcessOptions(key, options, '');
160+
161+
options[key] = {
162+
...deprecatedSearchBarOptions,
163+
visible: value,
164+
};
165+
} else {
144166
options[key] = {
145-
...options[key],
146-
visible: options[key].visible ?? value,
147-
hiddenWhenScrolling:
148-
options[key].hiddenWhenScrolling ?? options.searchBarHiddenWhenScrolling ?? false,
149-
hideTopBarOnFocus:
150-
options[key].hideTopBarOnFocus ?? options.hideNavBarOnFocusSearchBar ?? false,
151-
obscuresBackgroundDuringPresentation:
152-
options[key].obscuresBackgroundDuringPresentation ?? false,
153-
placeholder: options[key].placeholder ?? options.searchBarPlaceholder ?? '',
167+
...deprecatedSearchBarOptions,
168+
...value,
154169
};
155-
this.processColor(
156-
'backgroundColor',
157-
options[key].backgroundColor ?? options.searchBarBackgroundColor,
158-
options[key]
159-
);
160-
this.processColor(
161-
'tintColor',
162-
options[key].tintColor ?? options.searchBarTintColor,
163-
options[key]
164-
);
165170
}
166171
}
167172

lib/src/interfaces/Options.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,17 @@ export interface ViewAnimationOptions extends ScreenAnimationOptions {
11051105
id?: string;
11061106
}
11071107

1108+
export interface ModalAnimationOptions extends ViewAnimationOptions {
1109+
/**
1110+
* Animations to be applied on elements which are shared between the appearing and disappearing screens
1111+
*/
1112+
sharedElementTransitions?: SharedElementTransition[];
1113+
/**
1114+
* Animations to be applied on views in the appearing or disappearing screens
1115+
*/
1116+
elementTransitions?: ElementTransition[];
1117+
}
1118+
11081119
/**
11091120
* Used for describing stack commands animations.
11101121
*/
@@ -1163,11 +1174,11 @@ export interface AnimationOptions {
11631174
/**
11641175
* Configure what animates when modal is shown
11651176
*/
1166-
showModal?: ViewAnimationOptions;
1177+
showModal?: ModalAnimationOptions;
11671178
/**
11681179
* Configure what animates when modal is dismissed
11691180
*/
1170-
dismissModal?: ViewAnimationOptions;
1181+
dismissModal?: ModalAnimationOptions;
11711182
}
11721183

11731184
/**

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-navigation",
3-
"version": "7.1.0",
3+
"version": "7.2.0",
44
"description": "React Native Navigation - truly native navigation for iOS and Android",
55
"license": "MIT",
66
"nativePackage": true,
@@ -184,4 +184,4 @@
184184
}
185185
}
186186
}
187-
}
187+
}

playground/src/screens/ButtonsScreen.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default class ButtonOptions extends NavigationComponent {
5555
name: Screens.RoundButton,
5656
passProps: {
5757
title: 'Two',
58+
timesCreated: 1,
5859
},
5960
},
6061
},

playground/src/screens/RoundedButton.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@ import Colors from '../commons/Colors';
55

66
interface Props extends NavigationComponentProps {
77
title: string;
8+
timesCreated?: number;
89
}
910

11+
let timesCreated = 0;
1012
export default class RoundedButton extends React.Component<Props> {
1113
constructor(props: Props) {
1214
super(props);
1315
Navigation.events().bindComponent(this);
16+
timesCreated = props.timesCreated ?? timesCreated + 1;
1417
}
1518

1619
render() {
1720
return (
1821
<View style={styles.container}>
1922
<View style={styles.button}>
20-
<TouchableOpacity onPress={() => Alert.alert(this.props.title, 'Thanks for that :)')}>
23+
<TouchableOpacity
24+
onPress={() => Alert.alert(this.props.title, `Times created: ${timesCreated}`)}
25+
>
2126
<Text style={styles.text}>{this.props.title}</Text>
2227
</TouchableOpacity>
2328
</View>

scripts/test-e2e.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ function run() {
2727
}
2828
exec.execSync(
2929
`detox test --configuration ${configuration} ${headless$} -w ${workers} ${loglevel}`
30-
); //-f "ScreenStyle.test.js" --loglevel trace
30+
// "Buttons.test.js" --loglevel trace`
31+
);
3132
}

0 commit comments

Comments
 (0)