diff --git a/package.json b/package.json index 52f37b25..1089619b 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "remark-html": "^13.0.1", "request": "^2.88.2", "semver": "^7.5.2", + "snarkdown": "^2.0.0", "unist-util-visit": "^2.0.3", "use-debounce": "^8.0.4", "usehooks-ts": "^2.9.1", diff --git a/src/components/basics/Callout/Callout.stories.tsx b/src/components/basics/Callout/Callout.stories.tsx index d70eb2ea..ea76a5ac 100644 --- a/src/components/basics/Callout/Callout.stories.tsx +++ b/src/components/basics/Callout/Callout.stories.tsx @@ -4,70 +4,62 @@ import { styles } from '@storybook/design-system'; import { Callout } from './Callout'; +const { spacing } = styles; + +const StoryWrapper = styled.div` + padding: ${spacing.padding.medium}px; +`; + export default { title: 'Basics/Callout', component: Callout, parameters: { chromatic: { viewports: [320, 900] }, }, + decorators: [(story) => {story()}], }; -const { typography, spacing } = styles; - -const StoryWrapper = styled.div` - padding: ${spacing.padding.medium}px; -`; - -const Title = styled.h1` - font-family: ${typography.type}; - font-weight: ${typography.weight.bold}; - font-size: ${typography.size.s3}px; - line-height: ${typography.size.m3}px; -`; +export const Default = { + args: { + title: "Hello there, I'm a Callout", + children: `I'm here to bring attention to some important information that you might be interested in.`, + }, +}; -const BodyText = styled.p` - font-family: ${typography.type}; - font-size: ${typography.size.s3}px; - line-height: ${typography.size.m3}px; - margin: 0; -`; +export const Variants = { + args: { + ...Default.args, + }, + render: (args) => ( + <> + +
+ +
+ +
+ + + ), +}; -const Template = (args) => ( - - - 👋 Hello there, I'm a Callout - - I'm here to bring attention to some important information that you might be interested in. -
- You can play with the way I look using the prop controls below 👇 -
-
-
-); +export const WithEmoji = { + args: { + ...Default.args, + icon: '👋', + }, +}; -export const Default = Template.bind({}); +export const WithoutTitle = { + args: { + ...WithEmoji.args, + title: undefined, + }, +}; -export const Variants = () => ( - - - I'm a neutral Callout - - I'm here to bring attention to some important information that you might be interested in - - -
- - I'm a positive Callout - - I'm here to bring attention to some important information that you might be interested in - - -
- - I'm a selected Callout - - I'm here to bring attention to some important information that you might be interested in - - -
-); +export const WithMarkdownTitle = { + args: { + ...WithEmoji.args, + title: '`next/font` support', + }, +}; diff --git a/src/components/basics/Callout/Callout.tsx b/src/components/basics/Callout/Callout.tsx index 272db92d..8092cf59 100644 --- a/src/components/basics/Callout/Callout.tsx +++ b/src/components/basics/Callout/Callout.tsx @@ -1,24 +1,34 @@ import React from 'react'; +import snarkdown from 'snarkdown'; + import { rgba } from 'polished'; import { styled } from '@storybook/theming'; import { styles } from '@storybook/design-system'; -const { spacing, color, background } = styles; +const { spacing, color, background, typography, breakpoint } = styles; -type Variant = 'neutral' | 'positive' | 'selected'; +type Variant = 'neutral' | 'positive' | 'info' | 'warning'; const VARIANT_COLORS: Record = { neutral: { background: color.mediumlight, border: rgba(color.darker, 0.1) }, positive: { background: background.positive, border: rgba(color.positive, 0.1) }, - selected: { background: background.calmBlue, border: rgba(color.selected, 0.1) }, + info: { background: background.calmBlue, border: rgba(color.selected, 0.1) }, + warning: { background: background.warning, border: rgba(color.warning, 0.1) }, +}; + +const VARIANT_DEFAULT_ICON: Partial> = { + info: 'ℹ️', + warning: '⚠️', }; -export interface CalloutProps { +interface CalloutContainerProps { variant: Variant; } -export const Callout = styled.div` +const CalloutContainer = styled.div` padding: ${spacing.padding.medium}px; border-radius: ${spacing.borderRadius.small}px; + display: flex; + flex-direction: row; ${({ variant }) => ` background: ${VARIANT_COLORS[variant].background}; @@ -30,6 +40,66 @@ export const Callout = styled.div` } `; -Callout.defaultProps = { +CalloutContainer.defaultProps = { variant: 'neutral', }; + +const CalloutIcon = styled.span` + @media (min-width: ${breakpoint}px) { + margin-right: ${spacing.padding.small}px; + flex: 0 0 auto; + font-size: ${typography.size.m2}px; + display: inline-block; + } + display: none; +`; + +CalloutIcon.defaultProps = { + 'aria-hidden': true, +}; + +const CalloutContent = styled.div` + display: flex; + flex-direction: column; + flex: 1; + justify-content: center; +`; + +const CalloutTitle = styled.span` + font-family: ${typography.type}; + font-weight: ${typography.weight.bold}; + font-size: ${typography.size.s3}px; + line-height: ${typography.size.m3}px; + display: block; + + code { + color: inherit; + } +`; + +const CalloutBodyText = styled.p` + font-family: ${typography.type}; + font-size: ${typography.size.s3}px; + line-height: ${typography.size.m3}px; + margin: 0; +`; + +export interface CalloutProps extends CalloutContainerProps { + title?: string; + icon?: string; + children: string; +} + +export const Callout = ({ title, icon, children, variant, ...props }: CalloutProps) => { + const appliedIcon = icon ?? VARIANT_DEFAULT_ICON[variant]; + + return ( + + {appliedIcon && {appliedIcon}} + + {title && } + {children} + + + ); +}; diff --git a/src/components/screens/DocsScreen/DocsScreen.tsx b/src/components/screens/DocsScreen/DocsScreen.tsx index 6df19eef..3308c0d9 100644 --- a/src/components/screens/DocsScreen/DocsScreen.tsx +++ b/src/components/screens/DocsScreen/DocsScreen.tsx @@ -14,6 +14,7 @@ import { graphql } from 'gatsby'; import { CodeSnippets } from './CodeSnippets'; import { frameworkSupportsFeature, FrameworkSupportTable } from './FrameworkSupportTable'; import { SocialGraph } from '../../basics'; +import { Callout } from '../../basics/Callout'; import { Pre } from '../../basics/Pre'; import GatsbyLinkWrapper from '../../basics/GatsbyLinkWrapper'; import useSiteMetadata from '../../lib/useSiteMetadata'; @@ -36,14 +37,6 @@ const MDWrapper = styled.main` flex: 1; `; -const StyledHighlight = styled(Highlight)` - -webkit-text-size-adjust: none; - - > * > *:last-child { - margin-bottom: 0; - } -`; - const NextSubheading = styled(Subheading)` color: ${color.mediumdark}; font-size: ${typography.size.s2}px; @@ -235,11 +228,10 @@ function DocsScreen({ data, pageContext, location }) { IfRenderer: IfRendererWithCurrentFramework, YouTubeCallout, a: LinksWithPrefix, + Callout, }} > - - {body} - + {body} diff --git a/src/components/screens/IntegrationsCatalog/RecipesDetailScreen/RecipesDetailScreen.js b/src/components/screens/IntegrationsCatalog/RecipesDetailScreen/RecipesDetailScreen.js index a195f93e..81845b29 100644 --- a/src/components/screens/IntegrationsCatalog/RecipesDetailScreen/RecipesDetailScreen.js +++ b/src/components/screens/IntegrationsCatalog/RecipesDetailScreen/RecipesDetailScreen.js @@ -1,6 +1,7 @@ import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; import { format } from 'date-fns'; +import { rgba } from 'polished'; import { styled } from '@storybook/theming'; import { Link as GatsbyLink } from 'gatsby'; import { MDXProvider } from '@mdx-js/react'; @@ -18,7 +19,7 @@ import { import { SubNav, SubNavBreadcrumb, SubNavCTA, SubNavRight } from '@storybook/components-marketing'; import useSiteMetadata from '../../../lib/useSiteMetadata'; -import { SocialGraph, Callout, Pre } from '../../../basics'; +import { SocialGraph, Pre, Callout } from '../../../basics'; import { IntegrationsAside, IntegrationsAsideContainer, @@ -32,7 +33,7 @@ import { generateBreadcrumb } from '../../../../util/generate-breadcrumb'; import { generateRecipeGithubIssueLink } from './helpers'; import { CodeSnippets } from './CodeSnippets'; -const { color, typography, spacing } = styles; +const { color, background, typography, spacing } = styles; const SectionLinksContainer = styled.div` margin-bottom: 30px; @@ -59,7 +60,18 @@ const ReadMe = styled.section` min-width: 0; `; -const AddonsCallout = styled(Callout)` +const AddonsCallout = styled.div` + padding: ${spacing.padding.medium}px; + border-radius: ${spacing.borderRadius.small}px; + display: flex; + flex-direction: column; + + background: ${background.positive}; + box-shadow: ${rgba(color.positive, 0.1)} 0 0 0 1px inset; + + && *:last-child { + margin-bottom: 0px; + } margin-bottom: 40px; `; @@ -247,7 +259,7 @@ export const RecipesDetailScreen = ({ path, location, pageContext }) => { {hasAddons && (
- + Do it for me automatically The quickest way to integrate Storybook and {displayName} is to use an addon. @@ -259,12 +271,13 @@ export const RecipesDetailScreen = ({ path, location, pageContext }) => {
)} - + diff --git a/src/content/recipes/@emotion/styled.md b/src/content/recipes/@emotion/styled.md index dbca4159..680eb2a5 100644 --- a/src/content/recipes/@emotion/styled.md +++ b/src/content/recipes/@emotion/styled.md @@ -1,4 +1,4 @@ -
+ This recipe assumes that you have a React app using Emotion and have just set up Storybook >=7.0 using the [getting started guide](/docs/react/get-started/install). Don’t have this? Follow Emotion's [installation instructions](https://emotion.sh/docs/introduction#react) then run: @@ -7,29 +7,9 @@ This recipe assumes that you have a React app using Emotion and have just set up npx storybook@latest init ``` -
+
- - -How to setup Emotion and Storybook - - - -Emotion is a popular library for building UI components with CSS-in-JS, while Storybook is a tool for creating and testing UI components in isolation. -This post will show you how to integrate these two tools to create a powerful and flexible development environment for building user interfaces with Emotion. - -This post will explain how to: - -1. 🔌 Setup `Global` styles -1. 🧱 Use Emotion in your components -1. 💅 Use a theme in your stories -1. 🎨 Switch betweens themes in a click - -If you’d like to see the example code of this recipe, check out the [example repository](https://github.com/Integrayshaun/emotion-recipe) on GitHub. Let's get started! - -![Completed Emotion example with theme switcher](https://user-images.githubusercontent.com/18172605/208312563-875ca3b0-e7bc-4401-a445-4553b48068ed.gif) - -## Install `@storybook/addon-themes` +## 1. Add `@storybook/addon-themes` To get started, you'll need to install [`@storybook/addon-themes`](https://storybook.js.org/addons/@storybook/addon-themes). @@ -39,16 +19,17 @@ Run the following script to install and register the addon: npx storybook@latest add @storybook/addon-themes ``` -### How to setup `GlobalStyles` - -UIs often have a set of global styles that are applied to every component like CSS resets, `font-size`, `font-family`, and colors. +
+ Did the configuration script fail? +

Under the hood, this runs npx @storybook/auto-config themes, which should read your project and try to configure your Storybook with the correct decorator. If running that command directly does not solve your problem, please file a bug on the @storybook/auto-config repository so that we can further improve it. To manually add this addon, install it, and then add it to the addons array in your .storybook/main.ts.

+
-In Emotion, use the [`Global`](https://emotion.sh/docs/globals) component to scope styles globally instead of locally (which is the library's default behavior). +## 2. Provide `GlobalStyles` -Open `.storybook/preview.js` and create a `GlobalStyles` component which includes a `font-family`. Then apply it to your stories with the [`withThemeFromJSXProvider`](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider) decorator by adding it to the `decorators` array. +Inside of `.storybook/preview.js`, create a `` component that includes a `font-family`. Then apply it to your stories with the [`withThemeFromJSXProvider` decorator](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider) by adding it to the decorators array. ```js -// .storybook/preview.js +// .storybook/preview.jsx import { withThemeFromJSXProvider } from '@storybook/addon-themes'; import { Global, css } from '@emotion/react'; @@ -69,180 +50,22 @@ export const decorators = [ ]; ``` -
- -If you already have `Global` in your app, you can import it into `.storybook/preview.js` instead of creating it anew. - -
- -### Using Emotion in components - -Let’s update some of our example components to use Emotion instead. Open up the Button component in `./src/stories/button.js.` and replace it with the following code: - -```js -// ./src/stories/button.js - -import React from 'react'; -import PropTypes from 'prop-types'; -import { css } from '@emotion/react'; -import styled from '@emotion/styled'; - -const getVariantStyles = ({ primary = false }) => - primary - ? css` - color: white; - background-color: #1ea7fd; - ` - : css` - color: #333; - background-color: transparent; - box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; - `; - -const getSizeStyles = ({ size = 'medium' }) => { - switch (size) { - case 'small': { - return css` - font-size: 12px; - padding: 10px 16px; - `; - } - case 'large': { - return css` - font-size: 16px; - padding: 12px 24px; - `; - } - default: { - return css` - font-size: 14px; - padding: 11px 20px; - `; - } - } -}; - -/** - * Primary UI component for user interaction - */ -const StyledButton = styled.button` - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - font-weight: 700; - border: 0; - border-radius: 3em; - cursor: pointer; - display: inline-block; - line-height: 1; - - ${(props) => getVariantStyles(props)} - ${(props) => getSizeStyles(props)} - ${({ backgroundColor }) => - backgroundColor && - css` - background-color: ${backgroundColor}; - `} -`; - -export const Button = ({ label, ...rest }) => {label}; - -Button.propTypes = { - /** - * Is this the principal call to action on the page? - */ - primary: PropTypes.bool, - /** - * What background color to use - */ - backgroundColor: PropTypes.string, - /** - * How large should the button be? - */ - size: PropTypes.oneOf(['small', 'medium', 'large']), - /** - * Button contents - */ - label: PropTypes.string.isRequired, - /** - * Optional click handler - */ - onClick: PropTypes.func, -}; - -Button.defaultProps = { - backgroundColor: null, - primary: false, - size: 'medium', - onClick: undefined, -}; -``` - -Now the `Button` component is made with Emotion. In Storybook, you won't notice a visual difference. But if you inspect the DOM, you'll see hashed CSS-in-JS classnames. + -### Provide a theme for Emotion in Storybook +If you already have `` in your app, you can import it into `.storybook/preview.js` instead of creating it anew. -![Switching over to using a theme for emotion in Storybook](https://user-images.githubusercontent.com/18172605/208312571-431a182d-fe2b-40e7-a21f-aaadf55c899e.gif) + -One of the benefits of Emotion is that you can provide a theme to help you style all of your components in a consistent way. Let's create a new `./src/theme.js` and add the following light theme: - -```js -// ./src/theme.js - -export const lightTheme = { - colors: { - background: '#F6F9FC', - backgroundInverse: '#7A8997', - positive: '#E1FFD4', - negative: '#FEDED2', - primary: '#FF4785', - secondary: '#1EA7FD', - tertiary: '#DDDDDD', - text: '#222222', - }, - spacing: { - padding: { - small: 10, - medium: 20, - large: 30, - }, - borderRadius: { - small: 5, - default: 10, - }, - }, - typography: { - type: { - primary: '"Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif', - code: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace', - }, - weight: { - regular: '400', - bold: '700', - extrabold: '800', - black: '900', - }, - size: { - s1: 12, - s2: 14, - s3: 16, - m1: 20, - m2: 24, - m3: 28, - l1: 32, - l2: 40, - l3: 48, - }, - }, -}; -``` +## 3. Provide your theme(s) -To share this theme with the components in Storybook, you'll need to provide it to the `withThemeFromJSXProvider` decorator along with `@emotion/styled`'s ThemeProvider component. +To share your theme(s) with the components in Storybook, you'll need to provide them to the `withThemeFromJSXProvider` decorator along with `@emotion/styled`'s `` component. ```js -// .storybook/preview.js +// .storybook/preview.jsx import { withThemeFromJSXProvider } from '@storybook/addon-themes'; import { Global, css, ThemeProvider } from '@emotion/react'; -import { lightTheme } from '../src/themes'; +import { lightTheme, darkTheme } from '../src/themes'; const GlobalStyles = () => ( - - - - - -### Switch between themes in a click - -Dark mode has become an increasingly popular offering on the web. This can be achieved quickly using themes. - -![Completed Emotion example with theme switcher](https://user-images.githubusercontent.com/18172605/208312563-875ca3b0-e7bc-4401-a445-4553b48068ed.gif) - -Let's add the following dark theme to `theme.js` - -```js -// ./src/theme.js +Now, components made with Emotion will get the theme through the `theme` prop along with the styles inherited from ``. -/* snipped for brevity */ + -export const darkTheme = { - ...lightTheme, - colors: { - background: '#1b1c1d', - backgroundInverse: '#333333', - positive: '#9fd986', - negative: '#df987d', - primary: '#d43369', - secondary: '#1b8bd0', - tertiary: '#DDDDDD', - text: '#FFFFFF', - }, -}; -``` +When you provide more than one theme, a toolbar menu will appear in the Storybook UI to select your desired theme for your stories. -Now, to get the most out of your stories, there should be a way to toggle between themes in a click. + ![Completed Emotion example with theme switcher](https://user-images.githubusercontent.com/18172605/208312563-875ca3b0-e7bc-4401-a445-4553b48068ed.gif) -To add the switcher, add your `darkTheme` object into the the `withThemeFromJSXProvider` decorator themes object - -```js -// .storybook/preview.js -import { Global, css, ThemeProvider } from '@emotion/react'; -import { lightTheme, darkTheme } from '../src/themes'; - -/* snipped for brevity */ - -export const decorators = [ - withThemeFromJSXProvider({ - themes: { - light: lightTheme, - dark: darkTheme, - } - defaultTheme: 'light', - Provider: ThemeProvider, - GlobalStyles, -})]; -``` - -Adding a second theme will create a new toolbar menu to select your desired theme for your stories. - ## Get involved Now you're ready to use Emotion with Storybook. 🎉 diff --git a/src/content/recipes/@mui/material.md b/src/content/recipes/@mui/material.md index e4572ee4..4c268450 100644 --- a/src/content/recipes/@mui/material.md +++ b/src/content/recipes/@mui/material.md @@ -1,24 +1,15 @@ -
+ -This recipe assumes that you already have a React app using the `@mui/material` package set up with Storybook 7.0 or newer. If you don’t have a project ready, check out this [Stackblitz](https://stackblitz.com/edit/github-ju9knk?file=src/stories/Button.tsx) to follow along. +This recipe assumes that you already have a React app using `@mui/material` and have just set up **Storybook >= 7.0** using the [getting started guide](/docs/react/get-started/install). Don't have this? Follow MUI's [setup instructions](https://mui.com/material-ui/getting-started/installation/) then run: -
- - - -How to setup Material UI and Storybook - - - -Material UI offers a set of themeable components that devs can use to start building UIs right away. It’s based on Material Design language from Google. - -Storybook is a frontend workbench for building UIs in isolation. By combining Storybook and Material UI, you can build UIs faster without all the grunt work. This recipe shows you how to configure Storybook to load Material UI components and dynamically interact with their API. +```shell +# Add Storybook: +npx storybook@latest init +``` -- 📦 Bundle your fonts for fast and consistent rendering -- 🎨 Load your custom theme and add a theme switcher -- ♻️ Reuse Material UI types to auto-generate story controls +
-## Install `@storybook/addon-themes` +## 1. Add `@storybook/addon-themes` To get started, you'll need to install [`@storybook/addon-themes`](https://storybook.js.org/addons/@storybook/addon-themes). @@ -28,7 +19,12 @@ Run the following script to install and register the addon: npx storybook@latest add @storybook/addon-themes ``` -### Bundle fonts and icons for better perf +
+ Did the configuration script fail? +

Under the hood, this runs npx @storybook/auto-config themes, which should read your project and try to configure your Storybook with the correct decorator. If running that command directly does not solve your problem, please file a bug on the @storybook/auto-config repository so that we can further improve it. To manually add this addon, install it, and then add it to the addons array in your .storybook/main.ts.

+
+ +### 2. Bundle fonts and icons for better perf Material UI depends on two fonts to render as intended, Google’s [`Roboto`](https://fonts.google.com/specimen/Roboto) and [`Material Icons`](https://fonts.google.com/icons?query=Christian+Robertson&icon.style=Outlined&icon.set=Material+Icons). While you can load these fonts directly from the Google Fonts CDN, bundling fonts with Storybook is better for performance. @@ -42,7 +38,7 @@ To get started, install the fonts as dependencies. yarn add @fontsource/roboto @fontsource/material-icons ``` -Then import the CSS files into `.storybook/preview.js`, the entrypoint of your Storybook. +Then import the CSS files into `.storybook/preview.js`, the entry point of your Storybook. ```javascript // .storybook/preview.js @@ -54,50 +50,10 @@ import '@fontsource/roboto/700.css'; import '@fontsource/material-icons'; ``` -### Load custom themes and add a theme switcher +### 3. Load your theme(s) and global CSS -Material UI comes with a default theme out of the box, but you can also create and provide your own themes. Given the popularity of dark mode, you'll likely end with more than one custom theme. Let's look at how you can load custom themes and switch between them with just a click. +Inside of `.storybook/preview.js`, import ``, ``, and your theme(s), then apply them to your stories with the [`withThemeFromJSXProvider`](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider) decorator by adding it to the `decorators` array. -![Switching between light and dark mode using a theme switcher in the Storybook toolbar](https://lh3.googleusercontent.com/iqsY5lIKADg0xiIxGe7a9qS40R_HP-yNi50PGqO5VuPKVTFoio98LRdM8VvIE40kENxw6nHpu9P5DqkUQNLRJDtGCg9aw-hf4hW8dCtnRdqgxjCLJHOol-04dKjN-cEi-7pBzgy-s8Z8X_ojXMLGXdy04CsttlQevGeAiu6nyGHxzb7VW9FsTnmYQw) - -For example, take these custom light and dark mode themes. - -```js -// src/themes.js - -import { createTheme } from '@mui/material'; -import { blueGrey, cyan, pink } from '@mui/material/colors'; - -export const lightTheme = createTheme({ - palette: { - mode: 'light', - primary: { - main: cyan['A200'], - }, - secondary: { - main: pink['A400'], - }, - }, -}); - -export const darkTheme = createTheme({ - palette: { - mode: 'dark', - primary: { - main: pink['A200'], - }, - secondary: { - main: cyan['A400'], - }, - background: { - default: blueGrey['800'], - paper: blueGrey['700'], - }, - }, -}); -``` - -Then apply the custom themes to our stories. We’ll need to wrap them in Material UI’s `ThemeProvider` using the `withThemeFromJSXProvider` decorator. ```js // .storybook/preview.js @@ -119,13 +75,18 @@ export const decorators = [ })]; ``` -Awesome! Now when Storybook is reloaded, you'll see that our `withThemeFromJSXProvider` decorator is providing our custom light theme by default. + + +When you provide more than one theme, a toolbar menu will appear in the Storybook UI to select your desired theme for your stories. + + + -## Use Material UI prop types for better controls and docs +## 4. Use Material UI prop types for better controls and docs Storybook controls give you graphical controls to manipulate a component’s props. They’re handy for finding edge cases of a component and prototyping in the browser. -Usually, you have to manually configure controls. But if you’re using Typescript, you can reuse Material UI’s component prop types to auto generate story controls. As a bonus, this will also automatically populate the prop table in your documentation tab. +Usually, you have to manually configure controls. But if you’re using Typescript, you can reuse Material UI’s component prop types to auto-generate story controls. As a bonus, this will also automatically populate the prop table in your documentation tab. ![Changing the button components props using Storybook controls](https://storybookblog.ghost.io/content/images/2022/10/2022-10-04-15.48.29.gif) diff --git a/src/content/recipes/@sveltejs/kit.md b/src/content/recipes/@sveltejs/kit.md index 5874e7f2..19a505f9 100644 --- a/src/content/recipes/@sveltejs/kit.md +++ b/src/content/recipes/@sveltejs/kit.md @@ -1,18 +1,17 @@ -
+ -This recipe assumes that you are using SvelteKit >= 1.0 as well as Storybook >= 7.0 +This recipe assumes that you already have a **SvelteKit >= 1.0** app and have just set up **Storybook >= 7.0** using the [getting started guide](/docs/svelte/get-started/install). Don't have this? Follow Sveltekit's [setup instructions](https://kit.svelte.dev/docs/creating-a-project) then run: -
- - - -How to setup SvelteKit and Storybook +```shell +# Add Storybook: +npx storybook@latest init +``` - +
-Svelte is quickly becoming a major framework in the front-end ecosystem, offering lots of fantastic features for web developers. With SvelteKit, it also provides a powerful meta-framework for applications. At Storybook, we're investing in the Svelte ecosystem to create a seamless and enjoyable experience for users of Svelte and Storybook. +## Feature support -Fortunately, there is now an easier way to develop isolated components with the new `@storybook/sveltekit` framework package. As an industry-standard for component development, Storybook is proud to offer SvelteKit 1.0 features in a seamless integration. With our package, Storybook automatically mirrors the project settings of both SvelteKit. Here's what you'll get: +With our package, Storybook automatically mirrors the project settings of SvelteKit. Here's what you'll get: - 📚 Supports imports that use the special `$lib` alias - 👓 Components can read current environment information from `$app/environment` diff --git a/src/content/recipes/@vanilla-extract/css.md b/src/content/recipes/@vanilla-extract/css.md index 25f1611b..0fa40648 100644 --- a/src/content/recipes/@vanilla-extract/css.md +++ b/src/content/recipes/@vanilla-extract/css.md @@ -1,28 +1,22 @@ -
+ -This recipe assumes that you are using Storybook >= 7.0. If you haven't set up Storybook yet, run the following command in the root of your project: +This recipe assumes that you already have an app using Vanilla-extract and have just set up **Storybook >= 7.0** using the [getting started guide](/docs/react/get-started/install). Don't have this? Follow Vanilla-extract's [setup instructions](https://vanilla-extract.style/documentation/getting-started) then run: ```shell +# Add Storybook: npx storybook@latest init ``` -
+
- - -How to setup Vanilla Extract and Storybook - - - -Vanilla Extract Uses TypeScript as your CSS preprocessor. Allowing you to write type‑safe, locally scoped classes, variables and themes, then generate static CSS files at build time. Storybook is an industry-standard tool for developing and testing UI components in isolation. ## Configure your Storybook builder -
+ If you're already using Vanilla Extract in your project, you may already have these dependencies installed. -
+ First of all, install the required dependencies: @@ -52,10 +46,17 @@ npx storybook@latest add @storybook/addon-styling-webpack This will run a configuration script that will walk you through setting up the addon. If prompted, select `Vanilla Extract` as your CSS processor. -### Manually configure Webpack +
+ Did the configuration script fail? +

Under the hood, this command runs npx @storybook/auto-config styling, which is responsible for reading your project and attempting to configure your Storybook Webpack for your desired tools. If running that command directly does not resolve your issue, please consider filing a bug report on the @storybook/auto-config repository so that we can further improve it. For manual configuration instructions for Less, you can refer to the documentation.

+
+ + For an example of manual configuration, you can view a full example on [Stackblitz](https://stackblitz.com/edit/sb-vanilla-extract-webpack?file=.storybook/main.ts). + + ## Get involved Now you're ready to use Vanilla Extract with Storybook. 🎉 If you use Vanilla Extract at work, we'd love your feedback on the Vanilla Extract + Storybook experience. diff --git a/src/content/recipes/bootstrap.md b/src/content/recipes/bootstrap.md index 103fda89..48e7eaaf 100644 --- a/src/content/recipes/bootstrap.md +++ b/src/content/recipes/bootstrap.md @@ -1,4 +1,4 @@ -
+ This recipe assumes that you are using Storybook >=7.0 using the [getting started guide](/docs/react/get-started/install). Don’t have this? Then run: @@ -7,28 +7,9 @@ This recipe assumes that you are using Storybook >=7.0 using the [getting starte npx storybook@latest init ``` -
+ - - -How to setup Bootstrap and Storybook - - - -Bootstrap is a popular library for quickly building UI with ready-made CSS classes, while Storybook is a tool for creating and testing UI components in isolation. This post will show you how to integrate these two tools to create a powerful and flexible development environment for building user interfaces with Bootstrap. - -This post will explain how to: - -1. 🔌 Setup Bootstrap in Storybook using CSS or Sass -2. 🎨 Switch betweens themes in a click - -If you’d like to see the example code of this recipe, check out the [example repository](https://github.com/Integrayshaun/bootstrap-storybook-example) on GitHub. Let's get started! - -![Completed styled-components example with theme switcher](https://raw.githubusercontent.com/Integrayshaun/bootstrap-storybook-example/main/.storybook/demo-recording.gif) - -## How to setup `Bootstrap` - -### CSS +## 1. Import `Bootstrap` Import the Bootstrap files in your `.storybook/preview.js` file. @@ -53,19 +34,13 @@ export const parameters = { }; ``` -### Sass + -If you're using Sass in a Webpack based Storybook (Other than Next or Angular), you'll need to install the [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack) addon. +Check out our [Sass recipe](/docs/react/recipes/sass) for instructions on how to configure Storybook to work with Sass. -Run the following script to install and register the addon: + -```shell -npx storybook@latest add @storybook/addon-styling-webpack -``` - -This will run a configuration script that will walk you through setting up the addon. If prompted, select `Sass` in the configuration options. - -## Add a theme switcher +## 2. Add a theme switcher Bootstrap now ships with a dark mode that you can activate by adding a `[data-bs-theme]` data attribute to a parent element. @@ -77,6 +52,11 @@ Run the following script to install and register the addon: npx storybook@latest add @storybook/addon-themes ``` +
+ Did the configuration script fail? +

Under the hood, this runs npx @storybook/auto-config themes which should read your project and try to configure your Storybook with the correct decorator. If running that command directly does not solve your problem, please file a bug on the @storybook/auto-config repository for that we can make this good as can be. To manually add this addon, install it then add it to the addons array in your .storybook/main.ts.

+
+ Then, to enable switching between these modes in a click for your stories, use our `withThemeByDataAttribute` decorator by adding the following code to your `.storybook/preview.js` file. ```js diff --git a/src/content/recipes/less.md b/src/content/recipes/less.md index ec4d45e4..7d93ded4 100644 --- a/src/content/recipes/less.md +++ b/src/content/recipes/less.md @@ -1,28 +1,23 @@ -
+ -This recipe assumes that you are using Storybook >= 7.0. If you haven't set up Storybook yet, run the following command in the root of your project: +This recipe assumes that you have an app using Less and have just set up **Storybook >=7.0** using the [getting started guide](/docs/react/get-started/install). Don’t have this? Then run: ```shell +# Add Storybook: npx storybook@latest init ``` -
+ - +## 1. Configure your Storybook builder -How to setup Less and Storybook + - +If you are using Vite as your Storybook builder, you can skip to the [next step](#2-import-global-styles). -Less is a popular CSS preprocessor that allows developers to write more maintainable and reusable stylesheets. Storybook is an industry-standard tool for developing and testing UI components in isolation. With the help of the `@storybook/addon-styling` package, developers can easily incorporate Less stylesheets into their Storybook components. + -## Before you begin - -If you are using Vite as your Storybook builder, all you need to do is import your Less files into your `preview.js` file. - -## Configure your Storybook builder - -If you use Webpack to build your Storybook you'll need to install the [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack) addon. +Firstly, install the [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack) addon. Run the following script to install and register the addon: @@ -32,7 +27,12 @@ npx storybook@latest add @storybook/addon-styling-webpack This will run a configuration script that will walk you through setting up the addon. When prompted, select `Less` from the configuration options. -## Import global styles +
+ Did the configuration script fail? +

Under the hood, this command runs npx @storybook/auto-config styling, which is responsible for reading your project and attempting to configure your Storybook Webpack for your desired tools. If running that command directly does not resolve your issue, please consider filing a bug report on the @storybook/auto-config repository so that we can further improve it. For manual configuration instructions for Less, you can refer to the documentation here.

+
+ +## 2. Import global styles If you have any global styles you would like to expose for your stories, you can now import them into your `preview.js` file: diff --git a/src/content/recipes/next.md b/src/content/recipes/next.md index 5ea791b2..fabdf289 100644 --- a/src/content/recipes/next.md +++ b/src/content/recipes/next.md @@ -1,27 +1,18 @@ -
+ -This recipe assumes that you are using Next.js >= 12.x as well as Storybook >= 7.x +This recipe assumes that you have a Next >= 12 app. Don’t have this? Follow Next's [setup instructions](https://nextjs.org/docs/getting-started/installation) then run: -
- - - -How to setup Next.js and Storybook - - +```shell +# Add Storybook: +npx storybook@latest init +``` -Tens of thousands of websites and apps rely on Next.js for its powerful features, and the latest release of version 13 has brought many improvements, particularly in routing and image optimization. However, transitioning your existing Next app, along with its integrations, can be a daunting task. + -Fortunately, there is now an easier way to develop isolated components with the new `@storybook/nextjs` framework package. As an industry-standard for component development, Storybook is proud to offer Next.js 13 features in a seamless integration. With our package, Storybook automatically mirrors the project settings of both Next.js 12 and 13. Here's what you'll get: +## Set up your project -- 🔀 Routing -- 🖼 Image optimization -- ⤵️ Absolute imports -- 🎨 Styling -- 🎛 Webpack & Babel config -- 💫 and [more](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md#supported-features)! -## In a project without Storybook +### In a project without Storybook Follow the prompts after running this command in your Next.js project's root directory: @@ -29,7 +20,7 @@ Follow the prompts after running this command in your Next.js project's root dir npx storybook@latest init ``` -## In a project with Storybook +### In a project with Storybook This framework is designed to work with Storybook 7. If you’re not already using v7, upgrade with this command: @@ -37,11 +28,11 @@ This framework is designed to work with Storybook 7. If you’re not already usi npx storybook@latest upgrade ``` -### Automatic migration +#### Automatic migration When running the upgrade command above, you should get a prompt asking you to migrate to `@storybook/nextjs`, which should handle everything for you. In case that auto-migration does not work for your project, refer to the manual migration below. -### Manual migration +#### Manual migration Install the framework: @@ -78,60 +69,6 @@ export default { }; ``` -## Configuring next/navigation - -Next.js 13 introduced the experimental app directory with new features and conventions. It brings support for nested routes and layouts. - -If your story uses components in the app directory and they are importing modules from `next/navigation`, you have to tell Storybook to use the correct mocked router context by setting the `nextjs.appDirectory` parameter to `true`: - -```js -export const Example = { - parameters: { - nextjs: { - appDirectory: true, - }, - }, -}; -``` - -The Navigation provider is configured with some defaults. You can override those defaults by setting the parameter for `nextjs.navigation`: - -```js -export const Example = { - parameters: { - nextjs: { - appDirectory: true, - navigation: { - pathname: '/profile', - query: { - user: 'santa', - }, - }, - }, - }, -}; -``` - -Take a look at the [AppRouterProvider](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/routing/app-router-provider.tsx#L15) for all available parameters. - -## Configuring next/router - -Within the pages directory, you should continue to use imports from `next/router` for routing purposes. If you want to configure the Router provider, you can do so by setting the `nextjs.router` parameter: - -```js -export const Example = { - parameters: { - nextjs: { - router: { - basePath: '/profile', - }, - }, - }, -}; -``` - -Take a look at the [PageRouterProvider](https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/src/routing/page-router-provider.tsx#L18) for all available parameters. - ## Get involved Now you're ready to use Next.js with Storybook. 🎉 If you use Nextjs at work, we'd love your feedback on the Next + Storybook experience. diff --git a/src/content/recipes/pinia.md b/src/content/recipes/pinia.md index 084b7218..45593059 100644 --- a/src/content/recipes/pinia.md +++ b/src/content/recipes/pinia.md @@ -1,24 +1,15 @@ -
+ -This recipe assumes that you are using Vue 3 and Storybook >= 7.x. If you haven't upgraded yet, run the following command: +This recipe assumes that you have a Vue 3 app using Pinia and have just set up **Storybook >=7.0** using the [getting started guide](/docs/vue/get-started/install). Don’t have this? Follow Pinia's [setup instructions](https://pinia.vuejs.org/getting-started.html) then run: ```shell -npx storybook@latest upgrade +# Add Storybook: +npx storybook@latest init ``` -
+ - - -How to setup Pinia and Storybook - - - -Pinia is the recommended standard for state management in Vue. It gives you a lightweight and type-safe way to handle global state for your applications. This recipe will show you how to integrate [Pinia](https://pinia.vuejs.org/) into Storybook so that you can test your state connected components. - -If you want to look at a full example, look at this [awesome repo](https://github.com/chakAs3/vue3-pinia-storybook/tree/main) built by [Chakir Qatab (ChakAs3)](https://github.com/chakAs3). - -## Initialize Pinia +## 1. Initialize Pinia Inside of `.storybook/preview.ts`, import and initialize Pinia. @@ -47,7 +38,7 @@ const preview: Preview = { }; ``` -## Register Pinia +## 2. Register Pinia Import Storybook's setup function that lets you register tools with Storybook's Vue app instance. @@ -80,6 +71,12 @@ const preview: Preview = { }; ``` + + +If you want to look at a full example, look at this [awesome repo](https://github.com/chakAs3/vue3-pinia-storybook/tree/main) built by [Chakir Qatab (ChakAs3)](https://github.com/chakAs3). + + + ## Get involved Now you're ready to use Pinia with Storybook. 🎉 If you use Pinia at work, we'd love your feedback on the Pinia + Storybook experience. diff --git a/src/content/recipes/react-i18next.md b/src/content/recipes/react-i18next.md index 89ecb840..1f4ae949 100644 --- a/src/content/recipes/react-i18next.md +++ b/src/content/recipes/react-i18next.md @@ -1,18 +1,4 @@ - - -How to setup React i18next and Storybook - - - -Most developers use [`i18next`](https://www.i18next.com/), a popular JavaScript library that lets apps define separate files for each supported locale. It detects a user’s language preferences and region, and only loads the detected locale. - -Instead of being passed to components as inputs, the locale is shared globally through context. Let’s use i18next to extend Storybook with a locale switcher in the toolbar to choose which locale is shared with your components. - -Follow along using the [code examples](https://github.com/i18next/react-i18next/tree/master/example/storybook) in the react-i18next GitHub repository. - -![Switching locale between English, German, and Arabic in Storybook](https://storybookblog.ghost.io/content/images/2022/09/finished-switcher.gif) - -### Prerequisites + Before we begin, ensure that you have a working React app using [`react-i18next`](https://github.com/i18next/react-i18next) which is set up with Storybook 6.0 or newer. If you need resources to set these up, I’ve included some recommendations below: @@ -20,9 +6,11 @@ Before we begin, ensure that you have a working React app using [`react-i18next` - [Configure i18next language detector](https://react.i18next.com/latest/using-with-hooks) - [Getting started with Storybook](https://storybook.js.org/tutorials/intro-to-storybook/) -Or if you'd prefer a video, check out **Chantastic's** awesome video on adding i18next to your React app. +Or if you'd prefer a video, check out [**Chantastic's** awesome video](https://youtu.be/sr0Pahym3VM?feature=shared) on adding i18next to your React app. + + -### 1. Expose i18next to Storybook +## 1. Expose i18next to Storybook To make your translations available in your stories, you’ll first need to expose your i18next instance to Storybook. Here’s an example of an i18next instance from the `./src/i18n.js` file being used in my React app. @@ -50,16 +38,16 @@ export default i18n; To expose this instance to Storybook, we can import it into the `./.storybook/preview.js` file where Storybook holds its shared story configurations. ```js -// .storybook/preview.js +// .storybook/preview.jsx import i18n from '../src/i18n'; ``` -### 2. Wrap your stories with the i18next provider +## 2. Wrap your stories with the i18next provider Now that Storybook has access to i18next, we need to share that with our stories. To do that we’re going to make a decorator to wrap our stories in. ```jsx -// .storybook/preview.js +// .storybook/preview.jsx import React, { Suspense } from 'react'; import { I18nextProvider } from 'react-i18next'; import i18n from '../src/i18n'; @@ -85,14 +73,14 @@ Sweet! Our stories officially have access to our translations. If we change the ![Manually changing the locale from English to French](https://storybookblog.ghost.io/content/images/2022/09/manual-change.gif) -### 3. Add a locale switcher +## 3. Add a locale switcher Hardcoding your locale is annoying and won’t be helpful to anyone viewing your deployed Storybook, so let’s add a locale switcher to the Storybook toolbar. If you want to learn more about switchers, check out **Yann Braga’s** article on [adding a theme switcher](https://storybook.js.org/blog/how-to-add-a-theme-switcher-to-storybook/). To do this, we can declare a global variable named `locale` in `.storybook/preview.js` and assign it to a list of supported languages to choose from. ```js -// .storybook/preview.js +// .storybook/preview.jsx /* Snipped for brevity */ @@ -121,7 +109,7 @@ Looking back at Storybook, we can now see that we have a “Locale” switcher a Now let’s update our decorator to change our locale when we select a new language. ```jsx -// .storybook/preview.js +// .storybook/preview.jsx /* Snipped for brevity */ @@ -148,14 +136,14 @@ Voila— a fully functioning locale switcher for your stories powered by react-i ![Switching between English and German using the locale switcher](https://storybookblog.ghost.io/content/images/2022/09/en-to-de.gif) -### 4. Set document direction +## 4. Set document direction Some languages are not read from left to right like English is. Arabic, for example, is read from right to left. HTML has built-in support for this with the `dir` attribute. First of all, let's add Arabic as an option in our locale switcher by adding an object into the items array of our globalTypes. ```js -// .storybook/preview.js +// .storybook/preview.jsx /* Snipped for brevity */ @@ -181,7 +169,7 @@ export const globalTypes = { Using i18next’s `dir(lng)` function and `languageChanged` event, we can set the document direction for the selected locale. ```js -// .storybook/preview.js +// .storybook/preview.jsx /* Snipped for brevity */ diff --git a/src/content/recipes/sass.md b/src/content/recipes/sass.md index d84a7656..26bbd88b 100644 --- a/src/content/recipes/sass.md +++ b/src/content/recipes/sass.md @@ -1,23 +1,26 @@ -
+ -Some configurations of Storybook already come pre-configured to support Sass. If your project meets the following, you're likely ready to go. +This recipe assumes that you have an app using Sass and have just set up **Storybook >=7.0** using the [getting started guide](/docs/react/get-started/install). Don’t have this? Then run: -1. Storybook >= 7.x with the `vite` builder. -2. Storybook >= 7.x with the `@storybook/nextjs` framework. -3. Storybook >= 6.x with the `@storybook/preset-create-react-app` and `react-scripts@2.x.x` or higher. -4. Storybook >= 6.x with the `@storybook/angular` framework. Inject your global stylesheets into Storybook through your `angular.json` file. +```shell +# Add Storybook: +npx storybook@latest init +``` -
+ - +## 1. Add `@storybook/addon-styling-webpack` -How to setup Sass and Storybook + - +Some Storybook configurations are pre-configured to support Sass. If your project meets any of the following criteria, you can skip to the [next step](#2-import-global-styles). -Sass is a popular CSS preprocessor that allows developers to write more maintainable and reusable stylesheets. Storybook is an industry-standard tool for developing and testing UI components in isolation. With the help of the `@storybook/addon-styling-webpack` package, developers can easily incorporate Sass stylesheets into their Storybook components. +- Storybook >= 7.x with the `vite` builder. +- Storybook >= 7.x with the `@storybook/nextjs` framework. +- Storybook >= 7.x with the `@storybook/preset-create-react-app` and `react-scripts@2.x.x` or higher. +- Storybook >= 7.x with the `@storybook/angular` framework -## Adding `@storybook/addon-styling-webpack` + Run the following script to install and register the addon: @@ -27,7 +30,12 @@ npx storybook@latest add @storybook/addon-styling-webpack This will run a configuration script that will walk you through setting up the addon. When prompted, select `Sass` from the configuration options. -## Import global styles +
+ Did the configuration script fail? +

Under the hood, this command runs npx @storybook/auto-config styling, which is responsible for reading your project and attempting to configure your Storybook Webpack for your desired tools. If running that command directly does not resolve your issue, please consider filing a bug report on the @storybook/auto-config repository so that we can further improve it. For manual configuration instructions for Sass, you can refer to the documentation here.

+
+ +## 2. Import global styles If you have any global styles you would like to expose for your stories, you can now import them into your `preview.js` file: @@ -36,6 +44,23 @@ If you have any global styles you would like to expose for your stories, you can import '../src/index.scss'; ``` +### 2.1. Angular + +If you are using Angular, you will need to add your global scss file(s) to your `angular.json` file instead. This will make sure your styles are processed by Angular's Webpack and injected into the preview iframe where your stories are rendered. + +```json +// angular.json +{ + "storybook": { + "builder": "@storybook/angular:start-storybook", + "options": { + "browserTarget": "my-default-project:build", + "styles": ["src/index.scss"] + } + } +} +``` + ## Get involved Now you're ready to use Sass with Storybook. 🎉 If you use Sass at work, we'd love your feedback on the Sass + Storybook experience. diff --git a/src/content/recipes/styled-components.md b/src/content/recipes/styled-components.md index 14314def..c2e99bf9 100644 --- a/src/content/recipes/styled-components.md +++ b/src/content/recipes/styled-components.md @@ -1,4 +1,4 @@ -
+ This recipe assumes that you have a React app using styled-components and have just set up Storybook >=7.0 using the [getting started guide](/docs/react/get-started/install). Don’t have this? Follow styled-components' [installation instructions](https://styled-components.com/docs/basics#installation) then run: @@ -7,28 +7,9 @@ This recipe assumes that you have a React app using styled-components and have j npx storybook@latest init ``` -
+ - - -How to setup styled-components and Storybook - - - -styled-components is a popular library for building UI components with CSS-in-JS, while Storybook is a tool for creating and testing UI components in isolation. This post will show you how to integrate these two tools to create a powerful and flexible development environment for building user interfaces with styled-components. - -This post will explain how to: - -1. 🔌 Setup `GlobalStyles` -2. 🧱 Use styled-components in your components -3. 💅 Use a theme in your stories -4. 🎨 Switch betweens themes in a click - -If you’d like to see the example code of this recipe, check out the [example repository](https://github.com/Integrayshaun/styled-components-recipe) on GitHub. Let's get started! - -![Completed styled-components example with theme switcher](https://user-images.githubusercontent.com/18172605/208312563-875ca3b0-e7bc-4401-a445-4553b48068ed.gif) - -## Install `@storybook/addon-themes` +## 1. Add `@storybook/addon-themes` Run the following script to install and register the addon: @@ -38,16 +19,17 @@ npx storybook@latest add @storybook/addon-themes This will run a configuration script that will walk you through setting up the addon. When prompted, select `styled-components` from the configuration options. -### How to setup `GlobalStyles` - -UIs often have a set of global styles that are applied to every component like CSS resets, `font-size`, `font-family`, and colors. +
+ Did the configuration script fail? +

Under the hood, this runs npx @storybook/auto-config themes, which should read your project and try to configure your Storybook with the correct decorator. If running that command directly does not solve your problem, please file a bug on the @storybook/auto-config repository so that we can further improve it. To manually add this addon, install it, and then add it to the addons array in your .storybook/main.ts.

+
-In styled-components, use the [`createGlobalStyle`](https://styled-components.com/docs/api#createglobalstyle) API to scope styles globally instead of locally (which is the library's default behavior). +## 2. Provide `GlobalStyles` -Open `.storybook/preview.js` and create a `GlobalStyles` component which includes a `font-family`. Then apply it to your stories with the [`withThemeFromJSXProvider`](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider) decorator by adding it to the `decorators` array. +In `.storybook/preview.js`, create a ` component that includes a `font-family`. Then apply it to your stories with the [`withThemeFromJSXProvider`](https://github.com/storybookjs/storybook/blob/next/code/addons/themes/docs/api.md#withthemefromjsxprovider) decorator by adding it to the `decorators` array. ```js -// .storybook/preview.js +// .storybook/preview.jsx import { withThemeFromJSXProvider } from '@storybook/addon-themes'; import { createGlobalStyle } from 'styled-components'; @@ -64,247 +46,18 @@ export const decorators = [ ]; ``` -
- -If you already have `GlobalStyles` in your app, you can import it into `.storybook/preview.js` instead of creating it anew. - -
- -### Use styled-components in components - -Let’s update some of our example components to use styled-components instead. Open up the Button component in `./src/stories/button.js.` and replace it with the following code: - -```js -// ./src/stories/button.js - -import React from 'react'; -import PropTypes from 'prop-types'; -import styled, { css } from 'styled-components'; - -const getVariantStyles = ({ primary = false }) => - primary - ? css` - color: white; - background-color: #1ea7fd; - ` - : css` - color: #333; - background-color: transparent; - box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; - `; - -const getSizeStyles = ({ size = 'medium' }) => { - switch (size) { - case 'small': { - return css` - font-size: 12px; - padding: 10px 16px; - `; - } - case 'large': { - return css` - font-size: 16px; - padding: 12px 24px; - `; - } - default: { - return css` - font-size: 14px; - padding: 11px 20px; - `; - } - } -}; - -/** - * Primary UI component for user interaction - */ -const StyledButton = styled.button` - font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - font-weight: 700; - border: 0; - border-radius: 3em; - cursor: pointer; - display: inline-block; - line-height: 1; - - ${(props) => getVariantStyles(props)} - ${(props) => getSizeStyles(props)} - ${({ backgroundColor }) => - backgroundColor && - css` - background-color: ${backgroundColor}; - `} -`; - -export const Button = ({ label, ...rest }) => {label}; - -Button.propTypes = { - /** - * Is this the principal call to action on the page? - */ - primary: PropTypes.bool, - /** - * What background color to use - */ - backgroundColor: PropTypes.string, - /** - * How large should the button be? - */ - size: PropTypes.oneOf(['small', 'medium', 'large']), - /** - * Button contents - */ - label: PropTypes.string.isRequired, - /** - * Optional click handler - */ - onClick: PropTypes.func, -}; - -Button.defaultProps = { - backgroundColor: null, - primary: false, - size: 'medium', - onClick: undefined, -}; -``` - -Now the `Button` component is made with styled-components. In Storybook, you won't notice a visual difference. But if you inspect the DOM, you'll see hashed CSS-in-JS classnames. - -### Provide a theme for styled-components in Storybook - -![Switching over to using a theme for styled-components in Storybook](https://user-images.githubusercontent.com/18172605/208312571-431a182d-fe2b-40e7-a21f-aaadf55c899e.gif) - -One of the benefits of styled-components is that you can provide a theme to help you style all of your components in a consistent way. Let's create a new `./src/theme.js` and add the following light theme: - -```js -// ./src/theme.js - -export const lightTheme = { - colors: { - background: '#F6F9FC', - backgroundInverse: '#7A8997', - positive: '#E1FFD4', - negative: '#FEDED2', - primary: '#FF4785', - secondary: '#1EA7FD', - tertiary: '#DDDDDD', - text: '#222222', - }, - spacing: { - padding: { - small: 10, - medium: 20, - large: 30, - }, - borderRadius: { - small: 5, - default: 10, - }, - }, - typography: { - type: { - primary: '"Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif', - code: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace', - }, - weight: { - regular: '400', - bold: '700', - extrabold: '800', - black: '900', - }, - size: { - s1: 12, - s2: 14, - s3: 16, - m1: 20, - m2: 24, - m3: 28, - l1: 32, - l2: 40, - l3: 48, - }, - }, -}; -``` - -To share this theme with the components in Storybook, you'll need to provide it to the `withThemeFromJSXProvider` decorator along with `styled-components` ThemeProvider component. - -```js -// .storybook/preview.js -import { withThemeFromJSXProvider } from '@storybook/addon-themes'; -import { createGlobalStyle, ThemeProvider } from 'styled-components'; - -import { lightTheme } from '../src/themes'; - -const GlobalStyles = createGlobalStyle` - body { - font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; - } -`; - -export const decorators = [ - withThemeFromJSXProvider({ - themes: { - light: lightTheme, - } - defaultTheme: 'light', - Provider: ThemeProvider, - GlobalStyles, -})]; -``` - -Now, components made with styled-components will get the theme through the `theme` prop along with the styles inherited from `GlobalStyles`. Let's update the example components to use the theme. - - - - - - - -### Switch between themes in a click - -Dark mode has become an increasingly popular offering on the web. This can be achieved quickly using themes. + -![Completed styled-components example with theme switcher](https://user-images.githubusercontent.com/18172605/208312563-875ca3b0-e7bc-4401-a445-4553b48068ed.gif) +If you already have `` in your app, you can import it into `.storybook/preview.js` instead of creating it anew. -Let's add the following dark theme to `theme.js` + -```js -// ./src/theme.js - -/* snipped for brevity */ - -export const darkTheme = { - ...lightTheme, - colors: { - background: '#1b1c1d', - backgroundInverse: '#333333', - positive: '#9fd986', - negative: '#df987d', - primary: '#d43369', - secondary: '#1b8bd0', - tertiary: '#DDDDDD', - text: '#FFFFFF', - }, -}; -``` -Now, to get the most out of your stories, there should be a way to toggle between themes in a click. - -![Completed styled-components example with theme switcher](https://user-images.githubusercontent.com/18172605/208312563-875ca3b0-e7bc-4401-a445-4553b48068ed.gif) - -To add the switcher, add your `darkTheme` object into the the `withThemeFromJSXProvider` decorator themes object +## 3. Provide your theme(s) +To share your theme(s) with the components in Storybook, you'll need to provide them to the `withThemeFromJSXProvider` decorator along with `styled-components` `` component. ```js -// .storybook/preview.js +// .storybook/preview.jsx import { createGlobalStyle, ThemeProvider } from 'styled-components'; import { withThemeFromJSXProvider } from '@storybook/addon-themes'; @@ -324,7 +77,11 @@ export const decorators = [ })]; ``` -Adding a second theme will create a new toolbar menu to select your desired theme for your stories. + + +When you provide more than one theme, a toolbar menu will appear in the Storybook UI to select your desired theme for your stories. + + ## Get involved diff --git a/src/content/recipes/tailwindcss.md b/src/content/recipes/tailwindcss.md index 54c43590..2eaca97a 100644 --- a/src/content/recipes/tailwindcss.md +++ b/src/content/recipes/tailwindcss.md @@ -1,36 +1,30 @@ -
+ -This recipe assumes that you have a React app using Tailwind CSS and have just set up Storybook >=7.0 using the [getting started guide](/docs/react/get-started/install). Don’t have this? Follow Tailwind's [setup instructions](https://tailwindcss.com/docs/installation) then run: +This recipe assumes that you have a React app using Tailwind CSS and have just set up **Storybook >=7.0** using the [getting started guide](/docs/react/get-started/install). Don’t have this? Follow Tailwind's [setup instructions](https://tailwindcss.com/docs/installation) then run: ```shell # Add Storybook: npx storybook@latest init ``` -
+ - +## 1. Configure PostCSS -How to setup Tailwind CSS and Storybook - + -Storybook.js is a fantastic tool for developing and showcasing UI components in isolation. One of the great things about it is that you can use any CSS framework you like, including Tailwind CSS. +Tailwind uses PostCSS to compile your CSS. If you are using: +- `vite` +- `@storybook/nextjs` +- `@storybook/preset-create-react-app` with `react-scripts@2.0.0` +- `@storybook/angular` + +then you can skip to the [next step](#2-provide-tailwind-to-stories). -In this post, we will: + -1. 🏗️ Build Tailwind next to Storybook -2. 🎁 Provide Tailwind to stories -3. 🧱 Use Tailwind in your components -4. 🎨 Switch Tailwind themes in a click -![Finished example of Tailwind CSS in Storybook with a theme switcher](https://user-images.githubusercontent.com/18172605/208201389-1f448dbb-978c-442e-9d6b-7bf3fea63e64.gif) - -## Before you begin - -Tailwind uses PostCSS to compile your CSS. If you are using Vite, `@storybook/nextjs`, `@storybook/angular`, or `@storybook/preset-create-react-app` with `react-scripts@2.0.0`, then you can skip to the [theme switching section](#add-a-theme-switcher-tool). - -## Configure PostCSS For Webpack users, you'll need to install the [`@storybook/addon-styling-webpack`](https://storybook.js.org/addons/@storybook/addon-styling-webpack) addon. @@ -42,7 +36,12 @@ npx storybook@latest add @storybook/addon-styling-webpack This will run a configuration script that will walk you through setting up the addon. If prompted, select `PostCSS` from the configuration options. -### Provide Tailwind to stories +
+ Did the configuration script fail? +

Under the hood, this command runs npx @storybook/auto-config styling, which is responsible for reading your project and attempting to configure your Storybook Webpack for your desired tools. If running that command directly does not resolve your issue, please consider filing a bug report on the @storybook/auto-config repository so that we can further improve it. For manual configuration instructions for PostCSS, you can refer to the documentation here.

+
+ +## 2. Provide Tailwind to stories Now you can import the `tailwind.css` file into your `.storybook/preview.js` file. This will make Tailwind’s style classes available to all of your stories. @@ -52,29 +51,24 @@ Now you can import the `tailwind.css` file into your `.storybook/preview.js` fil import '../src/tailwind.css'; // replace with the name of your tailwind css file ``` -## Use Tailwind in components - -Let’s update some of our example components to use Tailwind instead. Open up Storybook to see what we have so far. - -![Storybook before adding tailwind CSS to the example components](https://user-images.githubusercontent.com/18172605/208201413-ace25d53-880a-4580-a81a-3d628fba229e.gif) - -To make use of Tailwind, replace the contents of each component file with the following code: - - - - - - - -![Storybook after adding tailwind CSS to the example components](https://user-images.githubusercontent.com/18172605/208201423-c7ea9392-1851-4fc3-9968-6d05399c2e91.gif) +### 2.1. Angular + +If you are using Angular, you will need to add the `tailwind.css` file to your `angular.json` file instead. This will make sure your styles are processed with PostCSS and are injected into the preview iframe where your stories are rendered. + +```json +// angular.json +{ + "storybook": { + "builder": "@storybook/angular:start-storybook", + "options": { + "browserTarget": "my-default-project:build", + "styles": ["src/tailwind.css"] + } + } +} +``` -### Add a theme switcher tool +## 3. Add a theme switcher tool Tailwind comes out of the box with a light and dark theme. You can override those themes and add more. To get the most out of your stories, you should have a way to toggle between all of your themes. @@ -87,7 +81,7 @@ First of all, update your `tailwind.config.js` file to [change themes based on a module.exports = { content: ['./src/**/*.{js,jsx,ts,tsx}'], - // Toggle dark-mode based on data-mode="dark" + // Toggle dark-mode based on .dark class or data-mode="dark" darkMode: ['class', '[data-mode="dark"]'], theme: { extend: {}, @@ -106,7 +100,35 @@ npx storybook@latest add @storybook/addon-themes This will run a configuration script that will walk you through setting up the addon. -To add the switcher, add the [`withThemeByDataAttribute`](https://github.com/storybookjs/addon-themes/blob/main/code/addons/themes/docs/api.md#withthemebydataattribute) decorator to your Storybook from `@storybook/addon-themes` +
+ Did the configuration script fail? +

Under the hood, this runs npx @storybook/auto-config themes, which should read your project and try to configure your Storybook with the correct decorator. If running that command directly does not solve your problem, please file a bug on the @storybook/auto-config repository so that we can further improve it. To manually add this addon, install it, and then add it to the addons array in your .storybook/main.ts.

+
+ +### 3.1. Toggle themes by class name + +Add the [`withThemeByClassName`](https://github.com/storybookjs/addon-themes/blob/main/code/addons/themes/docs/api.md#withthemebyclassname) decorator to your Storybook from `@storybook/addon-themes` + +```js +// .storybook/preview.js +import { withThemeByClassName } from '@storybook/addon-themes'; + +/* snipped for brevity */ + +export const decorators = [ + withThemeByClassName({ + themes: { + light: 'light', + dark: 'dark', + }, + defaultTheme: 'light', + }), +]; +``` + +### 3.2. Toggle themes by data-attribute + +Add the [`withThemeByDataAttribute`](https://github.com/storybookjs/addon-themes/blob/main/code/addons/themes/docs/api.md#withthemebydataattribute) decorator to your Storybook from `@storybook/addon-themes` ```js // .storybook/preview.js diff --git a/src/content/recipes/vuetify.md b/src/content/recipes/vuetify.md index 88b84091..2e263040 100644 --- a/src/content/recipes/vuetify.md +++ b/src/content/recipes/vuetify.md @@ -1,4 +1,4 @@ -
+ This recipe assumes that you have a Vue 3 app using Vuetify v3 and have just set up Storybook 7.0 using the [getting started guide](/docs/7.0/vue/get-started/install). Don’t have this? Follow Vuetify’s [installation instructions](https://next.vuetifyjs.com/en/getting-started/installation/#installation) then run: @@ -7,28 +7,9 @@ This recipe assumes that you have a Vue 3 app using Vuetify v3 and have just set npx storybook@latest init ``` -
+ - - -How to setup Vuetify and Storybook - - - -Vuetify is a popular UI framework for Vue.js that provides a variety of pre-designed components, while Storybook is a tool for creating and testing UI components in isolation. -This post will show you how to integrate these two tools to create a powerful and flexible development environment for building user interfaces with Vuetify. - -This post will explain how to: - -1. 🔌 Setup Vuetify with Storybook -2. 🧱 Use Vuetify in your components -3. 🎨 Switch Vuetify themes in a click - -If you’d like to see the example code of this recipe, check out the [example repository](https://github.com/Integrayshaun/vue3-vuetify-storybook-recipe-example) on GitHub. Let's get started! - -![Completed Vuetify example with theme switcher](https://user-images.githubusercontent.com/18172605/207120625-bedb53ec-eac4-4690-a06a-5d0579cb9809.gif) - -## Register Vuetify in Storybook +## 1. Register Vuetify in Storybook To get started, you'll need to add Vuetify’s fontloader and plugin to your Storybook configuration. To do this, add the following to your `.storybook/preview.js` file: @@ -47,11 +28,14 @@ setup((app) => { Here `registerPlugins` loads Vuetify’s fonts and registers all of its components with Storybook’s Vue app. -Next you will need to wrap your stories in Vuetify's `v-app` component in order to use some of it's larger layout components like `v-app-bar`. +## 2. Create a story wrapper component + +Next, you will need to wrap your stories in Vuetify's `v-app` component in order to use some of its larger layout components like `v-app-bar`. To do this, create a component in `.storybook/` called `StoryWrapper.vue` ```vue +