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

[POC] Emotion Themes #387

Closed
wants to merge 12 commits into from
Closed
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
4 changes: 3 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@typescript-eslint/naming-convention": "off",
"@typescript-eslint/no-shadow": "error",
"@typescript-eslint/no-use-before-define": "error",
"arrow-parens": "off",
"no-shadow": "off",
"no-use-before-define": "off",
"react/jsx-filename-extension": ["warn", { "extensions": [".js", ".tsx"] }],
Expand All @@ -56,7 +57,8 @@
"emotion/jsx-import": "error",
"emotion/no-vanilla": "error",
"emotion/import-from-emotion": "error",
"emotion/styled-import": "error"
"emotion/styled-import": "error",
"react/jsx-props-no-spreading": "off"
}
},
{
Expand Down
135 changes: 75 additions & 60 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,89 @@
import { useState } from 'react';
import { addDecorator, addParameters, configure } from '@storybook/react';
import { withA11y } from '@storybook/addon-a11y';
import { addReadme, configureReadme } from 'storybook-readme';
import centered from '@storybook/addon-centered/react';
import { Global, css } from '@emotion/core';
import { ThemeProvider } from 'emotion-theming';
import Theme from './theme';
import {
resetStyles,
brandStyles,
} from '../src/utils/injectGlobalStyles/style';
import { primaryTheme, secondaryTheme } from '../src/constants/themes';

const InjectGlobalStyles = (storyFn) => (
<div
css={css`
padding: 1rem;
`}
>
<Global styles={resetStyles} />
<Global styles={brandStyles} />
<Global
styles={css`
@font-face {
font-family: 'nocturno';
src: url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.eot');
src: url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.eot?#iefix')
format('embedded-opentype'),
url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.woff2')
format('woff2'),
url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.woff')
format('woff'),
url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.svg#Typotheque_webfonts_service')
format('svg');
}
`}
/>
<Global
styles={css`
@font-face {
font-family: 'larssiet';
src: url('https://assets.curology.com/fonts/larssiet/34535B_1_0.eot');
src: url('https://assets.curology.com/fonts/larssiet/34535B_1_0.eot?#iefix')
format('embedded-opentype'),
url('https://assets.curology.com/fonts/larssiet/34535B_1_0.woff2')
format('woff2'),
url('https://assets.curology.com/fonts/larssiet/34535B_1_0.woff')
format('woff'),
url('https://assets.curology.com/fonts/larssiet/34535B_1_0.ttf')
format('truetype');
}
`}
/>
<Global
styles={css`
@font-face {
font-family: 'larssiet';
font-weight: bold;
src: url('https://assets.curology.com/fonts/larssiet/34535B_0_0.eot');
src: url('https://assets.curology.com/fonts/larssiet/34535B_0_0.eot?#iefix')
format('embedded-opentype'),
url('https://assets.curology.com/fonts/larssiet/34535B_0_0.woff2')
format('woff2'),
url('https://assets.curology.com/fonts/larssiet/34535B_0_0.woff')
format('woff'),
url('https://assets.curology.com/fonts/larssiet/34535B_0_0.ttf')
format('truetype');
}
const InjectGlobalStyles = (storyFn) => {
const [theme, setTheme] = useState(primaryTheme);

const toggleTheme = () =>
theme.__type === 'primary'
? setTheme(secondaryTheme)
: setTheme(primaryTheme);

return (
<div
css={css`
padding: 1rem;
`}
/>
{storyFn()}
</div>
);
>
<Global styles={resetStyles} />
<Global styles={brandStyles} />
<Global
styles={css`
@font-face {
font-family: 'nocturno';
src: url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.eot');
src: url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.eot?#iefix')
format('embedded-opentype'),
url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.woff2')
format('woff2'),
url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.woff')
format('woff'),
url('https://s3-us-west-1.amazonaws.com/fonts-california.typotheque.com/WF-029669-009918-001560-fa6dd062b0c32d6d9a297bd175bb0381.svg#Typotheque_webfonts_service')
format('svg');
}
`}
/>
<Global
styles={css`
@font-face {
font-family: 'larssiet';
src: url('https://assets.curology.com/fonts/larssiet/34535B_1_0.eot');
src: url('https://assets.curology.com/fonts/larssiet/34535B_1_0.eot?#iefix')
format('embedded-opentype'),
url('https://assets.curology.com/fonts/larssiet/34535B_1_0.woff2')
format('woff2'),
url('https://assets.curology.com/fonts/larssiet/34535B_1_0.woff')
format('woff'),
url('https://assets.curology.com/fonts/larssiet/34535B_1_0.ttf')
format('truetype');
}
`}
/>
<Global
styles={css`
@font-face {
font-family: 'larssiet';
font-weight: bold;
src: url('https://assets.curology.com/fonts/larssiet/34535B_0_0.eot');
src: url('https://assets.curology.com/fonts/larssiet/34535B_0_0.eot?#iefix')
format('embedded-opentype'),
url('https://assets.curology.com/fonts/larssiet/34535B_0_0.woff2')
format('woff2'),
url('https://assets.curology.com/fonts/larssiet/34535B_0_0.woff')
format('woff'),
url('https://assets.curology.com/fonts/larssiet/34535B_0_0.ttf')
format('truetype');
}
`}
/>
<ThemeProvider theme={theme}>
<button onClick={toggleTheme}>Swap Theme</button>
{storyFn()}
</ThemeProvider>
</div>
);
};

addDecorator(InjectGlobalStyles);
addDecorator(centered);
Expand Down Expand Up @@ -105,7 +120,7 @@ addParameters({
},
});

const req = require.context('../stories', true, /.(ts|tsx|js)$/);
const req = require.context('../stories/toggle', true, /.(ts|tsx|js)$/);
function loadStories() {
req.keys().forEach(req);
}
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,10 @@
"yarn-run-all": "^3.1.1"
},
"dependencies": {
"@emotion/core": "^10.0.35",
"@emotion/styled": "^10.0.27",
"@emotion/core": "10.0.35",
"@emotion/styled": "10.0.27",
"@react-aria/focus": "^3.0.2",
"emotion-theming": "10.0.27",
"lodash.round": "^4.0.4",
"lodash.throttle": "^4.1.1",
"lodash.uniqueid": "^4.0.1",
Expand All @@ -146,6 +147,7 @@
"peerDependencies": {
"@emotion/core": "10.0.35",
"@emotion/styled": "10.0.27",
"emotion-theming": "10.0.27",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
Expand Down
60 changes: 60 additions & 0 deletions src/constants/colors/primary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import PropTypes from 'prop-types';

import COLORS from '.';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/constants/colors/index.ts is unchanged to keep the diff to a minimum, but introducing full theming support would require making changes to that file as well. We'd want to disallow access to COLORS directly except under specific circumstances.

I think our goal should be to make opting-in to the Theme as easy as possible. Personally I've already enjoyed not needing to import COLORS and just access it (and already typed!) off of a theme.


const PRIMARY_COLORS = {
// brand colors
primary: COLORS.purple100,
primaryTint1: COLORS.purple85,
primaryTint2: COLORS.purple70,
primaryTint3: COLORS.purple30,
secondary: COLORS.lavender100,
tertiary: COLORS.purple4,

// general colors
success: COLORS.statusGreen,
successBackground: COLORS.statusGreenBackground,
successBorder: COLORS.statusGreenBorder,
info: COLORS.statusPurple,
infoBackground: COLORS.statusPurpleBackground,
infoBorder: COLORS.statusPurpleBorder,
error: COLORS.statusRed,
errorBackground: COLORS.statusRedBackground,
errorBorder: COLORS.statusRedBorder,
default: COLORS.purple70,
defaultBackground: COLORS.purple10,
defaultBorder: COLORS.purple15,
accent: COLORS.red,
disabled: COLORS.purple10,
failure: COLORS.red,
hover: COLORS.purple4,
warning: COLORS.yellowLight,

// ui colors
background: COLORS.purple4,
backgroundDark: COLORS.purple4,
border: COLORS.purple10,
divider: COLORS.purple10,

// form colors
radioBorder: COLORS.purple30,
radioBorderSelected: COLORS.lavender100,

// typography
textMuted: COLORS.purple70,
textGhost: COLORS.purple30,
textDisabled: COLORS.purple30,

// overlay
overlay: 'rgba(45, 45, 48, 0.7)',
overlaySolid: 'rgba(45, 45, 48, 1)',

black: COLORS.black,
white: COLORS.white,
};

export const PRIMARY_COLORS_PROP_TYPES = PropTypes.oneOf(
Object.values(PRIMARY_COLORS),
);

export default PRIMARY_COLORS;
60 changes: 60 additions & 0 deletions src/constants/colors/secondary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import PropTypes from 'prop-types';

import { COLORS } from '..';

const SECONDARY_COLORS = {
// brand colors
primary: null,
primaryTint1: '#000000',
primaryTint2: null,
primaryTint3: '#cccccc',
secondary: '#414a4c',
tertiary: null,

// general colors
success: null,
successBackground: null,
successBorder: null,
info: null,
infoBackground: null,
infoBorder: null,
error: null,
errorBackground: null,
errorBorder: null,
default: null,
defaultBackground: null,
defaultBorder: null,
accent: null,
disabled: null,
failure: null,
hover: null,
warning: null,

// ui colors
background: null,
backgroundDark: null,
border: null,
divider: null,

// form colors
radioBorder: null,
radioBorderSelected: null,

// typography
textMuted: null,
textGhost: null,
textDisabled: null,

// overlay
overlay: null,
overlaySolid: null,

black: COLORS.black,
white: COLORS.white,
};

export const SECONDARY_COLORS_PROP_TYPES = PropTypes.oneOf(
Object.values(SECONDARY_COLORS),
);

export default SECONDARY_COLORS;
10 changes: 10 additions & 0 deletions src/constants/colors/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import PRIMARY_COLORS from './primary';
import SECONDARY_COLORS from './secondary';

describe('theme colors', () => {
it('primary and secondary colors have the same number of properties', () => {
expect(Object.keys(PRIMARY_COLORS).length).toEqual(
Object.keys(SECONDARY_COLORS).length,
);
});
});
2 changes: 2 additions & 0 deletions src/constants/themes/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as primaryTheme } from './primary';
export { default as secondaryTheme } from './secondary';
7 changes: 7 additions & 0 deletions src/constants/themes/primary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import PRIMARY_COLORS from '../colors/primary';

export default {
__type: 'primary',
BOX_SHADOW: {},
COLORS: PRIMARY_COLORS,
} as const;
7 changes: 7 additions & 0 deletions src/constants/themes/secondary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import SECONDARY_COLORS from '../colors/secondary';

export default {
__type: 'secondary',
BOX_SHADOW: {},
COLORS: SECONDARY_COLORS,
} as const;
14 changes: 14 additions & 0 deletions src/constants/themes/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import primaryTheme from './primary';
import secondaryTheme from './secondary';

type BoxShadow =
| typeof primaryTheme['BOX_SHADOW']
| typeof secondaryTheme['BOX_SHADOW'];

type Colors = typeof primaryTheme['COLORS'] | typeof secondaryTheme['COLORS'];

export type ThemeType = {
__type: 'primary' | 'secondary';
BOX_SHADOW: BoxShadow;
COLORS: Colors;
};
Loading