Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/src/tests/single-feature-tests/split/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { ScenarioGroup } from '@apps/tests/shared/helpers';
import TestTopColumnForCollapsing from './test-top-column-for-collapsing';
import TestCommandShowColumn from './test-command-show-column';
import TestColorScheme from './test-split-color-scheme';

const scenarios = { TestTopColumnForCollapsing, TestCommandShowColumn };
const scenarios = {
TestTopColumnForCollapsing,
TestCommandShowColumn,
TestColorScheme,
};

const SplitScenarioGroup: ScenarioGroup<keyof typeof scenarios> = {
name: 'Split',
Expand Down
138 changes: 138 additions & 0 deletions apps/src/tests/single-feature-tests/split/test-split-color-scheme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import {
Appearance,
ColorSchemeName,
Platform,
ScrollView,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
import type { ScenarioDescription } from '@apps/tests/shared/helpers';
import { createScenario } from '@apps/tests/shared/helpers';
import React, { useEffect, useState } from 'react';
import { SettingsPicker } from '@apps/shared';
import { Split } from 'react-native-screens/experimental';
import { SplitHostColorScheme } from 'react-native-screens/components/gamma/split/SplitHost.types';

const scenarioDescription: ScenarioDescription = {
name: 'Split Color Scheme',
key: 'test-split-color-scheme',
details:
'Tests how Split handles system, React Native and prop color scheme.',
platforms: ['ios'],
};

export function ConfigColumn({
reactColorScheme,
setReactColorScheme,
hostColorScheme,
setHostColorScheme,
}: {
reactColorScheme: ColorSchemeName;
setReactColorScheme: (value: ColorSchemeName) => void;
hostColorScheme: SplitHostColorScheme;
setHostColorScheme: (value: SplitHostColorScheme) => void;
}) {
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<View style={styles.section}>
<Text style={styles.text}>
There are 3 sources of color scheme, in ascending order of precedence:
system, React Native and our property on SplitHost.
</Text>
</View>

<View style={styles.section}>
<Text style={styles.heading}>System color scheme</Text>
<Text style={styles.text}>
Switch system color scheme via Cmd+Shift+A (iOS simulator).
</Text>
</View>

<View style={styles.section}>
<Text style={styles.heading}>React Native's color scheme</Text>
<SettingsPicker<ColorSchemeName>
label={'colorScheme'}
value={reactColorScheme}
onValueChange={setReactColorScheme}
items={['unspecified', 'light', 'dark']}
/>
</View>

<View style={styles.section}>
<Text style={styles.heading}>SplitHost color scheme</Text>
<SettingsPicker<NonNullable<SplitHostColorScheme>>
label={'colorScheme'}
value={hostColorScheme}
onValueChange={setHostColorScheme}
items={['inherit', 'light', 'dark']}
/>
</View>
</ScrollView>
);
}

export function TestColumn() {
return (
<View style={styles.containerCenter}>
<TextInput placeholder="Type something..." />
</View>
);
}

export function App() {
const [hostColorScheme, setHostColorScheme] =
useState<SplitHostColorScheme>('inherit');
const [reactColorScheme, setReactColorScheme] =
useState<ColorSchemeName>('unspecified');

useEffect(() => {
Appearance.setColorScheme(reactColorScheme);
}, [reactColorScheme]);

return (
<Split.Host colorScheme={hostColorScheme}>
<Split.Column>
<ConfigColumn
reactColorScheme={reactColorScheme}
setReactColorScheme={setReactColorScheme}
hostColorScheme={hostColorScheme}
setHostColorScheme={setHostColorScheme}
/>
</Split.Column>
<Split.Column>
<TestColumn />
</Split.Column>
</Split.Host>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
},
containerCenter: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
content: {
padding: 20,
paddingTop: Platform.OS === 'android' ? 60 : undefined,
},
heading: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 5,
color: 'rgb(0, 122, 255)',
},
section: {
marginBottom: 10,
},
text: {
color: 'gray',
},
});

export default createScenario(App, scenarioDescription);
16 changes: 16 additions & 0 deletions ios/conversion/RNSConversions-SplitView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ RNSOrientation RNSOrientationFromRNSSplitHostOrientation(react::RNSSplitHostOrie
}
}

UIUserInterfaceStyle UIUserInterfaceStyleFromHostProp(react::RNSSplitHostColorScheme colorScheme)
{
using enum facebook::react::RNSSplitHostColorScheme;
switch (colorScheme) {
case Inherit:
return UIUserInterfaceStyleUnspecified;
case Light:
return UIUserInterfaceStyleLight;
case Dark:
return UIUserInterfaceStyleDark;
default:
RCTLogError(@"[RNScreens] unsupported color scheme");
return UIUserInterfaceStyleUnspecified;
}
}

