Skip to content

Commit

Permalink
feat: Make themes use inheritance. (#241)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Theme is now an abstract base class instead of an interface, and themes' names have changed. Please also note that you now must create an instance of a theme using new.
  • Loading branch information
goloroden authored Jan 23, 2020
1 parent be23724 commit 00a43ee
Show file tree
Hide file tree
Showing 25 changed files with 657 additions and 392 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ thenativeweb-ux provides UI components for the native web applications.
| Dev dependencies | ![David](https://img.shields.io/david/dev/thenativeweb/thenativeweb-ux) |
| Build | ![GitHub Actions](https://github.com/thenativeweb/thenativeweb-ux/workflows/Release/badge.svg?branch=master) |
| License | ![GitHub](https://img.shields.io/github/license/thenativeweb/thenativeweb-ux) |

## Installation

```shell
Expand Down
2 changes: 1 addition & 1 deletion lib/components/branding/Product/Documentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const Documentation = (): ReactElement => (

<ComponentPreview>
<div>
<ThemeProvider theme={ themes.wolkenkit }>
<ThemeProvider theme={ new themes.Wolkenkit() }>
<div style={{ background: 'rgb(47, 51, 59)' }}>
<Product name='wolkenkit' />
<hr />
Expand Down
4 changes: 2 additions & 2 deletions lib/components/branding/Product/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ const Product: FunctionComponent<ProductProps> = ({
let nameComponent = <div className={ classes.Name }>{ name }</div>;
let Logo = LogoTheNativeWeb;

if (theme.name === 'wolkenkit' || name === 'wolkenkit') {
if (theme.name === 'Wolkenkit' || name === 'wolkenkit') {
Logo = LogoWolkenkit;
}
if ((theme.name === 'wolkenkit' && !name) || name === 'wolkenkit') {
if ((theme.name === 'Wolkenkit' && !name) || name === 'wolkenkit') {
nameComponent = <div className={ classes.CompositeName }><span>wolken</span>kit</div>;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/components/documentation/ComponentPreview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const ComponentPreview: FunctionComponent<ComponentPreviewProps> = ({

<hr />

<ThemeProvider theme={ themes.wolkenkit }>
<ThemeProvider theme={ new themes.Wolkenkit() }>
<div>
{ children }
</div>
Expand Down
8 changes: 4 additions & 4 deletions lib/components/roots/ThemeProvider/Documentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ const Documentation = (): ReactElement => (

<Paragraph>
By default the <code>ThemeProvider</code> will use the default
theme called <code>thenativeweb</code>. To apply the wolkenkit theme,
import the <code>themes</code> object and
pass <code>themes.wolkenkit</code> as the <code>theme</code> property.
theme called <code>TheNativeWeb</code>. To apply the wolkenkit theme,
import the <code>themes</code> object and pass a new instance
of <code>themes.Wolkenkit</code> as the <code>theme</code> property.
</Paragraph>

<ComponentPreview>
<div style={{ position: 'relative', width: '100%', height: '100%', border: '1px solid black' }}>
<ThemeProvider theme={ themes.wolkenkit }>
<ThemeProvider theme={ new themes.Wolkenkit() }>
<Application useNotifications={ false } useDialogs={ false }>
<Sidebar>
<SidebarBrand><Product name='my-app' /></SidebarBrand>
Expand Down
2 changes: 1 addition & 1 deletion lib/components/roots/ThemeProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface ThemeProviderProps {
theme?: Theme;
}

const ThemeProvider: FunctionComponent<ThemeProviderProps> = ({ theme = themes.thenativeweb, children }): ReactElement => (
const ThemeProvider: FunctionComponent<ThemeProviderProps> = ({ theme = new themes.TheNativeWeb(), children }): ReactElement => (
<JssThemeProvider theme={ theme }>{children}</JssThemeProvider>
);

Expand Down
4 changes: 1 addition & 3 deletions lib/styles/Documentation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import React, { ReactElement } from 'react';

const Documentation = (): ReactElement => (
<React.Fragment>
<Headline>styles</Headline>

<Headline level='2'>Creating custom components</Headline>
<Headline>Creating custom components</Headline>

<Paragraph>
<code>thenativeweb-ux</code> uses <Link href='https://cssinjs.org'>JSS</Link> and <Link href='https://github.com/JedWatson/classnames'>classnames</Link> to
Expand Down
139 changes: 139 additions & 0 deletions lib/themes/Documentation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { SplitView } from '../../components/documentation/SplitView';
import { Button, Code, Headline, Paragraph, ThemeProvider } from '../..';
import { customThemeThatExtendsBaseTheme, CustomThemeThatExtendsWolkenkit } from './themes';
import React, { ReactElement } from 'react';

const Documentation = (): ReactElement => (
<React.Fragment>
<Headline>Creating custom themes</Headline>

<Paragraph>
<code>thenativeweb-ux</code> comes with two default
themes, <code>themes.TheNativeWeb</code> and <code>themes.Wolkenkit</code>. Both of
them extend the abstract class <code>Theme</code>.
</Paragraph>

<Paragraph>
In order to create a custom theme, you have two options: create a new
theme by extending the abstract <code>Theme</code> or extending one of
the default themes.
</Paragraph>

<Headline level='2'>Creating a theme from scratch</Headline>

<Paragraph>
You create a custom theme by extending the abstract
class <code>Theme</code>. Use this option if you would like to override
theme properties like colors or font sizes.
</Paragraph>

<SplitView>
<Code language='tsx'>{`
const customThemeThatExtendsBaseTheme = new CustomThemeThatExtendsBaseTheme({
name: 'CustomTheme',
spaceUnit: 18,
brandColors: {
highlight: '#48BB78',
gray: '#222',
grayDark: '#111',
grayLight: '#eeeeee',
grayModest: '#999999',
white: '#ffffff'
},
interactionColors: {
focus: '#363d45'
},
fontSizes: {
xxs: '12px',
xs: '16px',
sm: '18px',
md: '20px',
lg: '24px',
xl: '30px',
xxl: '48px'
},
pattern: {
opacity: 0.05,
backgroundImage: 'none'
}
});
<ThemeProvider theme={ customThemeThatExtendsBaseTheme }>
<Button>Styled with theme that extends base class</Button>
</ThemeProvider>
`}
</Code>
<ThemeProvider theme={ customThemeThatExtendsBaseTheme }>
<Button>Styled with theme that extends base class</Button>
</ThemeProvider>
</SplitView>

<Headline level='2'>Extending one of the default themes</Headline>

<Paragraph>
If you would like to use a default theme but simply need to override
some properties, extend <code>themes.TheNativeWeb</code> or <code>themes.Wolkenkit</code>.
</Paragraph>

<SplitView>
<Code language='tsx'>{`
class CustomThemeThatExtendsWolkenkit extends themes.Wolkenkit {
public constructor () {
super();
this.font.size.md = '18px';
}
}
<ThemeProvider theme={ new CustomThemeThatExtendsWolkenkit() }>
<Button>Styled with theme that extends Wolkenkit</Button>
</ThemeProvider>
`}
</Code>
<ThemeProvider theme={ new CustomThemeThatExtendsWolkenkit() }>
<Button>Styled with theme that extends Wolkenkit</Button>
</ThemeProvider>
</SplitView>

<Headline level='2'>Extending a theme with custom properties</Headline>

<Paragraph>
If you want to extend your theme with additional properties, add them
as readonly properties to your theme class.
</Paragraph>

<Code language='tsx'>{`
class CustomThemeWithCustomProperty extends themes.Wolkenkit {
public readonly customComponent = {
width: '300px'
};
}
`}
</Code>

<Paragraph>
You can now use these properties when styling your custom components.
You just need to make sure that you reference the custom theme instead
of the default one.
</Paragraph>

<Code language='tsx'>{`
import { CustomTheme as Theme } from '../../themes/CustomTheme';
const styles = (theme: Theme) => ({
CustomComponent: {
width: theme.customComponent.width
}
});
export { styles };
`}
</Code>
</React.Fragment>
);

export { Documentation };
56 changes: 56 additions & 0 deletions lib/themes/Documentation/themes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Theme, themes } from '../..';

class CustomThemeThatExtendsBaseTheme extends Theme {}

const customThemeThatExtendsBaseTheme = new CustomThemeThatExtendsBaseTheme({
name: 'CustomTheme',
spaceUnit: 18,

brandColors: {
highlight: '#48BB78',
gray: '#222',
grayDark: '#111',
grayLight: '#eeeeee',
grayModest: '#999999',
white: '#ffffff'
},

interactionColors: {
focus: '#363d45'
},

fontSizes: {
xxs: '12px',
xs: '16px',
sm: '18px',
md: '20px',
lg: '24px',
xl: '30px',
xxl: '48px'
},

pattern: {
opacity: 0.05,
backgroundImage: 'none'
}
});

class CustomThemeThatExtendsWolkenkit extends themes.Wolkenkit {
public constructor () {
super();

this.font.size.md = '18px';
}
}

class CustomThemeWithCustomProperty extends themes.Wolkenkit {
public readonly customComponent = {
width: '300px'
};
}

export {
customThemeThatExtendsBaseTheme,
CustomThemeThatExtendsWolkenkit,
CustomThemeWithCustomProperty
};
Loading

0 comments on commit 00a43ee

Please sign in to comment.