diff --git a/CHANGELOG.md b/CHANGELOG.md index b5f0051005..06775630b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Add focus styles for `Menu.Item` component @Bugaa92 ([#286](https://github.com/stardust-ui/react/pull/286)) - Add keyboard handling and ARIA attributes for `ButtonGroup`, `Tablist` and `Toolbar` behaviors @jurokapsiar ([#254](https://github.com/stardust-ui/react/pull/254)) +### Documentation +- Add theme switcher for exploring different themes on the docs (under development mode flag) @mnajdova ([#280](https://github.com/stardust-ui/react/pull/280)) + ## [v0.8.0](https://github.com/stardust-ui/react/tree/v0.8.0) (2018-10-01) [Compare changes](https://github.com/stardust-ui/react/compare/v0.7.0...v0.8.0) diff --git a/build/tsconfig.docs.json b/build/tsconfig.docs.json index 02ea804b83..0b396f19cb 100644 --- a/build/tsconfig.docs.json +++ b/build/tsconfig.docs.json @@ -2,7 +2,7 @@ "extends": "./tsconfig.common.json", "compilerOptions": { "module": "esnext", - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true }, "include": [ "../src", diff --git a/docs/src/app.tsx b/docs/src/app.tsx new file mode 100644 index 0000000000..ee8195fedc --- /dev/null +++ b/docs/src/app.tsx @@ -0,0 +1,57 @@ +import * as React from 'react' +import { Provider, themes } from '@stardust-ui/react' + +import { mergeThemes } from '../../src/lib' +import { semanticCssOverrides } from './Style' +import { ThemeContext } from './context/theme-context' +import Router from './routes' + +const semanticStyleOverrides = { + staticStyles: [semanticCssOverrides], +} + +interface IAppState { + themeName: string + changeTheme: (newTheme: string) => void +} + +class App extends React.Component { + private changeTheme + + constructor(props) { + super(props) + + this.changeTheme = newTheme => { + this.setState({ + themeName: newTheme, + }) + } + + // State also contains the updater function so it will + // be passed down into the context provider + this.state = { + themeName: 'teams', + changeTheme: this.changeTheme, + } + } + render() { + const { themeName } = this.state + return ( + + + + + + ) + } +} + +export default App diff --git a/docs/src/components/ComponentDoc/ComponentExample/ComponentExample.tsx b/docs/src/components/ComponentDoc/ComponentExample/ComponentExample.tsx index ec2ed1171c..e7a0fa0c92 100644 --- a/docs/src/components/ComponentDoc/ComponentExample/ComponentExample.tsx +++ b/docs/src/components/ComponentDoc/ComponentExample/ComponentExample.tsx @@ -1,7 +1,7 @@ import * as _ from 'lodash' import PropTypes from 'prop-types' import * as React from 'react' -import { withRouter, RouteComponentProps } from 'react-router' +import { RouteComponentProps, withRouter } from 'react-router' import { renderToStaticMarkup } from 'react-dom/server' import { html } from 'js-beautify' import * as copyToClipboard from 'copy-to-clipboard' @@ -23,17 +23,21 @@ import ComponentExampleTitle from './ComponentExampleTitle' import ContributionPrompt from '../ContributionPrompt' import getSourceCodeManager, { ISourceCodeManager, SourceCodeType } from './SourceCodeManager' import { IThemeInput, IThemePrepared } from 'types/theme' +import { mergeThemeVariables } from '../../../../../src/lib/mergeThemes' +import { ThemeContext } from '../../../context/theme-context' export interface IComponentExampleProps extends RouteComponentProps { title: string description: string examplePath: string suiVersion?: string + themeName?: string } interface IComponentExampleState { knobs: Object - theme: IThemeInput + themeName: string + componentVariables: Object exampleElement?: JSX.Element handleMouseLeave?: () => void handleMouseMove?: () => void @@ -62,7 +66,7 @@ const codeTypeApiButtonLabels: { [key in SourceCodeType]: string } = { * Renders a `component` and the raw `code` that produced it. * Allows toggling the the raw `code` code block. */ -class ComponentExample extends React.PureComponent { +class ComponentExample extends React.Component { private componentRef: React.Component private sourceCodeMgr: ISourceCodeManager private anchorName: string @@ -71,7 +75,8 @@ class ComponentExample extends React.PureComponent { @@ -346,10 +356,13 @@ class ComponentExample extends React.PureComponent this.props.examplePath.split('/')[1] private renderWithProvider(ExampleComponent) { - const { showRtl, theme } = this.state + const { showRtl, componentVariables, themeName } = this.state + const theme = themes[themeName] const newTheme: IThemeInput = { - componentVariables: theme.componentVariables, + componentVariables: mergeThemeVariables(theme.componentVariables, { + [this.getDisplayName()]: componentVariables, + }), rtl: showRtl, } @@ -540,7 +553,10 @@ class ComponentExample extends React.PureComponent { - const variables = componentVariables[displayName] + const mergedVariables = mergeThemeVariables(componentVariables, { + [displayName]: this.state.componentVariables, + }) + const variables = mergedVariables[displayName] if (!variables) { return ( @@ -580,15 +596,9 @@ class ComponentExample extends React.PureComponent (e, { value }) => { this.setState( state => ({ - theme: { - ...state.theme, - componentVariables: { - ...state.theme.componentVariables, - [component]: { - ...(state.theme.componentVariables && state.theme.componentVariables[component]), - [variable]: value, - }, - }, + componentVariables: { + ...state.componentVariables, + [variable]: value, }, }), this.renderSourceCode, @@ -697,4 +707,10 @@ class ComponentExample extends React.PureComponent ( + + {({ themeName }) => } + +)) + +export default withRouter(ComponentExampleWithTheme) diff --git a/docs/src/components/Sidebar/Sidebar.tsx b/docs/src/components/Sidebar/Sidebar.tsx index 2e8ec6e0f4..e398d9d4e0 100644 --- a/docs/src/components/Sidebar/Sidebar.tsx +++ b/docs/src/components/Sidebar/Sidebar.tsx @@ -5,10 +5,12 @@ import * as React from 'react' import { findDOMNode } from 'react-dom' import { NavLink } from 'react-router-dom' import { withRouter } from 'react-router' -import { Menu, Icon, Input as SemanticUIInput } from 'semantic-ui-react' +import { Icon, Input as SemanticUIInput, Menu } from 'semantic-ui-react' import Logo from 'docs/src/components/Logo/Logo' -import { getComponentPathname, typeOrder, repoURL } from 'docs/src/utils' +import { getComponentPathname, repoURL, typeOrder } from 'docs/src/utils' +import { themes } from '@stardust-ui/react' +import { ThemeContext } from '../../context/theme-context' const pkg = require('../../../../package.json') const componentMenu = require('docs/src/componentMenu') @@ -167,66 +169,95 @@ class Sidebar extends React.Component { const { style } = this.props const { query } = this.state return ( - - - - - Stardust UI React   - - {pkg.version} - - - - - GitHub + + {({ themeName, changeTheme }) => ( + + + + + Stardust UI React   + + {pkg.version} + + + + + GitHub + + + CHANGELOG + + - - CHANGELOG + {process.env.NODE_ENV !== 'production' && ( + +

Theme:

+ +
+ )} + + Introduction - -
- - Introduction - - - Guides - - - Quick Start - - - Glossary - - - Accessibility - - - Theming + + Guides + + + Quick Start + + + Glossary + + + Accessibility + + + Theming + + + Theming Examples + + - - Theming Examples + + - - - - - - {query ? this.renderSearchItems() : this.menuItemsByType} -
+ {query ? this.renderSearchItems() : this.menuItemsByType} +
+ )} + ) } + + private getThemeOptions = () => { + return Object.keys(themes).map(key => ({ + text: _.startCase(key), + value: key, + })) + } } export default withRouter(Sidebar) diff --git a/docs/src/context/theme-context.tsx b/docs/src/context/theme-context.tsx new file mode 100644 index 0000000000..640c8470c6 --- /dev/null +++ b/docs/src/context/theme-context.tsx @@ -0,0 +1,6 @@ +import * as React from 'react' + +export const ThemeContext = React.createContext({ + themeName: 'teams', + changeTheme: (newTheme: string) => {}, +}) diff --git a/docs/src/index.tsx b/docs/src/index.tsx index 0fbdf3ff37..c3c357c85b 100644 --- a/docs/src/index.tsx +++ b/docs/src/index.tsx @@ -1,14 +1,7 @@ import * as React from 'react' import * as ReactDOM from 'react-dom' import { AppContainer } from 'react-hot-loader' - -// TODO make themes a monorepo of packages -import { Provider, themes } from '@stardust-ui/react' - -import Router from './routes' -import { mergeThemes } from '../../src/lib' - -import { semanticCssOverrides } from './Style' +import App from './app' // ---------------------------------------- // Rendering @@ -17,24 +10,10 @@ import { semanticCssOverrides } from './Style' const mountNode = document.createElement('div') document.body.appendChild(mountNode) -const semanticStyleOverrides = { - staticStyles: [semanticCssOverrides], -} - const render = NewApp => ReactDOM.render( - - - + , mountNode, ) @@ -46,13 +25,13 @@ const render = NewApp => if (__DEV__) { // When the application source code changes, re-render the whole thing. if (module.hot) { - module.hot.accept('./routes', () => { + module.hot.accept('./app', () => { // restore scroll const { scrollLeft, scrollTop } = document.scrollingElement! ReactDOM.unmountComponentAtNode(mountNode) try { - render(require('./routes').default) + render(require('./app').default) document.scrollingElement!.scrollTop = scrollTop document.scrollingElement!.scrollLeft = scrollLeft } catch (e) { @@ -66,4 +45,4 @@ if (__DEV__) { // Start the app // ---------------------------------------- -render(Router) +render(App) diff --git a/src/themes/index.ts b/src/themes/index.ts index 91c945c79c..4dfa3d06e2 100644 --- a/src/themes/index.ts +++ b/src/themes/index.ts @@ -1,2 +1,4 @@ // Themes export { default as teams } from './teams' +export { default as teamsDark } from './teams-dark' +export { default as teamsHighContrast } from './teams-high-contrast' diff --git a/src/themes/teams-dark/componentVariables.ts b/src/themes/teams-dark/componentVariables.ts new file mode 100644 index 0000000000..e17b98e8c2 --- /dev/null +++ b/src/themes/teams-dark/componentVariables.ts @@ -0,0 +1 @@ +export { default as Button } from './components/Button/buttonVariables' diff --git a/src/themes/teams-dark/components/Button/buttonVariables.ts b/src/themes/teams-dark/components/Button/buttonVariables.ts new file mode 100644 index 0000000000..e5ab4067ef --- /dev/null +++ b/src/themes/teams-dark/components/Button/buttonVariables.ts @@ -0,0 +1,64 @@ +export interface IButtonVariables { + [key: string]: string | number + + color: string + backgroundColor: string + backgroundColorHover: string + typePrimaryColor: string + typePrimaryBackgroundColor: string + typePrimaryBackgroundColorActive: string + typePrimaryBackgroundColorHover: string + typePrimaryBorderColor: string + typePrimaryBorderColorFocus: string + typePrimaryBorderColorInsetFocus: string + typeSecondaryColor: string + typeSecondaryBackgroundColor: string + typeSecondaryBackgroundColorActive: string + typeSecondaryBackgroundColorHover: string + typeSecondaryBackgroundColorFocus: string + typeSecondaryBorderColor: string + typeSecondaryBorderColorActive: string + typeSecondaryBorderColorHover: string + typeSecondaryBorderColorFocus: string + typeSecondaryBorderColorInsetFocus: string + typeDisabledButtonColor: string + typeDisabledButtonBackgroundColor: string + typeTextColorHover: string + typeTextPrimaryColor: string + typeTextPrimaryColorHover: string + typeTextSecondaryColor: string + typeTextSecondaryColorHover: string +} + +export default (siteVars: any): IButtonVariables => { + return { + color: siteVars.black, + backgroundColor: siteVars.gray08, + backgroundColorHover: siteVars.gray06, + typePrimaryColor: siteVars.white, + typePrimaryBackgroundColor: siteVars.brand, + typePrimaryBackgroundColorActive: siteVars.brand02, + typePrimaryBackgroundColorHover: siteVars.brand04, + typePrimaryBackgroundColorFocus: siteVars.brand04, + typePrimaryBorderColor: 'transparent', + typePrimaryBorderColorFocus: siteVars.black, + typePrimaryBorderColorInsetFocus: siteVars.white, + typeSecondaryColor: siteVars.white, + typeSecondaryBackgroundColor: siteVars.black, + typeSecondaryBackgroundColorActive: siteVars.gray08, + typeSecondaryBackgroundColorHover: siteVars.brand04, + typeSecondaryBackgroundColorFocus: siteVars.gray08, + typeSecondaryBorderColor: siteVars.white, + typeSecondaryBorderColorActive: siteVars.gray06, + typeSecondaryBorderColorHover: siteVars.gray06, + typeSecondaryBorderColorFocus: siteVars.black, + typeSecondaryBorderColorInsetFocus: siteVars.white, + typeDisabledButtonColor: siteVars.gray08, + typeDisabledButtonBackgroundColor: siteVars.gray09, + typeTextColorHover: siteVars.brand04, + typeTextPrimaryColor: siteVars.brand, + typeTextPrimaryColorHover: siteVars.brand04, + typeTextSecondaryColor: siteVars.gray03, + typeTextSecondaryColorHover: siteVars.brand04, + } +} diff --git a/src/themes/teams-dark/index.ts b/src/themes/teams-dark/index.ts new file mode 100644 index 0000000000..4cd2c1e2b5 --- /dev/null +++ b/src/themes/teams-dark/index.ts @@ -0,0 +1,6 @@ +import mergeThemes from '../../lib/mergeThemes' +import * as siteVariables from './siteVariables' +import * as componentVariables from './componentVariables' +import teams from '../teams' + +export default mergeThemes(teams, { siteVariables, componentVariables }) diff --git a/src/themes/teams-dark/siteVariables.ts b/src/themes/teams-dark/siteVariables.ts new file mode 100644 index 0000000000..51b8027cc6 --- /dev/null +++ b/src/themes/teams-dark/siteVariables.ts @@ -0,0 +1,26 @@ +// +// COLORS +// +export const gray02 = '#bfbfbf' +export const gray03 = '#a6a6a6' +export const gray04 = '#808080' +export const gray06 = '#4d4d4d' +export const gray08 = '#262626' +export const gray09 = '#292827' +export const gray10 = '#2d2c2c' +export const gray14 = '#292828' + +export const brand = '#6264A7' +export const brand02 = '#e2e2f6' +export const brand04 = '#bdbde6' +export const brand06 = '#a6a7dc' +export const brand08 = '#8b8cc7' +export const brand12 = brand +export const brand14 = '#464775' +export const brand16 = '#33344a' + +export const orange04 = '#e97548' +export const magenta = '#cf6098' +export const orchid = '#ae3d84' +export const red = '#d74654' +export const red08 = '#4f232b' diff --git a/src/themes/teams-high-contrast/index.ts b/src/themes/teams-high-contrast/index.ts new file mode 100644 index 0000000000..6ebff98067 --- /dev/null +++ b/src/themes/teams-high-contrast/index.ts @@ -0,0 +1,5 @@ +import mergeThemes from '../../lib/mergeThemes' +import * as siteVariables from './siteVariables' +import teams from '../teams' + +export default mergeThemes(teams, { siteVariables }) diff --git a/src/themes/teams-high-contrast/siteVariables.ts b/src/themes/teams-high-contrast/siteVariables.ts new file mode 100644 index 0000000000..96cd019900 --- /dev/null +++ b/src/themes/teams-high-contrast/siteVariables.ts @@ -0,0 +1,6 @@ +import { white } from '../teams/siteVariables' + +// +// SEMANTIC ASSIGNMENTS +// +export const bodyColor = white diff --git a/src/themes/teams/components/Input/inputVariables.ts b/src/themes/teams/components/Input/inputVariables.ts index d32c23bdb6..060bd6b50d 100644 --- a/src/themes/teams/components/Input/inputVariables.ts +++ b/src/themes/teams/components/Input/inputVariables.ts @@ -7,7 +7,7 @@ export default (siteVars: any) => { vars.borderBottom = `${pxToRem(2)} solid transparent` vars.backgroundColor = siteVars.gray10 - vars.fontColor = siteVars.fontBlack + vars.fontColor = siteVars.bodyColor vars.fontSize = siteVars.fontSizes.medium vars.inputPadding = `${pxToRem(6)} ${pxToRem(24)} ${pxToRem(6)} ${pxToRem(12)}` diff --git a/src/themes/teams/siteVariables.ts b/src/themes/teams/siteVariables.ts index 3c74615a62..ea1fc3af7d 100644 --- a/src/themes/teams/siteVariables.ts +++ b/src/themes/teams/siteVariables.ts @@ -17,7 +17,6 @@ export const gray08 = '#E1DFDD' export const gray09 = '#EDEBE9' export const gray10 = '#F3F2F1' export const gray14 = '#FAF9F8' -export const fontBlack = black export const white = '#FFF' diff --git a/src/themes/teams/staticStyles/globalStyles.ts b/src/themes/teams/staticStyles/globalStyles.ts index 0148b5cbee..48a221ec77 100644 --- a/src/themes/teams/staticStyles/globalStyles.ts +++ b/src/themes/teams/staticStyles/globalStyles.ts @@ -1,4 +1,6 @@ -const globalStyles = siteVars => ({ +import { StaticStyleFunction } from '../../../../types/theme' + +const globalStyles: StaticStyleFunction = siteVars => ({ html: { fontSize: siteVars.htmlFontSize, },