Skip to content

Fix support for setting color scheme manually #1561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 29, 2021
Merged
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
2 changes: 1 addition & 1 deletion demo/src/configurations.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Spacings.loadSpacings({
/* Dark Mode Schemes */
Colors.loadSchemes({
light: {
screenBG: 'transparent',
screenBG: Colors.white,
textColor: Colors.grey10,
moonOrSun: Colors.yellow30,
mountainForeground: Colors.green30,
Expand Down
42 changes: 33 additions & 9 deletions demo/src/screens/foundationScreens/DarkModeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
import React, {Component} from 'react';
import {StyleSheet} from 'react-native';
import {View, Text, Constants} from 'react-native-ui-lib';
import {View, Text, Colors, Constants, SegmentedControl, SchemeType} from 'react-native-ui-lib';

const SCHEME_TYPES: {label: string; value: SchemeType}[] = [
{label: 'device (default)', value: 'default'},
{label: 'dark', value: 'dark'},
{label: 'light', value: 'light'}
];

const DEVICE_DARK_MODE_MESSAGE = Constants.isIOS
? 'Change to dark mode in simulator by pressing Cmd+Shift+A'
: 'Change to dark mode';
const MANUAL_DARK_MODE_MESSAGE = 'Setting the scheme manually will ignore device settings';

class DarkModeScreen extends Component {
state = {};
state = {
selectedSchemeType: 'default'
};

changeSchemeType = (index: number) => {
this.setState({selectedSchemeType: SCHEME_TYPES[index].value});
Colors.setScheme(SCHEME_TYPES[index].value);
};

render() {
const {selectedSchemeType} = this.state;
const message = selectedSchemeType === 'default' ? DEVICE_DARK_MODE_MESSAGE : MANUAL_DARK_MODE_MESSAGE;

return (
<View flex padding-page bg-screenBG>
<Text h1 textColor>
Dark Mode
</Text>
{Constants.isIOS ? (
<Text marginT-s2 body textColor>
Change to dark mode in simulator by pressing Cmd+Shift+A
</Text>
) : (
<Text marginT-s2 body textColor>Change to dark mode</Text>
)}
<SegmentedControl
containerStyle={{alignSelf: 'flex-start', marginTop: 20}}
segments={SCHEME_TYPES}
onChangeIndex={this.changeSchemeType}
/>

<Text marginT-s2 body textColor>
{message}
</Text>

<View style={styles.moonOrSun} bg-moonOrSun/>
<View style={[styles.mountain, styles.mountainBackground]} bg-mountainBackground/>
Expand Down
6 changes: 0 additions & 6 deletions generatedTypes/src/components/connectionStatusBar/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,6 @@ declare class ConnectionStatusBar extends PureComponent<ConnectionStatusBarProps
}
export { ConnectionStatusBar };
declare const _default: React.ComponentClass<ConnectionStatusBarProps & {
/**
* @description: Top bar to show a "no internet" connection status. Note: Run on real device for best results
* @image: https://user-images.githubusercontent.com/33805983/34683190-f3b1904c-f4a9-11e7-9d46-9a340bd35448.png, https://user-images.githubusercontent.com/33805983/34484206-edc6c6e4-efcb-11e7-88b2-cd394c19dd5e.png
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/ConnectionStatusBarScreen.tsx
* @notes: The component requires installing the '@react-native-community/netinfo' native library
*/
useCustomTheme?: boolean | undefined;
}, any> & typeof ConnectionStatusBar;
export default _default;
28 changes: 12 additions & 16 deletions generatedTypes/src/style/colors.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
import _ from 'lodash';
import tinycolor from 'tinycolor2';
declare type Schemes = {
light: {
[key: string]: string;
};
dark: {
[key: string]: string;
};
};
declare type SchemeType = 'default' | 'light' | 'dark';
import { Schemes, SchemeType } from './scheme';
export declare class Colors {
[key: string]: any;
schemes: Schemes;
currentScheme: SchemeType;
constructor();
/**
* Load custom set of colors
Expand Down Expand Up @@ -107,6 +97,9 @@ declare const colorObject: Colors & {
orange30: string;
orange40: string;
orange50: string;
/**
* Get app's current color scheme
*/
orange60: string;
orange70: string;
orange80: string;
Expand All @@ -120,6 +113,14 @@ declare const colorObject: Colors & {
red80: string;
purple10: string;
purple20: string;
/**
* Add alpha to hex or rgb color
* arguments:
* p1 - hex color / R part of RGB
* p2 - opacity / G part of RGB
* p3 - B part of RGB
* p4 - opacity
*/
purple30: string;
purple40: string;
purple50: string;
Expand All @@ -138,11 +139,6 @@ declare const colorObject: Colors & {
black: string;
transparent: string;
} & {
/**
* Set color scheme for app
* arguments:
* scheme - color scheme e.g light/dark/default
*/
primary: string;
};
export default colorObject;
1 change: 1 addition & 0 deletions generatedTypes/src/style/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as Colors } from './colors';
export { default as Scheme, SchemeType, Schemes, SchemeChangeListener } from './scheme';
export { default as Typography } from './typography';
export { default as BorderRadiuses } from './borderRadiuses';
export { default as Shadows } from './shadows';
Expand Down
53 changes: 53 additions & 0 deletions generatedTypes/src/style/scheme.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export declare type Schemes = {
light: {
[key: string]: string;
};
dark: {
[key: string]: string;
};
};
export declare type SchemeType = 'default' | 'light' | 'dark';
export declare type SchemeChangeListener = (schemeType?: 'light' | 'dark') => void;
declare class Scheme {
currentScheme: SchemeType;
schemes: Schemes;
changeListeners: SchemeChangeListener[];
constructor();
private broadcastSchemeChange;
/**
* Get app's current color scheme
*/
getSchemeType(): 'light' | 'dark';
/**
* Set color scheme for app
* arguments:
* scheme - color scheme e.g light/dark/default
*/
setScheme(scheme: SchemeType): void;
/**
* Load set of schemes for light/dark mode
* arguments:
* schemes - two sets of map of colors e.g {light: {screen: 'white'}, dark: {screen: 'black'}}
*/
loadSchemes(schemes: Schemes): void;
/**
* Retrieve scheme by current scheme type
*/
getScheme(): {
[key: string]: string;
} | {
[key: string]: string;
};
/**
* Add a change scheme event listener
*/
addChangeListener(listener: SchemeChangeListener): void;
/**
* Remove a change scheme event listener
* arguments:
* listener - listener reference to remove
*/
removeChangeListener(listener: SchemeChangeListener): void;
}
declare const _default: Scheme;
export default _default;
25 changes: 6 additions & 19 deletions src/commons/asBaseComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import {Appearance, EventSubscription} from 'react-native';
import hoistStatics from 'hoist-non-react-statics';
import * as Modifiers from './modifiers';
import {Scheme} from '../style';
import forwardRef from './forwardRef';
import UIComponent from './UIComponent';

Expand All @@ -27,32 +27,19 @@ function asBaseComponent<PROPS, STATICS = {}>(WrappedComponent: React.ComponentT
error: false
};

appearanceListenerSubscription?: EventSubscription = undefined;

componentDidMount() {
// < RN64 - void
// >= RN65 - EventSubscription
const subscription = Appearance.addChangeListener(this.appearanceListener);
if (subscription !== undefined) {
// @ts-ignore
this.appearanceListenerSubscription = subscription;
}
Scheme.addChangeListener(this.appearanceListener);
}

componentWillUnmount() {
if (this.appearanceListenerSubscription) {
// >=RN65
this.appearanceListenerSubscription?.remove();
} else {
// <RN65
Appearance.removeChangeListener(this.appearanceListener);
}
Scheme.removeChangeListener(this.appearanceListener);
}

appearanceListener: Appearance.AppearanceListener = () => {
appearanceListener = () => {
// iOS 13 and above will trigger this call with the wrong colorScheme value. So just ignore returned colorScheme for now
// https://github.com/facebook/react-native/issues/28525
this.setState({colorScheme: Appearance.getColorScheme()});
// this.setState({colorScheme: Appearance.getColorScheme()});
this.setState({colorScheme: Scheme.getSchemeType()});
};

static getThemeProps = (props: any, context: any) => {
Expand Down
33 changes: 18 additions & 15 deletions src/commons/modifiers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from 'lodash';
import {StyleSheet} from 'react-native';
import {Typography, Colors, BorderRadiuses, Spacings, ThemeManager} from '../style';
import {Typography, Colors, Scheme, BorderRadiuses, Spacings, ThemeManager} from '../style';
import {BorderRadiusesLiterals} from '../style/borderRadiuses';
import TypographyPresets from '../style/typographyPresets';
import {SpacingLiterals} from '../style/spacings';
Expand Down Expand Up @@ -58,7 +58,6 @@ const STYLE_KEY_CONVERTERS = {
flexS: 'flexShrink'
} as const;


export type PaddingLiterals = keyof typeof PADDING_VARIATIONS;
export type NativePaddingKeyType = typeof PADDING_VARIATIONS[PaddingLiterals];
export type MarginLiterals = keyof typeof MARGIN_VARIATIONS;
Expand All @@ -69,12 +68,18 @@ export type ColorLiterals = keyof typeof colorsPalette;
export type TypographyLiterals = keyof typeof TypographyPresets;
export type BorderRadiusLiterals = keyof typeof BorderRadiusesLiterals;
export type AlignmentLiterals =
| 'row' | 'spread'
| 'center' | 'centerH' | 'centerV'
| 'left' | 'right' | 'top' | 'bottom';
| 'row'
| 'spread'
| 'center'
| 'centerH'
| 'centerV'
| 'left'
| 'right'
| 'top'
| 'bottom';
export type PositionLiterals = 'absF' | 'absL' | 'absR' | 'absT' | 'absB' | 'absV' | 'absH';

export type Modifier<T extends string> = Partial<Record<T, boolean>>
export type Modifier<T extends string> = Partial<Record<T, boolean>>;
export type CustomModifier = {[key: string]: boolean};

export type TypographyModifiers = Modifier<TypographyLiterals> | CustomModifier;
Expand All @@ -87,8 +92,7 @@ export type MarginModifiers = Modifier<MarginLiterals>;
export type FlexModifiers = Modifier<FlexLiterals>;
export type BorderRadiusModifiers = Modifier<BorderRadiusLiterals>;

export type ContainerModifiers =
AlignmentModifiers &
export type ContainerModifiers = AlignmentModifiers &
PositionModifiers &
PaddingModifiers &
MarginModifiers &
Expand All @@ -97,8 +101,7 @@ export type ContainerModifiers =
BackgroundColorModifier;

export function extractColorValue(props: Dictionary<any>) {
const scheme = Colors.getScheme();
const schemeColors = Colors.schemes[scheme];
const schemeColors = Scheme.getScheme();
const allColorsKeys: Array<keyof typeof Colors> = [..._.keys(Colors), ..._.keys(schemeColors)];
const colorPropsKeys = _.chain(props)
.keys()
Expand All @@ -110,8 +113,8 @@ export function extractColorValue(props: Dictionary<any>) {

export function extractBackgroundColorValue(props: Dictionary<any>) {
let backgroundColor;
const scheme = Colors.getScheme();
const schemeColors = Colors.schemes[scheme];

const schemeColors = Scheme.getScheme();

const keys = Object.keys(props);
const bgProp = _.findLast(keys, prop => Colors.getBackgroundKeysPattern().test(prop) && !!props[prop])!;
Expand Down Expand Up @@ -243,7 +246,7 @@ export function extractPositionStyle(props: Dictionary<any>) {
}
style = {...style, ...styles.absolute};
});

return _.isEmpty(style) ? undefined : style;
}

Expand Down Expand Up @@ -366,8 +369,8 @@ export function generateModifiersStyle(options = {
alignments: true,
flex: true,
position: true
}, props: Dictionary<any>) {

},
props: Dictionary<any>) {
//@ts-ignore
const boundProps = props || this.props;
const style: ExtractedStyle = {};
Expand Down
Loading