Skip to content
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

Theme switching ESLint rules #32569

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
0095fc7
update eslint
chrispader Dec 7, 2023
8aa81be
add eslint ignores
chrispader Dec 7, 2023
8879e2c
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
Dec 13, 2023
26fa87e
update eslint rules
Dec 13, 2023
7dc7d8e
fix: storybook
Dec 13, 2023
b756433
fix: style util structure
Dec 14, 2023
157548e
fix: more imports
Dec 14, 2023
8db99c5
fix: illustrations type
Dec 14, 2023
41d4b83
remove staticStyleUtils export
Dec 14, 2023
35a1f1e
create FontUtils
Dec 14, 2023
c07f952
fix: font utils usages
Dec 14, 2023
de21804
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
Dec 14, 2023
0826677
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
chrispader Dec 15, 2023
ece565a
move FontUtils
chrispader Dec 15, 2023
9920571
move again
chrispader Dec 15, 2023
194160f
adapt eslint rules
chrispader Dec 15, 2023
0b3e28f
fix: eslint rule
chrispader Dec 15, 2023
678bfdf
fix imports
chrispader Dec 15, 2023
2334531
fix: adress comments
chrispader Dec 16, 2023
a1ff255
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
chrispader Dec 16, 2023
e9950ab
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
chrispader Dec 19, 2023
19d729b
add eslint exception for types
chrispader Dec 19, 2023
deb3408
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
chrispader Dec 21, 2023
46a49d1
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
chrispader Jan 3, 2024
220c545
fix merge conflicts
chrispader Jan 3, 2024
32f176f
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
Jan 4, 2024
3b0e1a4
fix: lint
Jan 4, 2024
99ca991
Merge branch 'main' into @chrispader/theme-switching-eslint-rules
chrispader Jan 5, 2024
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
32 changes: 32 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,45 @@ const restrictedImportPaths = [
importNames: ['CSSProperties'],
message: "Please use 'ViewStyle', 'TextStyle', 'ImageStyle' from 'react-native' instead.",
},
{
name: '@styles/index',
importNames: ['default', 'defaultStyles'],
message: 'Do not import styles directly. Please use the `useThemeStyles` hook or `withThemeStyles` HOC instead.',
},
{
name: '@styles/utils',
importNames: ['default', 'DefaultStyleUtils'],
message: 'Do not import StyleUtils directly. Please use the `useStyleUtils` hook or `withStyleUtils` HOC instead.',
},
{
name: '@styles/theme',
importNames: ['default', 'defaultTheme'],

message: 'Do not import themes directly. Please use the `useTheme` hook or `withTheme` HOC instead.',
},
{
name: '@styles/theme/illustrations',
message: 'Do not import theme illustrations directly. Please use the `useThemeIllustrations` hook instead.',
},
];

const restrictedImportPatterns = [
{
group: ['**/assets/animations/**/*.json'],
message: "Do not import animations directly. Please use the 'src/components/LottieAnimations' import instead.",
},
{
group: ['@styles/theme/themes/**'],
message: 'Do not import themes directly. Please use the `useTheme` hook or `withTheme` HOC instead.',
},
{
group: ['@styles/utils/**', '!@styles/utils/FontUtils', '!@styles/utils/types'],
message: 'Do not import style util functions directly. Please use the `useStyleUtils` hook or `withStyleUtils` HOC instead.',
},
{
group: ['@styles/theme/illustrations/themes/**'],
message: 'Do not import theme illustrations directly. Please use the `useThemeIllustrations` hook instead.',
},
];

