Skip to content

Commit

Permalink
theme provider
Browse files Browse the repository at this point in the history
  • Loading branch information
jgdevelopment committed Jun 12, 2023
1 parent fd90e2e commit 9f85b23
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 21 deletions.
14 changes: 7 additions & 7 deletions built/src/components/Button/IconButton/IconButton.styles.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ export declare const GHOST_ICON_BUTTON_CSS: ({ $type, $forceTheme }: {
}, any>>;
export declare const ICON_BUTTON_VARIANT_CSS: ({ $variant }: {
$variant: FilledVariant;
}) => (({ $type }: {
$type: Type;
$forceTheme?: ThemeMode | undefined;
}) => ({ $forceTheme }: {
$forceTheme?: ThemeMode | undefined;
}) => import("styled-components").FlattenSimpleInterpolation) | (({ $type, $forceTheme }: {
}) => (({ $type, $forceTheme }: {
$type: IconButtonType;
$forceTheme?: ThemeMode | undefined;
}) => import("styled-components").FlattenInterpolation<import("styled-components").ThemedStyledProps<{
$forceTheme?: ThemeMode | undefined;
}, any>>);
}, any>>) | (({ $type }: {
$type: Type;
$forceTheme?: ThemeMode | undefined;
}) => ({ $forceTheme }: {
$forceTheme?: ThemeMode | undefined;
}) => import("styled-components").FlattenSimpleInterpolation);
//# sourceMappingURL=IconButton.styles.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions built/src/theme/AppThemeProvider.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { LocalStorageThemeMode, ThemeMode } from '../types';
import { LocalStorageThemeMode, ThemeMode } from 'src/types';
export declare const THEME_SELECT_VERSION = "0.1.0";
export declare function isOfTypeThemeName(keyInput: LocalStorageThemeMode): boolean;
type ThemeContextType = {
Expand All @@ -10,9 +10,6 @@ type ThemeContextType = {
export declare const ThemeContext: React.Context<ThemeContextType>;
export declare const useTheme: () => ThemeContextType;
export declare const THEME_LOCAL_STORAGE_KEY = "THEME_MODE";
interface Props {
children: React.ReactNode;
}
export declare const AppThemeProvider: React.FC<Props>;
export declare const AppThemeProvider: React.FC;
export {};
//# sourceMappingURL=AppThemeProvider.d.ts.map
2 changes: 1 addition & 1 deletion built/src/theme/AppThemeProvider.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions built/src/theme/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { AppThemeProvider, isOfTypeThemeName, ThemeContext, THEME_LOCAL_STORAGE_KEY, THEME_SELECT_VERSION, useTheme } from './AppThemeProvider';
export * from './theme';
//# sourceMappingURL=index.d.ts.map
2 changes: 1 addition & 1 deletion built/src/theme/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions built/src/utils/colorUtils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ declare const ACCENT_COLORS: readonly ["green", "orange", "red", "yellow", "pink
export type AccentColor = (typeof ACCENT_COLORS)[number];
export type TextColor = (typeof TEXT_COLORS)[number];
export type Color = TextColor | AccentColor;
export declare const isAccentColor: (color: Color) => color is "green" | "orange" | "red" | "yellow" | "pink" | "dark-blue" | "blue";
export declare const isTextColor: (color: Color) => color is "link" | "disabled" | "primary" | "secondary" | "tertiary" | "destructive" | "inverse" | "white" | "black";
export declare const isColor: (color: string) => color is "green" | "orange" | "red" | "yellow" | "pink" | "dark-blue" | "blue";
export declare const isAccentColor: (color: Color) => color is "blue" | "green" | "orange" | "pink" | "red" | "yellow" | "dark-blue";
export declare const isTextColor: (color: Color) => color is "link" | "black" | "white" | "disabled" | "secondary" | "primary" | "tertiary" | "destructive" | "inverse";
export declare const isColor: (color: string) => color is "blue" | "green" | "orange" | "pink" | "red" | "yellow" | "dark-blue";
/** [primary, secondary, accent] */
type ColorOptions = [string, string, AccentColor];
export declare const TEXT_COLOR_VALUES: Record<TextColor, string>;
export declare const ACCENT_COLOR_VALUES: Record<AccentColor, ColorOptions>;
export declare const CorrectedColorSelect: Record<string, string>;
export declare const accentColorToPrimaryColor: Record<"green" | "orange" | "red" | "yellow" | "pink" | "dark-blue" | "blue", string>;
export declare const accentColorToPrimaryColor: Record<"blue" | "green" | "orange" | "pink" | "red" | "yellow" | "dark-blue", string>;
/**
* Given an color in form var(--color), return the inner --color
*/
Expand Down
2 changes: 1 addition & 1 deletion built/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@skiff-org/skiff-ui",
"version": "1.1.6",
"version": "1.2.1",
"prepublish": "tsc",
"main": "./src/index.ts",
"module": "./built/src/index.d.ts",
Expand Down
107 changes: 107 additions & 0 deletions src/theme/AppThemeProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import noop from 'lodash/noop';
import React, { createContext, useCallback, useContext, useEffect, useState } from 'react';
import { LocalStorageThemeMode, StorageOnlyThemeMode, ThemeMode } from 'src/types';
import { createGlobalStyle, ThemeProvider } from 'styled-components';

import { themeNames } from './theme';

export const THEME_SELECT_VERSION = '0.1.0';

// validate type (necessary if older theme still stored in local storage)
export function isOfTypeThemeName(keyInput: LocalStorageThemeMode) {
return keyInput === ThemeMode.LIGHT || keyInput === ThemeMode.DARK;
}

type ThemeContextType = {
// displayed theme
theme: ThemeMode;
// theme in local storage
storedTheme: LocalStorageThemeMode;
// update theme in local storage
setStoredTheme: (name: LocalStorageThemeMode) => void;
};

export const ThemeContext = createContext<ThemeContextType>({
theme: ThemeMode.LIGHT,
storedTheme: StorageOnlyThemeMode.SYSTEM,
setStoredTheme: noop
});

export const useTheme = () => useContext(ThemeContext);

export const THEME_LOCAL_STORAGE_KEY = 'THEME_MODE';

const GlobalStyles = createGlobalStyle`
body {
font-family: 'Skiff Sans Text', sans-serif;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
}
`;
export const AppThemeProvider: React.FC = ({ children }) => {
const [themeName, setThemeName] = useState<ThemeMode>(ThemeMode.DARK);
const [storedThemeState, setStoredThemeState] = useState<LocalStorageThemeMode>(StorageOnlyThemeMode.SYSTEM);

let darkSystemThemeMediaQuery: MediaQueryList | undefined;
if (typeof window !== 'undefined') {
darkSystemThemeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
}

const updateRootData = (theme: ThemeMode) => {
const themeColor = themeNames[theme];
Object.keys(themeColor).forEach((key) => {
document.body.style.setProperty(key, themeColor[key]);
});
};

const updateThemeName = useCallback(
(name: LocalStorageThemeMode, darkSystemThemeMediaQuery?: MediaQueryList) => {
setStoredThemeState(name);
// if name is light or dark, set it to theme
if (isOfTypeThemeName(name)) {
setThemeName(name as ThemeMode);
updateRootData(name as ThemeMode);
} else if (darkSystemThemeMediaQuery !== undefined) {
// otherwise parse the system theme
const themeMode = darkSystemThemeMediaQuery.matches ? ThemeMode.DARK : ThemeMode.LIGHT;
setThemeName(themeMode);
updateRootData(themeMode);
}
},
[darkSystemThemeMediaQuery]
);

const setStoredTheme = (name: LocalStorageThemeMode) => {
// update local storage
localStorage.setItem(THEME_LOCAL_STORAGE_KEY, name);
updateThemeName(name, darkSystemThemeMediaQuery);
};

// Get theme from localStorage when app loads
useEffect(() => {
// if nothing stored default to system
const storedThemeMode = (localStorage.getItem(THEME_LOCAL_STORAGE_KEY) as ThemeMode) || StorageOnlyThemeMode.SYSTEM;
updateThemeName(storedThemeMode, darkSystemThemeMediaQuery);
}, []);

// Listen to live system changes
useEffect(() => {
if (storedThemeState !== StorageOnlyThemeMode.SYSTEM || darkSystemThemeMediaQuery === undefined) return;
const updateSystemTheme = () => updateThemeName(StorageOnlyThemeMode.SYSTEM, darkSystemThemeMediaQuery);
darkSystemThemeMediaQuery.addEventListener('change', updateSystemTheme);
return () => {
if (darkSystemThemeMediaQuery === undefined) return;
darkSystemThemeMediaQuery.removeEventListener('change', updateSystemTheme);
};
}, [storedThemeState, darkSystemThemeMediaQuery, updateThemeName]);

// updated `theme` object will be defined by design system and used here
return (
<ThemeProvider theme={{}}>
<ThemeContext.Provider value={{ theme: themeName, setStoredTheme, storedTheme: storedThemeState }}>
<GlobalStyles />
{children}
</ThemeContext.Provider>
</ThemeProvider>
);
};
8 changes: 8 additions & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
export {
AppThemeProvider,
isOfTypeThemeName,
ThemeContext,
THEME_LOCAL_STORAGE_KEY,
THEME_SELECT_VERSION,
useTheme
} from './AppThemeProvider';
export * from './theme';

0 comments on commit 9f85b23

Please sign in to comment.