Giter VIP home page Giter VIP logo

storybook-addon-theme-playground's Introduction

storybook-addon-theme-playground

npm version

storybook-addon-theme-playground is a theme addon for storybook. It provides a panel where theme values can be tweaked directly.

Screenshot 🌍 Example

Features

  • 🎛 Seperate panel with auto-generated controls for each theme value
  • 🧬 Customizable controls based on your needs

Table of Contents

Installation

1. Install the addon

npm install -D storybook-addon-theme-playground

yarn add -D storybook-addon-theme-playground

2. Add the addon to your storybook config

Add to .storybook/main.js

module.exports = {
  addons: ["storybook-addon-theme-playground"],
};

3. Add parameters

Add to .storybook/preview.js.

// Import a theme provider of your choice
import { ThemeProvider } from "styled-components";

import theme from "path/to/theme";

export const parameters = {
  themePlayground: {
    theme,
    provider: ThemeProvider,
  },
};

To add multiple themes, add an Array to the theme key. Each theme must have a name and a theme key.

import { ThemeProvider } from "styled-components";
import defaultTheme from "path/to/default/theme";
import anotherTheme from "path/to/another/theme";

export const parameters = {
  themePlayground: {
    theme: [
      { name: "Default Theme", theme: defaultTheme },
      { name: "Another Theme", theme: anotherTheme },
    ],
    provider: ThemeProvider,
  },
};

Parameters

theme

objectArray<{ name: string, theme: object }> | required

The theme object or multiple themes as an array of objects.

provider

any | required

Any provider component which will accept a theme object prop and children. storybook-addon-theme-playground has no default provider due to extendability.

controls

object | optional

Optional control components of default controls. Look at the controls section for detailed documentation.

config

object | optional

An additional config object can be added. Look at the Config section for detailed documentation.

config.labelFormat

"path" || "startCase" || (path: string[]) => string | default: "startCase"

config.debounce

boolean | default: true

Set to false updating the theme values will not be debounced.

config.debounceRate

number | default: 500

config.showCode

boolean | default: true

Set to false no code component will be rendered.

config.showDiff

boolean | default: false

Shows the difference between initial theme and modified theme. Currently in an experimental state. Rendering multiple global styles for example override each other.

disabled

boolean | default: false

Set to true to disable addon panel for single stories.

export default {
  title: "Disabled story",
  parameters: {
    themePlayground: { disabled: true },
  },
};

Config

Example

import { ThemeProvider } from "styled-components";

export const parameters = {
  themePlayground: {
    theme: { button: { color: "#000" } },
    provider: ThemeProvider,
    config: {
      // One of "path"
      labelFormat: "path", // "button.color"
      // or "startCase"
      labelFormat: "startCase", // "Button Color"
      // or a custom function
      labelFormat: (path) => {
        // path is equal to ["button", "color"]
        return path.join("-"); // "button-color"
      },
      debounce: true || false,
      debounceRate: 500,
      showConfig: true || false,
    },
  },
};

Controls

storybook-addon-theme-playground will render default controls based on the theme value. If you want to customize them, you can override the default controls by adding an controls object to the parameters.

As a key use the theme object path, e.g 'button.spacing'.

All controls accept a type, label, description and icon prop. You can use all icons from the storybook styleguide.

Example

import { ThemeProvider } from "styled-components";

import theme from "path/to/theme";

const controls = {
  "button.spacing": {
    type: "number",
    icon: "expand",
    label: "Button Spacing",
    description: "Spacing for all buttons",
    min: 1,
    max: 20,
    steps: 1,
  },
  "button.color.primary": {
    type: "color",
    label: "Button Primary Color",
  },
};

export const parameters = {
  themePlayground: { theme, controls, provider: ThemeProvider },
};

Hide specific theme values

It is also possible to hide specific theme values or objects, e.g.:

const controls = {
  breakpoints: {
    hidden: true,
  },
  "button.spacing": {
    hidden: true,
  },
};

Control components

Color

'theme.path': {
  type: 'color',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null
}

Number

'theme.path': {
  type: 'number',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null,
  min: number | 0,
  max: number | 100,
  steps: number | 1
}

Select