#pragma mark SplitScreen props

RNSSplitScreenColumnType RNSSplitScreenColumnTypeFromScreenProp(facebook::react::RNSSplitScreenColumnType columnType)
Expand Down
2 changes: 2 additions & 0 deletions ios/conversion/RNSConversions.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ std::optional<UISplitViewControllerColumn> SplitViewTopColumnForCollapsingFromHo

RNSOrientation RNSOrientationFromRNSSplitHostOrientation(react::RNSSplitHostOrientation orientation);

UIUserInterfaceStyle UIUserInterfaceStyleFromHostProp(react::RNSSplitHostColorScheme colorScheme);

#pragma mark SplitScreen props

RNSSplitScreenColumnType RNSSplitScreenColumnTypeFromScreenProp(react::RNSSplitScreenColumnType columnType);
Expand Down
1 change: 1 addition & 0 deletions ios/gamma/split/RNSSplitAppearanceApplicator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class RNSSplitAppearanceApplicator {
// Step 1 - general settings
splitHostController.displayModeButtonVisibility = splitHost.displayModeButtonVisibility
splitHostController.preferredSplitBehavior = splitHost.preferredSplitBehavior
splitHostController.overrideUserInterfaceStyle = splitHost.colorScheme
#if !os(tvOS)
splitHostController.primaryBackgroundStyle = splitHost.primaryBackgroundStyle
#endif
Expand Down
1 change: 1 addition & 0 deletions ios/gamma/split/RNSSplitHostComponentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ NS_ASSUME_NONNULL_BEGIN
#endif // RNS_IPHONE_OS_VERSION_AVAILABLE(26_0)

@property (nonatomic, readonly) RNSOrientation orientation;
@property (nonatomic, readonly) UIUserInterfaceStyle colorScheme;

@end

Expand Down
5 changes: 5 additions & 0 deletions ios/gamma/split/RNSSplitHostComponentView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ - (void)updateProps:(const facebook::react::Props::Shared &)props
rnscreens::conversion::SplitViewPreferredDisplayModeFromHostProp(newComponentProps.preferredDisplayMode);
}

if (oldComponentProps.colorScheme != newComponentProps.colorScheme) {
_needsSplitAppearanceUpdate = true;
_colorScheme = rnscreens::conversion::UIUserInterfaceStyleFromHostProp(newComponentProps.colorScheme);
}

#if !TARGET_OS_TV
if (oldComponentProps.primaryBackgroundStyle != newComponentProps.primaryBackgroundStyle) {
_needsSplitAppearanceUpdate = true;
Expand Down
17 changes: 16 additions & 1 deletion src/components/gamma/split/SplitHost.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { NativeSyntheticEvent, ViewProps } from 'react-native';
import type { InterfaceOrientation } from '../../shared/types';
import type { InterfaceOrientation, ColorScheme } from '../../shared/types';

// eslint-disable-next-line @typescript-eslint/ban-types
type GenericEmptyEvent = Readonly<{}>;
Expand Down Expand Up @@ -28,6 +28,8 @@ export type SplitDisplayMode =

export type SplitHostOrientation = InterfaceOrientation | 'inherit';

export type SplitHostColorScheme = ColorScheme | 'inherit';

export interface SplitColumnMetrics {
/**
* @summary Minimum width for the primary sidebar.
Expand Down Expand Up @@ -217,6 +219,19 @@ export interface SplitHostProps extends ViewProps {
* @platform ios
*/
orientation?: SplitHostOrientation | undefined;
/**
* @summary Specifies the color scheme used by the container and any child containers.
*
* The following values are currently supported:
* - `inherit` - the interface style from parent,
* - `light` - the light interface style,
* - `dark` - the dark interface style.
*
* @default inherit
*
* @platform ios
*/
colorScheme?: SplitHostColorScheme;
/**
* @summary Determines whether gestures are enabled to change the display mode.
*/
Expand Down
3 changes: 3 additions & 0 deletions src/fabric/gamma/split/SplitHostNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type SplitViewOrientation =
| 'landscapeLeft'
| 'landscapeRight';

type SplitViewColorScheme = 'inherit' | 'light' | 'dark';

type SplitViewPrimaryBackgroundStyle = 'default' | 'none' | 'sidebar';

type SplitViewTopColumnForCollapsing =
Expand Down Expand Up @@ -78,6 +80,7 @@ interface NativeProps extends ViewProps {
>;
columnMetrics?: ColumnMetrics | undefined;
orientation?: CT.WithDefault<SplitViewOrientation, 'inherit'>;
colorScheme?: CT.WithDefault<SplitViewColorScheme, 'inherit'>;
primaryBackgroundStyle?: CT.WithDefault<
SplitViewPrimaryBackgroundStyle,
'default'
Expand Down
Loading