@andrewizbatista/themes v0.4.2
@andrewizbatista/themes
Enhanced way of managing Material UI 5 (with Emotion) themes.
Table of Contents
Getting Started
Prerequisites
This package has peerDependencies
that are required for you to include in your app's dependencies
:
{
"dependencies": {
"@mui/material": "^5.1.1",
"next": "^12.0.4",
"react": "^17.0.2"
}
}
Installing
yarn
yarn add @andrewizbatista/themes
npm
npm install @andrewizbatista/themes
Usage
1. Define your Theme
related types
It's required that you define these types so TypeScript can do its magic.
// src/themes/types.ts
/**
* Names of the themes you support in your app.
*/
export type ThemeNames = 'foo' | 'bar';
/**
* Keys for all the assets you support in your app.
*/
export type AssetKeys = 'companyLogo' | 'heroImage';
2. Create your Theme(s)
Create all the themes you want your app to support. These themes are Material UI v5 Themes with an additional assets
prop which allows you to have different images between themes and even modes (Light/Dark).
// src/themes/foo/index.ts
import { createTheme } from '@andrewizbatista/themes';
/**
* Tip: Divide your theme into multiple files
* because Material themes can get big.
*/
import { paletteLight, paletteDark } from './palette';
import { assetsLight, assetsDark } from './assets';
import { typography } from './typography';
// Types
import { ThemeNames, AssetKeys } from './types';
/**
* Foo Theme
*/
export const fooTheme = createTheme<ThemeNames, AssetKeys>({
name: 'foo',
dark: {
palette: paletteDark,
assets: assetsDark,
typography
},
light: {
palette: paletteLight,
assets: assetsLight,
typography
},,
});
3. Create your ThemeContext
Feed all the themes you defined into your context and set some defaults.
// src/themes/index.ts
import { createThemeContext } from '@andrewizbatista/themes';
// Themes
import { fooTheme } from './foo';
import { barTheme } from './bar';
// Types
import { ThemeNames, AssetKeys } from './types';
/**
* ThemeContext
*/
export const { ThemeContext, ThemeProvider, useTheme } = createThemeContext<ThemeNames, AssetKeys>({
defaultTheme: 'foo',
defaultThemeMode: 'dark',
themes: {
foo: fooTheme,
bar: barTheme,
},
});
4. Support Next.js SSR (Server Side Rendering)
4.1. Changes in the Document (_document.tsx
)
For your Next.js app to support SSR you have to add an Emotion Cache to the NextDocument.getInitialProps
.
I've included a function that does exactly that. See getInitialPropsWithEmotionServer
for the full breakdown.
// pages/_document.tsx
import NextDocument, { DocumentContext, Html, Main, Head, NextScript } from 'next/document';
import { getInitialPropsWithEmotionServer } from '@andrewizbatista/themes';
export default class Document extends NextDocument {
static async getInitialProps(ctx: DocumentContext) {
return getInitialPropsWithEmotionServer(ctx, 'css'); // 'css' is the Emotion Cache Key
}
public render() {
return (
<Html lang="en">
<Head>
{...}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
4.2. Changes in the App (_app.tsx
)
We provide a type AppWithEmotionProps
that is extensible and already supports the emotionCache
prop. Also don't forget to wrap your app with the ThemeProvider
// pages/_app.tsx
import { AppWithEmotionProps } from '@andrewizbatista/themes';
import { ThemeProvider } from 'src/themes';
export default function App({
Component,
pageProps,
emotionCache,
}: AppWithEmotionProps<PageProps>) {
const { myCustomProp } = pageProps;
return (
<ThemeProvider emotionCache={emotionCache}>
<Component {...pageProps} />
</ThemeProvider>
);
}
/**
* Additional props you might have in `pageProps`
*/
interface PageProps {
myCustomProp: string;
}
5. Use the useTheme
hook
With your app wrapped with the ThemeProvider
you can now use the useTheme
hook everywhere you want.
const MyComponent = () => {
const {
state: { palette, assets },
actions: { changeTheme, toggleThemeMode },
} = useTheme();
return (
<Box>
<Image src={assets.companyLogo} />
<Button color={palette.primary.main} onClick={() => changeTheme('bar')}>
Change Theme to Bar
</Button>
<Button color={palette.secondary.main} onClick={toggleThemeMode}>
Toggle Light/Dark Mode
</Button>
</Box>
);
};
Contributing
Want to help? Feel free to open an Issue or create a Pull Request and let's get started 🚀
License
MIT © André Batista (@andrewizbatista)