'theme.path': {
  type: 'select',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null
  options: [
    {
      value: string | number,
      label: string
    }
  ]
}

Shorthand

'theme.path': {
  type: 'shorthand',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null
}

Switch

'theme.path': {
  type: 'switch',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null
}

RadioGroup

'theme.path': {
  type: 'radio',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null
  options: [
    {
      value: string,
      label: string
    }
  ]
}

Range

'theme.path': {
  type: 'range',
  icon: string,
  hidden: boolean,
  label: string | 'Theme Path',
  description: string | null,
  min: number | 0,
  max: number | 100,
  steps: number | 1
}

Default controls

storybook-addon-theme-playground will render the following components based on the value.

Switch

boolean

Number

number

Text

string

Range

string && string.endsWith("px" || "rem" || "em" || "%")

Color

string && string.startsWith("#" || "rgba" || "rgba") || label.includes("color")

Shorthand

object && Object.keys(object).length === 4 && Object.keys(object).includes("top" && "right" && "bottom" && "left")

Typescript

// .storybook/preview.ts

import {
  withThemePlayground,
  ThemePlaygroundProps,
} from "storybook-addon-theme-playground";

import theme from "path/to/theme";

interface ThemePlaygroundParams extends ThemePlaygroundProps {
  theme: typeof theme;
}

const params: ThemePlaygroundParams = {
  theme,
  provider: ThemeProvider,
  controls: {
    "headline.fontWeight": {
      type: "range",
      max: 900,
      min: 1,
      description: "Define the font weight of the variable font",
    },
    "copy.fontWeight": {
      type: "range",
      max: 900,
      min: 1,
      description: "Define the font weight of the variable font",
    },
  },
};

export const parameters = { themePlayground: params };

storybook-addon-theme-playground's People

Contributors

coderkevin avatar dependabot[bot] avatar jeslage avatar samvv avatar semantic-release-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

storybook-addon-theme-playground's Issues

Theme object throws error

The following theme object throws an error inside the addon.

const tokens: Tokens = {
  breakpoints: {
    s: 375,
    m: 768,
    l: 1024
  },
  colors: {
    black: '#181920',
    white: '#fff',
    primary: '#1E41FF',
    secondary: '#eee',
    positive: '#009900',
    critical: '#ff0000'
  },
  grid: {
    columns: 12,
    gutters: 0
  },
  spacings: {
    xs: 5,
    s: 10,
    m: 15,
    l: 20,
    xl: 25
  }
};

Bildschirmfoto 2021-01-21 um 10 24 54

Panel not load

Hello :)

My Theme Playground not load. what could it be? does not show any error

preview.tsx

import { ThemeProvider } from "styled-components";
import { Preview } from "@storybook/react";

import { drconsulta } from "../src/theme";

export const parameters = {
  themePlayground: {
    theme: [{ name: "Default Theme", theme: drconsulta }],
    provider: ThemeProvider,
  },
};

const preview: Preview = {};

export default preview;

theme.ts

export const drconsulta = {
  colors: {
    primary: '#ff9922',
    secondary: '#224422',
    tertiary: '#662255'
  },

  primary: {
    main: '#005DF9',
    light:  '#D6E4FF'
  },
  secondary: {
    main: '#00EEAD',
    light: '#CBFEDC'
  },
  floatButtonFill: '#FFFFFF',
  fontFamily: 'Arial',
  backgroundChatBotContainer: 'red',   
};

Theme doesn't persist when changing story

Hello there. I am using your addon within my companies style guide to assist the designers.

I was wondering if the theme playground properties are meant to persist between story changes?

Currently, if I edit a theme property and change the page the theme goes back to its default values. However, upon changing a property the theme goes back to the configured version.

Is this working as intended? If not, is there a workaround to have the configured theme persist without the need to toggle a theme value?

(p.s. appreciate all your hard work)

Fails to import `lodash` with Yarn 2

Lodash is imported in src/helper/index.ts but it is not included in the dependences. This doesn't cause an issue with Yarn 1 because Lodash is in node_modules thanks to being in the dependences tree of Storybook. With Yarn 2's plug-and-play (PNP), the way modules are managed changed. Yarn 2 will not provide an undeclared module to a module even when it likely has it.

