From 27afc4d4fbadad53d5d677c6cf1c6cfe7c0d4232 Mon Sep 17 00:00:00 2001 From: JP Date: Sat, 7 Nov 2020 12:50:48 +0000 Subject: [PATCH] adds support for column-based SplitViews on iOS 14+ --- e2e/SplitView.test.js | 2 +- lib/ios/RNNSplitViewController.m | 38 +++++++- lib/ios/RNNSplitViewOptions.h | 1 + lib/ios/RNNSplitViewOptions.m | 1 + lib/ios/UISplitViewController+RNNOptions.m | 19 ++++ lib/src/Navigation.ts | 2 +- lib/src/commands/Commands.test.ts | 3 +- lib/src/commands/Deprecations.ts | 18 ++++ lib/src/commands/LayoutTreeParser.test.ts | 7 +- lib/src/commands/LayoutTreeParser.ts | 32 ++++++- lib/src/interfaces/Layout.ts | 27 +++++- lib/src/interfaces/Options.ts | 28 ++++-- playground/src/screens/LayoutsScreen.tsx | 11 ++- playground/src/screens/Screens.ts | 4 +- playground/src/screens/index.tsx | 8 +- ...Screen.tsx => CocktailSecondaryScreen.tsx} | 2 +- .../CocktailsListScreen.tsx | 2 +- .../sharedElementTransition/CocktailsView.tsx | 1 + ...een.tsx => CocktailsListPrimaryScreen.tsx} | 10 +- playground/src/testIDs.ts | 2 +- website/docs/api/layout-splitView.mdx | 96 +++++++++++++++---- website/docs/api/options-splitView.mdx | 32 +++++-- website/docs/docs/style-animations.mdx | 6 +- .../version-6.12.2/docs/style-animations.mdx | 6 +- .../version-7.0.0/docs/style-animations.mdx | 6 +- 25 files changed, 291 insertions(+), 73 deletions(-) rename playground/src/screens/sharedElementTransition/{CocktailDetailsScreen.tsx => CocktailSecondaryScreen.tsx} (97%) rename playground/src/screens/splitView/{CocktailsListMasterScreen.tsx => CocktailsListPrimaryScreen.tsx} (85%) diff --git a/e2e/SplitView.test.js b/e2e/SplitView.test.js index ff5a4257913..fa1fdddb0cc 100644 --- a/e2e/SplitView.test.js +++ b/e2e/SplitView.test.js @@ -17,7 +17,7 @@ describe(':ios: SplitView', () => { }); it('push screen to master screen', async () => { - await elementById(TestIDs.PUSH_MASTER_BTN).tap(); + await elementById(TestIDs.PUSH_PRIMARY_BTN).tap(); await expect(elementByLabel('Pushed Screen')).toBeVisible(); }); diff --git a/lib/ios/RNNSplitViewController.m b/lib/ios/RNNSplitViewController.m index d0dca932b16..edfd8e12426 100644 --- a/lib/ios/RNNSplitViewController.m +++ b/lib/ios/RNNSplitViewController.m @@ -3,10 +3,44 @@ @implementation RNNSplitViewController +- (instancetype)initWithLayoutInfo:(RNNLayoutInfo *)layoutInfo + creator:(id)creator + options:(RNNNavigationOptions *)options + defaultOptions:(RNNNavigationOptions *)defaultOptions + presenter:(RNNBasePresenter *)presenter + eventEmitter:(RNNEventEmitter *)eventEmitter + childViewControllers:(NSArray *)childViewControllers { + if (@available(iOS 14.0, *)) { + NSString* style = options.splitView.style; + if ([style isEqualToString:@"tripleColumn"]) { + self = [self initWithStyle:UISplitViewControllerStyleTripleColumn]; + } else if ([style isEqualToString:@"doubleColumn"]) { + self = [self initWithStyle:UISplitViewControllerStyleDoubleColumn]; + } else { + self = [self init]; + } + } else { + // Fallback on earlier versions + self = [self init]; + } + self.options = options; + self.defaultOptions = defaultOptions; + self.layoutInfo = layoutInfo; + self.creator = creator; + self.eventEmitter = eventEmitter; + self.presenter = presenter; + [self loadChildren:childViewControllers]; + [self.presenter bindViewController:self]; + self.extendedLayoutIncludesOpaqueBars = YES; + [self.presenter applyOptionsOnInit:self.resolveOptions]; + + return self; +} + - (void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers { [super setViewControllers:viewControllers]; - UIViewController *masterViewController = viewControllers[0]; - self.delegate = masterViewController; + UIViewController *primaryViewController = viewControllers[0]; + self.delegate = primaryViewController; } - (UIViewController *)getCurrentChild { diff --git a/lib/ios/RNNSplitViewOptions.h b/lib/ios/RNNSplitViewOptions.h index c9644c25968..a5d6d98b125 100644 --- a/lib/ios/RNNSplitViewOptions.h +++ b/lib/ios/RNNSplitViewOptions.h @@ -7,5 +7,6 @@ @property(nonatomic, strong) Number *minWidth; @property(nonatomic, strong) Number *maxWidth; @property(nonatomic, strong) NSString *primaryBackgroundStyle; +@property(nonatomic, strong) NSString *style; @end diff --git a/lib/ios/RNNSplitViewOptions.m b/lib/ios/RNNSplitViewOptions.m index 7b0bcce0a3c..cd3be55fdc0 100644 --- a/lib/ios/RNNSplitViewOptions.m +++ b/lib/ios/RNNSplitViewOptions.m @@ -10,6 +10,7 @@ - (instancetype)initWithDict:(NSDictionary *)dict { self.minWidth = [NumberParser parse:dict key:@"minWidth"]; self.maxWidth = [NumberParser parse:dict key:@"maxWidth"]; self.primaryBackgroundStyle = dict[@"primaryBackgroundStyle"]; + self.style = dict[@"style"]; return self; } diff --git a/lib/ios/UISplitViewController+RNNOptions.m b/lib/ios/UISplitViewController+RNNOptions.m index 8eda7d52a58..d179921e680 100644 --- a/lib/ios/UISplitViewController+RNNOptions.m +++ b/lib/ios/UISplitViewController+RNNOptions.m @@ -5,11 +5,30 @@ @implementation UISplitViewController (RNNOptions) - (void)rnn_setDisplayMode:(NSString *)displayMode { if ([displayMode isEqualToString:@"visible"]) { + // deprecated since iOS 14 self.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; } else if ([displayMode isEqualToString:@"hidden"]) { + // deprecated since iOS 14 self.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden; } else if ([displayMode isEqualToString:@"overlay"]) { + // deprecated since iOS 14 self.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryOverlay; + } else if ([displayMode isEqualToString:@"secondaryOnly"]) { + self.preferredDisplayMode = UISplitViewControllerDisplayModeSecondaryOnly; + } else if ([displayMode isEqualToString:@"oneBesideSecondary"]) { + self.preferredDisplayMode = UISplitViewControllerDisplayModeOneBesideSecondary; + } else if ([displayMode isEqualToString:@"oneOverSecondary"]) { + self.preferredDisplayMode = UISplitViewControllerDisplayModeOneOverSecondary; + } else if (@available(iOS 14.0, *)) { + if ([displayMode isEqualToString:@"twoBesideSecondary"]) { + self.preferredDisplayMode = UISplitViewControllerDisplayModeTwoBesideSecondary; + } else if ([displayMode isEqualToString:@"twoDisplaceSecondary"]) { + self.preferredDisplayMode = UISplitViewControllerDisplayModeTwoDisplaceSecondary; + } else if ([displayMode isEqualToString:@"twoOverSecondary"]) { + self.preferredDisplayMode = UISplitViewControllerDisplayModeTwoOverSecondary; + } else { + self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic; + } } else { self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic; } diff --git a/lib/src/Navigation.ts b/lib/src/Navigation.ts index 47cd17baaa6..75658172948 100644 --- a/lib/src/Navigation.ts +++ b/lib/src/Navigation.ts @@ -63,7 +63,7 @@ export class NavigationRoot { this.componentWrapper, appRegistryService ); - this.layoutTreeParser = new LayoutTreeParser(this.uniqueIdProvider); + this.layoutTreeParser = new LayoutTreeParser(this.uniqueIdProvider, new Deprecations()); const optionsProcessor = new OptionsProcessor( this.store, this.uniqueIdProvider, diff --git a/lib/src/commands/Commands.test.ts b/lib/src/commands/Commands.test.ts index 1ad9f4a00df..fa5a7da3434 100644 --- a/lib/src/commands/Commands.test.ts +++ b/lib/src/commands/Commands.test.ts @@ -7,6 +7,7 @@ import { LayoutTreeParser } from './LayoutTreeParser'; import { LayoutTreeCrawler } from './LayoutTreeCrawler'; import { Store } from '../components/Store'; import { Commands } from './Commands'; +import { Deprecations } from './Deprecations'; import { CommandsObserver } from '../events/CommandsObserver'; import { NativeCommandsSender } from '../adapters/NativeCommandsSender'; import { OptionsProcessor } from './OptionsProcessor'; @@ -42,7 +43,7 @@ describe('Commands', () => { uut = new Commands( mockedStore, instance(mockedNativeCommandsSender), - new LayoutTreeParser(uniqueIdProvider), + new LayoutTreeParser(uniqueIdProvider, new Deprecations()), new LayoutTreeCrawler(instance(mockedStore), optionsProcessor), commandsObserver, uniqueIdProvider, diff --git a/lib/src/commands/Deprecations.ts b/lib/src/commands/Deprecations.ts index a10671a4598..d6073821881 100644 --- a/lib/src/commands/Deprecations.ts +++ b/lib/src/commands/Deprecations.ts @@ -2,6 +2,7 @@ import once from 'lodash/once'; import get from 'lodash/get'; import each from 'lodash/each'; import { Platform } from 'react-native'; +import { Layout, LayoutSplitView } from 'react-native-navigation/interfaces/Layout'; export class Deprecations { private deprecatedOptions: Array<{ key: string; showWarning: any }> = [ @@ -77,6 +78,17 @@ export class Deprecations { } } + public onParseLayout(api: Layout) { + if ( + api.splitView && + Platform.OS === 'ios' && + typeof api.splitView.master !== 'undefined' && + typeof api.splitView.detail !== 'undefined' + ) { + this.deprecateMasterDetailSplitView(api.splitView); + } + } + public onProcessDefaultOptions(_key: string, _parentOptions: Record) {} private deprecateSearchBarOptions = once((parentOptions: object) => { @@ -97,4 +109,10 @@ export class Deprecations { parentOptions ); }); + private deprecateMasterDetailSplitView = once((api: LayoutSplitView) => { + console.warn( + `using SplitView with master and detail is deprecated on iOS. For more information see https://github.com/wix/react-native-navigation/pull/6705`, + api + ); + }); } diff --git a/lib/src/commands/LayoutTreeParser.test.ts b/lib/src/commands/LayoutTreeParser.test.ts index 1b5e5c50fb2..65565cddf92 100644 --- a/lib/src/commands/LayoutTreeParser.test.ts +++ b/lib/src/commands/LayoutTreeParser.test.ts @@ -1,6 +1,7 @@ import keys from 'lodash/keys'; import { LayoutTreeParser } from './LayoutTreeParser'; import { LayoutType } from './LayoutType'; +import { Deprecations } from './Deprecations'; import { Options } from '../interfaces/Options'; import { Layout } from '../interfaces/Layout'; import { UniqueIdProvider } from '../adapters/UniqueIdProvider'; @@ -13,7 +14,7 @@ describe('LayoutTreeParser', () => { beforeEach(() => { mockedUniqueIdProvider = mock(UniqueIdProvider); when(mockedUniqueIdProvider.generate(anything())).thenReturn('myUniqueId'); - uut = new LayoutTreeParser(instance(mockedUniqueIdProvider)); + uut = new LayoutTreeParser(instance(mockedUniqueIdProvider), new Deprecations()); }); describe('parses into { type, data, children }', () => { @@ -293,13 +294,13 @@ const complexLayout: Layout = { const splitView: Layout = { splitView: { - master: { + primary: { stack: { children: [singleComponent], options, }, }, - detail: stackWithTopBar, + secondary: stackWithTopBar, options: optionsSplitView, }, }; diff --git a/lib/src/commands/LayoutTreeParser.ts b/lib/src/commands/LayoutTreeParser.ts index 57d75350b6c..26af1e41db5 100644 --- a/lib/src/commands/LayoutTreeParser.ts +++ b/lib/src/commands/LayoutTreeParser.ts @@ -1,5 +1,6 @@ import { LayoutType } from './LayoutType'; import { LayoutNode } from './LayoutTreeCrawler'; +import { Deprecations } from './Deprecations'; import { Layout, LayoutTopTabs, @@ -13,7 +14,7 @@ import { import { UniqueIdProvider } from '../adapters/UniqueIdProvider'; export class LayoutTreeParser { - constructor(private uniqueIdProvider: UniqueIdProvider) { + constructor(private uniqueIdProvider: UniqueIdProvider, private deprecations: Deprecations) { this.parse = this.parse.bind(this); } @@ -31,6 +32,10 @@ export class LayoutTreeParser { } else if (api.externalComponent) { return this.externalComponent(api.externalComponent); } else if (api.splitView) { + if (api.splitView.master || api.splitView.detail) { + // Deprecated + this.deprecations.onParseLayout(api); + } return this.splitView(api.splitView); } throw new Error(`unknown LayoutType "${Object.keys(api)}"`); @@ -126,14 +131,31 @@ export class LayoutTreeParser { } private splitView(api: LayoutSplitView): LayoutNode { - const master = api.master ? this.parse(api.master) : undefined; - const detail = api.detail ? this.parse(api.detail) : undefined; - return { id: api.id || this.uniqueIdProvider.generate(LayoutType.SplitView), type: LayoutType.SplitView, data: { options: api.options }, - children: master && detail ? [master, detail] : [], + children: this.splitViewChildren(api), }; } + + private splitViewChildren(api: LayoutSplitView): LayoutNode[] { + const children: LayoutNode[] = []; + if (api.primary) { + children.push(this.parse(api.primary)); + } else if (api.master) { + // Deprecated -- treat as `primary` + children.push(this.parse(api.master)); + } + if (api.supplementary) { + children.push(this.parse(api.supplementary)); + } + if (api.secondary) { + children.push(this.parse(api.secondary)); + } else if (api.detail) { + // Deprecated -- treat as `secondary` + children.push(this.parse(api.detail)); + } + return children; + } } diff --git a/lib/src/interfaces/Layout.ts b/lib/src/interfaces/Layout.ts index aee17a02ded..03142cd5ccb 100644 --- a/lib/src/interfaces/Layout.ts +++ b/lib/src/interfaces/Layout.ts @@ -105,26 +105,43 @@ export interface LayoutSideMenu { options?: Options; } -export interface LayoutSplitView { +export interface LayoutSplitViewCurrent { /** * Set ID of the stack so you can use Navigation.mergeOptions to * update options */ id?: string; /** - * Set master layout (the smaller screen, sidebar) + * Set primary layout */ - master?: Layout; + primary?: Layout; /** - * Set detail layout (the larger screen, flexes) + * Set supplementary layout (for 3 column layouts on iOS 14+) */ - detail?: Layout; + supplementary?: Layout; + /** + * Set secondary layout + */ + secondary?: Layout; /** * Configure split view */ options?: Options; } +export interface LayoutSplitViewDeprecated { + /** + * Set master layout (the smaller screen, sidebar) + */ + master?: Layout; + /** + * Set master layout (the smaller screen, sidebar) + */ + detail?: Layout; +} + +export type LayoutSplitView = LayoutSplitViewCurrent & LayoutSplitViewDeprecated; + export interface LayoutTopTabs { /** * Set the layout's id so Navigation.mergeOptions can be used to update options diff --git a/lib/src/interfaces/Options.ts b/lib/src/interfaces/Options.ts index 8645a898916..7a32c47b2da 100644 --- a/lib/src/interfaces/Options.ts +++ b/lib/src/interfaces/Options.ts @@ -77,21 +77,32 @@ type Interpolation = export interface OptionsSplitView { /** - * Master view display mode + * Primary view display mode. + * The following options will only work on iOS 14+: twoBesideSecondary, twoDisplaceSecondary, twoOverSecondary * @default 'auto' */ - displayMode?: 'auto' | 'visible' | 'hidden' | 'overlay'; - /** - * Master view side. Leading is left. Trailing is right. + displayMode?: + | 'auto' + | 'visible' + | 'hidden' + | 'overlay' + | 'secondaryOnly' + | 'oneBesideSecondary' + | 'oneOverSecondary' + | 'twoBesideSecondary' // iOS 14+ only + | 'twoDisplaceSecondary' // iOS 14+ only + | 'twoOverSecondary'; // iOS 14+ only + /** + * Primary view side. Leading is left. Trailing is right. * @default 'leading' */ primaryEdge?: 'leading' | 'trailing'; /** - * Set the minimum width of master view + * Set the minimum width of primary view */ minWidth?: number; /** - * Set the maximum width of master view + * Set the maximum width of primary view */ maxWidth?: number; /** @@ -99,6 +110,11 @@ export interface OptionsSplitView { * @default 'none' */ primaryBackgroundStyle?: 'none' | 'sidebar'; + /** + * Describe the number of columns the split view interface displays (iOS 14+) + * @default 'unspecified' + */ + style?: 'unspecified' | 'doubleColumn' | 'tripleColumn'; } export interface OptionsStatusBar { diff --git a/playground/src/screens/LayoutsScreen.tsx b/playground/src/screens/LayoutsScreen.tsx index 3465ac984ba..3a62b12b9d6 100644 --- a/playground/src/screens/LayoutsScreen.tsx +++ b/playground/src/screens/LayoutsScreen.tsx @@ -113,11 +113,11 @@ export default class LayoutsScreen extends NavigationComponent { id: 'SPLITVIEW_ID', master: { stack: { - id: 'MASTER_ID', + id: 'PRIMARY_ID', children: [ { component: { - name: Screens.CocktailsListMasterScreen, + name: Screens.CocktailsListPrimaryScreen, }, }, ], @@ -125,12 +125,12 @@ export default class LayoutsScreen extends NavigationComponent { }, detail: { stack: { - id: 'DETAILS_ID', + id: 'SECONDARY_ID', children: [ { component: { id: 'DETAILS_COMPONENT_ID', - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, }, }, ], @@ -142,6 +142,9 @@ export default class LayoutsScreen extends NavigationComponent { }, splitView: { displayMode: 'visible', + minWidth: 375, + maxWidth: 375, + style: 'doubleColumn', }, }, }, diff --git a/playground/src/screens/Screens.ts b/playground/src/screens/Screens.ts index 25ac5d4a07f..37d517f77fb 100644 --- a/playground/src/screens/Screens.ts +++ b/playground/src/screens/Screens.ts @@ -7,9 +7,9 @@ const StatusBarFirstTab = 'StatusBarFirstTab'; const Screens = { Buttons: 'Buttons', - CocktailDetailsScreen: 'CocktailDetailsScreen', + CocktailSecondaryScreen: 'CocktailSecondaryScreen', CocktailsListScreen: 'CocktailsListScreen', - CocktailsListMasterScreen: 'CocktailsListMasterScreen', + CocktailsListPrimaryScreen: 'CocktailsListPrimaryScreen', CarDetailsScreen: 'CarDetailsScreen', CarStoryScreen: 'CarStoryScreen', CarsListScreen: 'CarsListScreen', diff --git a/playground/src/screens/index.tsx b/playground/src/screens/index.tsx index e5eb043c65e..9d22ad716d7 100644 --- a/playground/src/screens/index.tsx +++ b/playground/src/screens/index.tsx @@ -6,8 +6,8 @@ import Screens from './Screens'; function registerScreens() { Navigation.registerComponent(Screens.Alert, () => require('./Alert').default); Navigation.registerComponent( - Screens.CocktailDetailsScreen, - () => require('./sharedElementTransition/CocktailDetailsScreen').default + Screens.CocktailSecondaryScreen, + () => require('./sharedElementTransition/CocktailSecondaryScreen').default ); Navigation.registerComponent( Screens.CocktailsListScreen, @@ -24,8 +24,8 @@ function registerScreens() { gestureHandlerRootHOC(require('./sharedElementCarDealer/CarStoryScreen').default) ); Navigation.registerComponent( - Screens.CocktailsListMasterScreen, - () => require('./splitView/CocktailsListMasterScreen').default + Screens.CocktailsListPrimaryScreen, + () => require('./splitView/CocktailsListPrimaryScreen').default ); Navigation.registerComponent( Screens.EventsOverlay, diff --git a/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.tsx b/playground/src/screens/sharedElementTransition/CocktailSecondaryScreen.tsx similarity index 97% rename from playground/src/screens/sharedElementTransition/CocktailDetailsScreen.tsx rename to playground/src/screens/sharedElementTransition/CocktailSecondaryScreen.tsx index 3918a422f41..a2b2d83b260 100644 --- a/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.tsx +++ b/playground/src/screens/sharedElementTransition/CocktailSecondaryScreen.tsx @@ -14,7 +14,7 @@ const { COCKTAILS_DETAILS_HEADER, PUSH_DETAILS_BTN } = testIDs; interface Props extends NavigationComponentProps, CocktailItem {} -export default class CocktailDetailsScreen extends React.Component { +export default class CocktailSecondaryScreen extends React.Component { static options(): Options { return { ...Platform.select({ diff --git a/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx b/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx index 60795a4b6bd..4309c904e47 100644 --- a/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx +++ b/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx @@ -43,7 +43,7 @@ export default class CocktailsListScreen extends NavigationComponent { pushCocktailDetails = (item: CocktailItem) => { Navigation.push(this, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: { diff --git a/playground/src/screens/sharedElementTransition/CocktailsView.tsx b/playground/src/screens/sharedElementTransition/CocktailsView.tsx index 066e0ae312c..03b2bce8ca7 100644 --- a/playground/src/screens/sharedElementTransition/CocktailsView.tsx +++ b/playground/src/screens/sharedElementTransition/CocktailsView.tsx @@ -68,6 +68,7 @@ export default class CocktailsView extends React.Component { const SIZE = 150; const styles = StyleSheet.create({ root: { + paddingLeft: 100, paddingTop: 16, }, itemContainer: { diff --git a/playground/src/screens/splitView/CocktailsListMasterScreen.tsx b/playground/src/screens/splitView/CocktailsListPrimaryScreen.tsx similarity index 85% rename from playground/src/screens/splitView/CocktailsListMasterScreen.tsx rename to playground/src/screens/splitView/CocktailsListPrimaryScreen.tsx index cbfacaf5cea..8f033fa83f4 100644 --- a/playground/src/screens/splitView/CocktailsListMasterScreen.tsx +++ b/playground/src/screens/splitView/CocktailsListPrimaryScreen.tsx @@ -8,9 +8,9 @@ import CocktailsListScreen from '../sharedElementTransition/CocktailsListScreen' import testIDs from '../../testIDs'; -const { PUSH_MASTER_BTN } = testIDs; +const { PUSH_PRIMARY_BTN } = testIDs; -export default class CocktailsListMasterScreen extends CocktailsListScreen { +export default class CocktailsListPrimaryScreen extends CocktailsListScreen { static options() { return { ...Platform.select({ @@ -27,8 +27,8 @@ export default class CocktailsListMasterScreen extends CocktailsListScreen { }, rightButtons: [ { - id: 'pushMaster', - testID: PUSH_MASTER_BTN, + id: 'pushPrimary', + testID: PUSH_PRIMARY_BTN, text: 'push', }, ], @@ -42,7 +42,7 @@ export default class CocktailsListMasterScreen extends CocktailsListScreen { } navigationButtonPressed(event: NavigationButtonPressedEvent) { - if (event.buttonId === 'pushMaster') { + if (event.buttonId === 'pushPrimary') { Navigation.push(this, Screens.Pushed); } } diff --git a/playground/src/testIDs.ts b/playground/src/testIDs.ts index 4143bb70a7b..81e05a8e56f 100644 --- a/playground/src/testIDs.ts +++ b/playground/src/testIDs.ts @@ -36,7 +36,7 @@ const testIDs = { LAZY_TOP_PAR: 'LAZY_TOP_PAR', PUSH_BTN: 'PUSH_BUTTON', PUSH_DETAILS_BTN: 'PUSH_DETAILS_BUTTON', - PUSH_MASTER_BTN: 'PUSH_MASTER_BUTTON', + PUSH_PRIMARY_BTN: 'PUSH_MASTER_BUTTON', PUSH_LAZY_BTN: 'PUSH_LAZY_BTN', PUSH_SIDE_MENU_BTN: 'PUSH_SIDE_MENU_BTN', SHOW_STATIC_EVENTS_SCREEN: 'SHOW_STATIC_EVENTS_SCREEN', diff --git a/website/docs/api/layout-splitView.mdx b/website/docs/api/layout-splitView.mdx index de1709b485d..d386be8a160 100644 --- a/website/docs/api/layout-splitView.mdx +++ b/website/docs/api/layout-splitView.mdx @@ -4,47 +4,111 @@ title: SplitView sidebar_label: SplitView --- -A container view controller implementing a master-detail interface. See [UISplitViewController docs](https://developer.apple.com/documentation/uikit/uisplitviewcontroller). -Currently implemented only in iOS. +A container view controller that implements a hierarchical interface. See [UISplitViewController docs](https://developer.apple.com/documentation/uikit/uisplitviewcontroller). +Only available for iOS. + +In iOS 14 and later, SplitView supports column-style layouts. Before iOS 14, SplitView supported just one interface style with a master view controller and a detail view controller. + +In order to use a column-style layout, you must set a `style` option. Without providing this, SplitView will default to displaying the classic interface. + +It is also worth noting that each `component` is automatially embedded into a UINavigationView by iOS when using a column-based layout style. Therefore you can set `topBar` options such as `title` as shown below. + +A toggle icon is also displayed in the Navigation bar to hide / show the Primary component. ```js { id: 'PROFILE_TAB', - master: { + primary: { component: { - id: 'MASTER_SCREEN', - name: 'MasterScreen' + id: 'PRIMARY_SCREEN', + name: 'PrimaryScreen', + options: { + topBar: { + title: { + text: 'Primary', + }, + }, + }, } }, - detail: { + supplementary: { component: { - id: 'DETAIL_SCREEN', - name: 'DetailScreen' + id: 'SUPPLEMENTARY_SCREEN', + name: 'SupplementaryScreen' + options: { + topBar: { + title: { + text: 'Supplementary', + }, + }, + }, } + }, + secondary: { + component: { + id: 'SECONDARY_SCREEN', + name: 'SecondaryScreen' + options: { + topBar: { + title: { + text: 'Secondary', + }, + }, + }, + } + }, + options: { + style: 'tripleColumn' } } ``` ## `id` -| Type | Required | Description | -| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Type | Required | Description | +| ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | string | No | Unique id used to interact with the view via the Navigation api, usually `Navigation.mergeOptions` which accepts the componentId as it's first argument. | +## `primary` + +| Type | Required | Description | +| --------------------------- | -------- | ------------------ | +| [Layout](layout-layout.mdx) | YES | Set primary layout | + +## `supplementary` + +| Type | Required | Description | +| --------------------------- | -------- | ---------------------------------------------------------- | +| [Layout](layout-layout.mdx) | NO | Set supplementary layout (for 3 column layouts on iOS 14+) | + +## `secondary` + +| Type | Required | Description | +| --------------------------- | -------- | -------------------- | +| [Layout](layout-layout.mdx) | YES | Set secondary layout | + ## `master` -| Type | Required | Description | -| ------------------ | -------- | ----------------------------------------------- | +| Type | Required | Description | +| --------------------------- | -------- | ----------------------------------------------- | | [Layout](layout-layout.mdx) | YES | Set master layout (the smaller screen, sidebar) | +:::warning Deprecation warning +This option is currently deprecated and will be removed in a future release. Please use `primary` instead. +::: + ## `detail` -| Type | Required | Description | -| ------------------ | -------- | --------------------------------------------- | +| Type | Required | Description | +| --------------------------- | -------- | --------------------------------------------- | | [Layout](layout-layout.mdx) | YES | Set detail layout (the larger screen, flexes) | +:::warning Deprecation warning +This option is currently deprecated and will be removed in a future release. Please use `secondary` instead. +::: + ## `options` -| Type | Required | Description | -| ----------------------- | -------- | ----------------------------------------------- | +| Type | Required | Description | +| --------------------------- | -------- | ----------------------------------------------- | | [Options](options-root.mdx) | No | dynamic options which will apply to all screens | diff --git a/website/docs/api/options-splitView.mdx b/website/docs/api/options-splitView.mdx index 85f43f41e43..b7d80edd535 100644 --- a/website/docs/api/options-splitView.mdx +++ b/website/docs/api/options-splitView.mdx @@ -8,9 +8,20 @@ sidebar_label: SplitView Master view display mode. -| Type | Required | Default | Platform | -| -------------------------------------------- | -------- | ------- | -------- | -| enum('auto', 'visible', 'hidden', 'overlay') | No | 'auto' | iOS | +| Type | Required | Default | Platform | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | -------- | +| enum('auto', 'visible', 'hidden', 'overlay', 'secondaryOnly', 'oneBesideSecondary', 'oneOverSecondary, 'twoBesideSecondary, 'twoDisplaceSecondary, 'twoOverSecondary') | No | 'auto' | iOS | + +The following values are only supported on iOS 14+: + +- "secondaryOnly" +- "oneBesideSecondary" +- "oneOverSecondary" +- "twoBesideSecondary" +- "twoDisplaceSecondary" +- "twoOverSecondary" + +To understand what these options do, refer the [DisplayMode docs](https://developer.apple.com/documentation/uikit/uisplitviewcontroller/displaymode). ### `primaryEdge` @@ -42,6 +53,15 @@ Set background style of sidebar. Currently works for Mac Catalyst apps only. See: [Optimizing Your iPad App for Mac ](https://developer.apple.com/documentation/uikit/mac_catalyst/optimizing_your_ipad_app_for_mac#3239145) -| Type | Required | Default | Platform | -| --------------------------- | -------- | --------- | -------- | -| enum('none', 'sidebar') | No | 'none' | iOS | +| Type | Required | Default | Platform | +| ----------------------- | -------- | ------- | -------- | +| enum('none', 'sidebar') | No | 'none' | iOS | + +### `style` + +The style that determines the number of columns that the split view interface displays. +See: [UISplitViewController.style](https://developer.apple.com/documentation/uikit/uisplitviewcontroller/style) + +| Type | Required | Default | Platform | +| --------------------------------------------------- | -------- | ------------- | -------- | +| enum('unspecified', 'doubleColumn', 'tripleColumn') | No | 'unspecified' | iOS | diff --git a/website/docs/docs/style-animations.mdx b/website/docs/docs/style-animations.mdx index 9fc1b97939d..17b1677343c 100644 --- a/website/docs/docs/style-animations.mdx +++ b/website/docs/docs/style-animations.mdx @@ -149,7 +149,7 @@ At the moment, the transition is available for push and pop commands. We are wor Let's take a more in-depth look at the following example, which you can find in the playground app: -> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.tsx) +> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.tsx) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailSecondaryScreen.tsx)

Shared Element Transition @@ -205,7 +205,7 @@ each element must include a unique `nativeID` prop. ```jsx Navigation.push(this.props.componentId, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: { @@ -265,7 +265,7 @@ An element can either be in the source or destination screen. ```jsx Navigation.push(this.props.componentId, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: { diff --git a/website/versioned_docs/version-6.12.2/docs/style-animations.mdx b/website/versioned_docs/version-6.12.2/docs/style-animations.mdx index d0f2e3d91d7..1d8b841c86a 100644 --- a/website/versioned_docs/version-6.12.2/docs/style-animations.mdx +++ b/website/versioned_docs/version-6.12.2/docs/style-animations.mdx @@ -149,7 +149,7 @@ At the moment, the transition is available for push and pop commands. We are wor Let's take a more in-depth look at the following example, which you can find in the playground app: -> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.js) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.js) +> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.js) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailSecondaryScreen.js)

Shared Element Transition @@ -205,7 +205,7 @@ each element must include a unique `nativeID` prop. ```jsx Navigation.push(this.props.componentId, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: { @@ -244,7 +244,7 @@ An element can either be in the source or destination screen. ```jsx Navigation.push(this.props.componentId, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: { diff --git a/website/versioned_docs/version-7.0.0/docs/style-animations.mdx b/website/versioned_docs/version-7.0.0/docs/style-animations.mdx index d0f2e3d91d7..1d8b841c86a 100644 --- a/website/versioned_docs/version-7.0.0/docs/style-animations.mdx +++ b/website/versioned_docs/version-7.0.0/docs/style-animations.mdx @@ -149,7 +149,7 @@ At the moment, the transition is available for push and pop commands. We are wor Let's take a more in-depth look at the following example, which you can find in the playground app: -> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.js) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailDetailsScreen.js) +> [Source screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailsListScreen.js) and the [Destination screen](https://github.com/wix/react-native-navigation/blob/master/playground/src/screens/sharedElementTransition/CocktailSecondaryScreen.js)

Shared Element Transition @@ -205,7 +205,7 @@ each element must include a unique `nativeID` prop. ```jsx Navigation.push(this.props.componentId, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: { @@ -244,7 +244,7 @@ An element can either be in the source or destination screen. ```jsx Navigation.push(this.props.componentId, { component: { - name: Screens.CocktailDetailsScreen, + name: Screens.CocktailSecondaryScreen, passProps: { ...item }, options: { animations: {