module.exports = {
Expand Down
4 changes: 2 additions & 2 deletions src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {defaultHTMLElementModels, RenderHTMLConfigProvider, TRenderEngineProvide
import _ from 'underscore';
import useThemeStyles from '@hooks/useThemeStyles';
import convertToLTR from '@libs/convertToLTR';
import singleFontFamily from '@styles/utils/fontFamily/singleFontFamily';
import FontUtils from '@styles/utils/FontUtils';
import * as HTMLEngineUtils from './htmlEngineUtils';
import htmlRenderers from './HTMLRenderers';

Expand Down Expand Up @@ -82,7 +82,7 @@ function BaseHTMLEngineProvider(props) {
baseStyle={styles.webViewStyles.baseFontStyle}
tagsStyles={styles.webViewStyles.tagStyles}
enableCSSInlineProcessing={false}
systemFonts={_.values(singleFontFamily)}
systemFonts={_.values(FontUtils.fontFamily.single)}
domVisitors={{
// eslint-disable-next-line no-param-reassign
onText: (text) => (text.data = convertToLTR(text.data)),
Expand Down
11 changes: 5 additions & 6 deletions src/components/Onfido/BaseOnfidoWeb.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import _ from 'underscore';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import Log from '@libs/Log';
import fontFamily from '@styles/utils/fontFamily';
import fontWeightBold from '@styles/utils/fontWeight/bold';
import FontUtils from '@styles/utils/FontUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import './index.css';
Expand All @@ -18,11 +17,11 @@ function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLo
containerId: CONST.ONFIDO.CONTAINER_ID,
useMemoryHistory: true,
customUI: {
fontFamilyTitle: `${fontFamily.EXP_NEUE}, -apple-system, serif`,
fontFamilySubtitle: `${fontFamily.EXP_NEUE}, -apple-system, serif`,
fontFamilyBody: `${fontFamily.EXP_NEUE}, -apple-system, serif`,
fontFamilyTitle: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
fontFamilySubtitle: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
fontFamilyBody: `${FontUtils.fontFamily.platform.EXP_NEUE}, -apple-system, serif`,
fontSizeTitle: `${variables.fontSizeLarge}px`,
fontWeightTitle: fontWeightBold,
fontWeightTitle: FontUtils.fontWeight.bold,
fontWeightSubtitle: 400,
fontSizeSubtitle: `${variables.fontSizeNormal}px`,
colorContentTitle: theme.text,
Expand Down
7 changes: 4 additions & 3 deletions src/components/Text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import React from 'react';
import {Text as RNText, StyleSheet} from 'react-native';
import type {TextProps as RNTextProps, TextStyle} from 'react-native';
import useTheme from '@hooks/useTheme';
import fontFamily from '@styles/utils/fontFamily';
import type {FontUtilsType} from '@styles/utils/FontUtils';
import FontUtils from '@styles/utils/FontUtils';
import variables from '@styles/variables';
import type ChildrenProps from '@src/types/utils/ChildrenProps';

Expand All @@ -22,7 +23,7 @@ type TextProps = RNTextProps &
children: React.ReactNode;

/** The family of the font to use */
family?: keyof typeof fontFamily;
family?: keyof FontUtilsType['fontFamily']['platform'];
marcaaron marked this conversation as resolved.
Show resolved Hide resolved
};

function Text({color, fontSize = variables.fontSizeNormal, textAlign = 'left', children, family = 'EXP_NEUE', style = {}, ...props}: TextProps, ref: ForwardedRef<RNText>) {
Expand All @@ -32,7 +33,7 @@ function Text({color, fontSize = variables.fontSizeNormal, textAlign = 'left', c
color: color ?? theme.text,
fontSize,
textAlign,
fontFamily: fontFamily[family],
fontFamily: FontUtils.fontFamily.platform[family],
...StyleSheet.flatten(style),
};

Expand Down
7 changes: 4 additions & 3 deletions src/components/ThemeIllustrationsProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, {useMemo} from 'react';
import useThemePreference from '@hooks/useThemePreference';
import ThemeIllustrationsContext from '@styles/theme/context/ThemeIllustrationsContext';
import Illustrations from '@styles/theme/illustrations';
// eslint-disable-next-line no-restricted-imports
import illustrations from '@styles/theme/illustrations';

type ThemeIllustrationsProviderProps = {
children: React.ReactNode;
Expand All @@ -10,9 +11,9 @@ type ThemeIllustrationsProviderProps = {
function ThemeIllustrationsProvider({children}: ThemeIllustrationsProviderProps) {
const themePreference = useThemePreference();

const illustrations = useMemo(() => Illustrations[themePreference], [themePreference]);
const themeIllustrations = useMemo(() => illustrations[themePreference], [themePreference]);

return <ThemeIllustrationsContext.Provider value={illustrations}>{children}</ThemeIllustrationsContext.Provider>;
return <ThemeIllustrationsContext.Provider value={themeIllustrations}>{children}</ThemeIllustrationsContext.Provider>;
}

ThemeIllustrationsProvider.displayName = 'ThemeIllustrationsProvider';
Expand Down
1 change: 1 addition & 0 deletions src/components/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import useThemePreferenceWithStaticOverride from '@hooks/useThemePreferenceWithStaticOverride';
// eslint-disable-next-line no-restricted-imports
import themes from '@styles/theme';
import ThemeContext from '@styles/theme/context/ThemeContext';
import type {ThemePreferenceWithoutSystem} from '@styles/theme/types';
Expand Down
10 changes: 6 additions & 4 deletions src/components/ThemeStylesProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import React, {useMemo} from 'react';
import useTheme from '@hooks/useTheme';
import stylesGenerator from '@styles/index';
// eslint-disable-next-line no-restricted-imports
import styles from '@styles/index';
import ThemeStylesContext from '@styles/theme/context/ThemeStylesContext';
// eslint-disable-next-line no-restricted-imports
import createStyleUtils from '@styles/utils';

type ThemeStylesProviderProps = React.PropsWithChildren;

function ThemeStylesProvider({children}: ThemeStylesProviderProps) {
const theme = useTheme();

const styles = useMemo(() => stylesGenerator(theme), [theme]);
const StyleUtils = useMemo(() => createStyleUtils(theme, styles), [theme, styles]);
const contextValue = useMemo(() => ({styles, StyleUtils}), [styles, StyleUtils]);
const themeStyles = useMemo(() => styles(theme), [theme]);
const StyleUtils = useMemo(() => createStyleUtils(theme, themeStyles), [theme, themeStyles]);
chrispader marked this conversation as resolved.
Show resolved Hide resolved
const contextValue = useMemo(() => ({styles: themeStyles, StyleUtils}), [themeStyles, StyleUtils]);

return <ThemeStylesContext.Provider value={contextValue}>{children}</ThemeStylesContext.Provider>;
}
Expand Down
4 changes: 3 additions & 1 deletion src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {memo, useEffect, useRef} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {withOnyx} from 'react-native-onyx';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import KeyboardShortcut from '@libs/KeyboardShortcut';
Expand Down Expand Up @@ -130,8 +131,9 @@ const modalScreenListeners = {

function AuthScreens({lastUpdateIDAppliedToClient, session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = false}: AuthScreensProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth} = useWindowDimensions();
const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles);
const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils);
const isInitialRender = useRef(true);

if (isInitialRender.current) {
Expand Down
chrispader marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type {StackCardInterpolatedStyle, StackCardInterpolationProps} from '@react-navigation/stack';
import {Animated} from 'react-native';
import type {StyleUtilsType} from '@styles/utils';
import variables from '@styles/variables';

type ModalCardStyleInterpolator = (
isSmallScreenWidth: boolean,
isFullScreenModal: boolean,
stackCardInterpolationProps: StackCardInterpolationProps,
outputRangeMultiplier?: number,
) => StackCardInterpolatedStyle;
type CreateModalCardStyleInterpolator = (StyleUtils: StyleUtilsType) => ModalCardStyleInterpolator;

const createModalCardStyleInterpolator: CreateModalCardStyleInterpolator =
(StyleUtils) =>
(isSmallScreenWidth, isFullScreenModal, {current: {progress}, inverted, layouts: {screen}}, outputRangeMultiplier = 1) => {
const translateX = Animated.multiply(
progress.interpolate({
inputRange: [0, 1],
outputRange: [outputRangeMultiplier * (isSmallScreenWidth ? screen.width : variables.sideBarWidth), 0],
extrapolate: 'clamp',
}),
inverted,
);

const cardStyle = StyleUtils.getCardStyles(screen.width);

if (!isFullScreenModal || isSmallScreenWidth) {
cardStyle.transform = [{translateX}];
}

return {
containerStyle: {
overflow: 'hidden',
},
cardStyle,
};
};

export default createModalCardStyleInterpolator;
138 changes: 73 additions & 65 deletions src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type {StackCardInterpolationProps, StackNavigationOptions} from '@react-navigation/stack';
import type {ThemeStyles} from '@styles/index';
import getNavigationModalCardStyle from '@styles/utils/getNavigationModalCardStyles';
import type {StyleUtilsType} from '@styles/utils';
import variables from '@styles/variables';
import CONFIG from '@src/CONFIG';
import modalCardStyleInterpolator from './modalCardStyleInterpolator';
import createModalCardStyleInterpolator from './createModalCardStyleInterpolator';

type ScreenOptions = Record<string, StackNavigationOptions>;

Expand All @@ -17,75 +17,83 @@ const commonScreenOptions: StackNavigationOptions = {

const SLIDE_LEFT_OUTPUT_RANGE_MULTIPLIER = -1;

export default (isSmallScreenWidth: boolean, themeStyles: ThemeStyles): ScreenOptions => ({
rightModalNavigator: {
...commonScreenOptions,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),
presentation: 'transparentModal',

// We want pop in RHP since there are some flows that would work weird otherwise
animationTypeForReplace: 'pop',
cardStyle: {
...getNavigationModalCardStyle(),

// This is necessary to cover translated sidebar with overlay.
width: isSmallScreenWidth ? '100%' : '200%',
// Excess space should be on the left so we need to position from right.
right: 0,
type GetRootNavigatorScreenOptions = (isSmallScreenWidth: boolean, styles: ThemeStyles, StyleUtils: StyleUtilsType) => ScreenOptions;

const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScreenWidth, themeStyles, StyleUtils) => {
const modalCardStyleInterpolator = createModalCardStyleInterpolator(StyleUtils);

return {
rightModalNavigator: {
...commonScreenOptions,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),
presentation: 'transparentModal',

// We want pop in RHP since there are some flows that would work weird otherwise
animationTypeForReplace: 'pop',
cardStyle: {
...StyleUtils.getNavigationModalCardStyle(),

// This is necessary to cover translated sidebar with overlay.
width: isSmallScreenWidth ? '100%' : '200%',
// Excess space should be on the left so we need to position from right.
right: 0,
},
},
},
leftModalNavigator: {
...commonScreenOptions,
cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props, SLIDE_LEFT_OUTPUT_RANGE_MULTIPLIER),
presentation: 'transparentModal',

// We want pop in LHP since there are some flows that would work weird otherwise
animationTypeForReplace: 'pop',
cardStyle: {
...getNavigationModalCardStyle(),

// This is necessary to cover translated sidebar with overlay.
width: isSmallScreenWidth ? '100%' : '200%',

// LHP should be displayed in place of the sidebar
left: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
leftModalNavigator: {
...commonScreenOptions,
cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, props, SLIDE_LEFT_OUTPUT_RANGE_MULTIPLIER),
presentation: 'transparentModal',

// We want pop in LHP since there are some flows that would work weird otherwise
animationTypeForReplace: 'pop',
cardStyle: {
...StyleUtils.getNavigationModalCardStyle(),

// This is necessary to cover translated sidebar with overlay.
width: isSmallScreenWidth ? '100%' : '200%',

// LHP should be displayed in place of the sidebar
left: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
},
},
},
homeScreen: {
title: CONFIG.SITE_TITLE,
...commonScreenOptions,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),

cardStyle: {
...getNavigationModalCardStyle(),
width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,

// We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
...(isSmallScreenWidth ? {} : themeStyles.borderRight),
homeScreen: {
title: CONFIG.SITE_TITLE,
...commonScreenOptions,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, props),

cardStyle: {
...StyleUtils.getNavigationModalCardStyle(),
width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,

// We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
...(isSmallScreenWidth ? {} : themeStyles.borderRight),
},
},
},

fullScreen: {
...commonScreenOptions,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
cardStyle: {
...getNavigationModalCardStyle(),
fullScreen: {
...commonScreenOptions,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
cardStyle: {
...StyleUtils.getNavigationModalCardStyle(),

// This is necessary to cover whole screen. Including translated sidebar.
marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
// This is necessary to cover whole screen. Including translated sidebar.
marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
},
},
},

centralPaneNavigator: {
title: CONFIG.SITE_TITLE,
...commonScreenOptions,
animationEnabled: isSmallScreenWidth,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),
centralPaneNavigator: {
title: CONFIG.SITE_TITLE,
...commonScreenOptions,
animationEnabled: isSmallScreenWidth,
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, props),

cardStyle: {
...getNavigationModalCardStyle(),
paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth,
cardStyle: {
...StyleUtils.getNavigationModalCardStyle(),
paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth,
},
},
},
});
};
};

export default getRootNavigatorScreenOptions;
Loading
Loading