Module not found: Error: storybook-addon-theme-playground tried to access lodash, but it isn't declared in its dependencies; this makes the require call ambiguous and unsound.

The fix I believe is to declare Lodash in the dependencies.

Configured theme does not persist between changing story

Hello there. I am using your addon within my companies style guide to assist the designers.

I was wondering if the theme playground properties are meant to persist between story changes?

Currently, if I edit a theme property and change the page the theme goes back to its default values. However, upon changing a property the theme goes back to the configured version.

Is this working as intended? If not, is there a workaround to have the configured theme persist without the need to toggle a theme value?

(p.s. appreciate all your hard work)

Panel not loading

For some reason the panel is not loading(just the loader spinning). I've tried in SB 6.4.x and Storybook 6.5.0-alpha.3. No errors in console or server.

React 18 Update

Hi, just wondering if there are going to be plans to make this usable for React 18?

Get current theme in decorator function

Hello, I am trying to switch from custom theming via the toolbar to storybook-addon-theme-playground to be able to utilize the playground feature vs hard-coded themes. I use a decorator that gets the current theme name from context.globals.theme and sets custom fonts, global styles, and logos based on that theme. I can't seem to figure out how to do the same thing with storybook-addon-theme-playground. This is my existing working code with the custom decorator:

const withThemeProviderAndFonts: DecoratorFn = (Story, context) => {
  const themeName = context.globals.theme;
  let theme: ThemeInterface;
  let globalStyles = "";
  let fontFaces = "";
  let tenantMock;

  switch (themeName) {
    case themeNames.ThemeOne:
      theme = themes.ThemeOne;
      globalStyles = generateGlobalStyles(themes.ThemeOne);
      fontFaces = generateFontFaces(fonts.ThemeOneFonts);
      tenantMock = tenantMocks.ThemeOneTenantMock;
      break;
    case themeNames.ThemeTwo:
      theme = themes.ThemeTwo;
      globalStyles = generateGlobalStyles(themes.ThemeTwo);
      fontFaces = generateFontFaces(fonts.ThemeTwoFonts);
      tenantMock = tenantMocks.ThemeTwoTenantMock;
      break;
    case themeNames.ThemeThree:
      theme = themes.ThemeThree;
      globalStyles = generateGlobalStyles(themes.ThemeThree);
      fontFaces = generateFontFaces(fonts.ThemeThreeFonts);
      tenantMock = tenantMocks.ThemeThreeTenantMock;
      break;
    default:
      theme = themes.Default;
      globalStyles = generateGlobalStyles(themes.Default);
      tenantMock = tenantMocks.DefaultTenantMock;
  }

  handleSetStyles(GLOBAL_STYLE_ELEMENT_ID, globalStyles);
  handleSetStyles(FONTS_ELEMENT_ID, fontFaces);

  return (
    <AppContext.Provider
      value={{
        featureFlags: [],
        tenant: tenantMock,
      }}
    >
      <ThemeProvider theme={theme}>
        <div id="__next">
          <div className="pageLayout">
            <Story {...context} />
          </div>
        </div>
      </ThemeProvider>
    </AppContext.Provider>
  );
};

export const globalTypes = {
  theme: {
    name: "Theme",
    description: "Themes",
    defaultValue: themeNames.ThemeOne,
    toolbar: {
      icon: "globe",
      items: [
        { value: themeNames.ThemeOne, title: themeNames.ThemeOne },
        { value: themeNames.ThemeTwo, title: themeNames.ThemeTwo },
        { value: themeNames.ThemeThree, title: themeNames.ThemeThree },
        { value: themeNames.Default, title: themeNames.Default },
      ],
    },
  },
};

export const decorators = [withThemeProviderAndFonts];

I've added this as per the docs to get the theme playground working, which works as intended:

export const parameters = {
  themePlayground: {
    theme: [
      { name: themeNames.ThemeOne, theme: themes.ThemeOne },
      { name: themeNames.ThemeTwo, theme: themes.ThemeTwo },
      { name: themeNames.ThemeThree, theme: themes.ThemeThree },
      { name: themeNames.Default, theme: themes.Default},
    ],
    provider: ThemeProvider
  }
};

I can see that the decorator gets called every time I change the theme from the theme playground, however I do not see what the current theme is. The only thing I can see regarding the theme playground is context.parameters.themePlayground which just shows me what I defined in parameters. Is there a way to get the current theme in a decorator (or some other way)? Thanks in advance for your help!

Storyshots Invalid hook call when using addon-theme-playground

Firstly, this is a great addon, and has been very useful for a color palette update, so thank you!

I've come across an issue I'm wondering if you could help with, when I'm using addon-theme-playground and I run a Storyshots test suite I get an 'Invalid hook call.' for each story tested, and when I disable addon-theme-playground the tests run ok.

` ● Storyshots › App › App Story

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.

  at resolveDispatcher (node_modules/react/cjs/react.development.js:1465:13)
  at Object.useState (node_modules/react/cjs/react.development.js:1496:20)
  at node_modules/storybook-addon-theme-playground/dist/src/withThemePlayground.tsx:29:9
  at node_modules/@storybook/addons/dist/hooks.js:241:21
  at node_modules/@storybook/client-api/dist/client_api.js:135:14
  at node_modules/@storybook/client-api/dist/client_api.js:136:16
  at withSubscriptionTracking (node_modules/@storybook/client-api/dist/client_api.js:164:16)
  at node_modules/@storybook/addons/dist/hooks.js:241:21
  at node_modules/@storybook/client-api/dist/client_api.js:135:14
  at node_modules/@storybook/addons/dist/hooks.js:269:20
  at Object.storyFn (node_modules/@storybook/client-api/dist/story_store.js:396:30)
  at getRenderedTree (node_modules/@storybook/addon-storyshots/dist/frameworks/react/renderTree.js:21:30)
  at node_modules/@storybook/addon-storyshots/dist/test-bodies.js:10:22
  at Object.<anonymous> (node_modules/@storybook/addon-storyshots/dist/api/snapshotsTestsTemplate.js:42:20)`

I created a little test project to recreate it outside of the large project it's being used in https://github.com/catkav/theme-playground-test

Have you come across anything like this and would you have any ideas for getting around it? The designers I'm working with love this addon so would appreciate any advice!

Missing properties from Type ThemePlaygroundProps - overrides, config

Hi

I have been trying to implement your application to storybook but having problems with typescript errors.
It appears config and overrides are required but in your documents it states these are optional.
Can you advise if there is something I have done wrong with my code or if this is a bug?
thanks

My code :

Theme.tsx

export const themeLight = {
  // dimensions
  maxTextWidth: '600px',

  pad10: `${ratios[2]}px`,
  pad20: `${ratios[3]}px`,

  // fonts:
  // fontFamily: "'Work Sans', sans-serif",
  fontFamily: 'sans-serif',
  fontSizeDefault: 1.4,
  fontSizeL: 1.8,

  // colours
  grey1: '#222',
  grey2: '#dedede',
  grey3: '#fefefe',
  blue1: '#22f',
  blue2: '#77f',
  warn: '#d82e2e',
  success: '#1b1'
};

.storybook/main.ts

import path from 'path';

import { addDecorator } from '@storybook/react';
import { ThemeProvider } from 'styled-components';
import { withThemePlayground } from 'storybook-addon-theme-playground';

import { themeLight } from '../src/Main/Styles/Theme';

const options = {
  theme: themeLight,
  provider: ThemeProvider
};

addDecorator(withThemePlayground(options));

Error:

Argument of type '{ theme: { maxTextWidth: string; pad10: string; pad20: string; fontFamily: string; fontSizeDefault: number; fontSizeL: number; grey1: string; grey2: string; grey3: string; blue1: string; blue2: string; warn: string; success: string; }; provider: BaseThemeProviderComponent<...>; }' is not assignable to parameter of type 'ThemePlaygroundProps'.
  Type '{ theme: { maxTextWidth: string; pad10: string; pad20: string; fontFamily: string; fontSizeDefault: number; fontSizeL: number; grey1: string; grey2: string; grey3: string; blue1: string; blue2: string; warn: string; success: string; }; provider: BaseThemeProviderComponent<...>; }' is missing the following properties from type 'ThemePlaygroundProps': overrides, config

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.