├── .nvmrc ├── .prettierrc ├── .eslintignore ├── .prettierignore ├── manager.js ├── preview.js ├── src ├── index.ts ├── constants.ts ├── preview.ts ├── types.ts ├── manager.ts ├── stories │ ├── Header.stories.ts │ ├── header.css │ ├── button.css │ ├── Page.stories.ts │ ├── Button.tsx │ ├── Button.stories.ts │ ├── assets │ │ ├── direction.svg │ │ ├── flow.svg │ │ ├── code-brackets.svg │ │ ├── comments.svg │ │ ├── repo.svg │ │ ├── plugin.svg │ │ ├── stackalt.svg │ │ └── colors.svg │ ├── page.css │ ├── Header.tsx │ ├── Page.tsx │ └── Introduction.mdx ├── components │ └── PanelContent.tsx ├── Panel.tsx └── withHTML.ts ├── .storybook ├── preview-head.html ├── local-preset.js ├── main.ts └── preview.ts ├── image.gif ├── screenshot.png ├── .gitignore ├── vite.config.ts ├── .eslintrc.yml ├── tsconfig.json ├── LICENSE ├── scripts ├── eject-typescript.js └── prepublish-checks.js ├── CONTRIBUTING.md ├── README.md ├── package.json ├── tsup.config.ts └── CHANGELOG.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 18 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | CHANGELOG.md -------------------------------------------------------------------------------- /manager.js: -------------------------------------------------------------------------------- 1 | import "./dist/manager"; 2 | -------------------------------------------------------------------------------- /preview.js: -------------------------------------------------------------------------------- 1 | export * from "./dist/preview"; 2 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // make it work with --isolatedModules 2 | export default {}; 3 | -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /image.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitespace-se/storybook-addon-html/HEAD/image.gif -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whitespace-se/storybook-addon-html/HEAD/screenshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | node_modules/ 3 | storybook-static/ 4 | build-storybook.log 5 | .DS_Store 6 | .env -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const ADDON_ID = "storybook/html"; 2 | export const PANEL_ID = `${ADDON_ID}/panel`; 3 | export const PARAM_KEY = `html`; 4 | 5 | export const EVENTS = { 6 | CODE_UPDATE: `${ADDON_ID}/codeUpdate`, 7 | }; 8 | -------------------------------------------------------------------------------- /src/preview.ts: -------------------------------------------------------------------------------- 1 | import type { ProjectAnnotations, Renderer } from "storybook/internal/types"; 2 | import { withHTML } from "./withHTML"; 3 | 4 | const preview: ProjectAnnotations = { 5 | decorators: [withHTML], 6 | }; 7 | 8 | export default preview; 9 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type Parameters = { 2 | highlighter?: { 3 | showLineNumbers?: boolean; 4 | wrapLines?: boolean; 5 | }; 6 | root?: string; 7 | removeEmptyComments?: boolean; 8 | removeComments?: boolean | RegExp; 9 | transform?: (code: string) => string; 10 | }; 11 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | root: true 2 | plugins: 3 | - import 4 | - react 5 | extends: 6 | - eslint:recommended 7 | - plugin:import/recommended 8 | - plugin:react/recommended 9 | parserOptions: 10 | ecmaVersion: 2021 11 | ecmaFeatures: 12 | jsx: true 13 | sourceType: module 14 | settings: 15 | react: 16 | version: "17" 17 | env: 18 | browser: true 19 | es6: true 20 | node: true 21 | -------------------------------------------------------------------------------- /.storybook/local-preset.js: -------------------------------------------------------------------------------- 1 | /** 2 | * to load the built addon in this test Storybook 3 | */ 4 | function previewAnnotations(entry = []) { 5 | return [...entry, require.resolve("../dist/preview.js")]; 6 | } 7 | 8 | function managerEntries(entry = []) { 9 | return [...entry, require.resolve("../dist/manager.js")]; 10 | } 11 | 12 | module.exports = { 13 | managerEntries, 14 | previewAnnotations, 15 | }; 16 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from "@storybook/react-vite"; 2 | const config: StorybookConfig = { 3 | stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], 4 | addons: ["@storybook/addon-links", "@storybook/addon-docs", "./local-preset.js"], 5 | 6 | framework: { 7 | name: "@storybook/react-vite", 8 | options: {}, 9 | } 10 | }; 11 | export default config; 12 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from "@storybook/react-vite"; 2 | 3 | const preview: Preview = { 4 | parameters: { 5 | backgrounds: { 6 | default: "light", 7 | }, 8 | actions: { argTypesRegex: "^on[A-Z].*" }, 9 | controls: { 10 | matchers: { 11 | color: /(background|color)$/i, 12 | date: /Date$/, 13 | }, 14 | }, 15 | }, 16 | }; 17 | 18 | export default preview; 19 | -------------------------------------------------------------------------------- /src/manager.ts: -------------------------------------------------------------------------------- 1 | import { addons, types } from "storybook/internal/manager-api"; 2 | import { ADDON_ID, PANEL_ID, PARAM_KEY } from "./constants"; 3 | import { Panel } from "./Panel"; 4 | 5 | // Register the addon 6 | addons.register(ADDON_ID, () => { 7 | // Register the panel 8 | addons.add(PANEL_ID, { 9 | type: types.PANEL, 10 | title: "HTML", 11 | match: ({ viewMode }) => viewMode === "story", 12 | render: Panel, 13 | paramKey: PARAM_KEY, 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "baseUrl": ".", 5 | "esModuleInterop": true, 6 | "experimentalDecorators": true, 7 | "incremental": false, 8 | "isolatedModules": true, 9 | "jsx": "react", 10 | "lib": ["es2020", "dom"], 11 | "module": "commonjs", 12 | "noImplicitAny": true, 13 | "rootDir": "./src", 14 | "skipLibCheck": true, 15 | "target": "ES2020" 16 | }, 17 | "include": ["src/**/*"] 18 | } 19 | -------------------------------------------------------------------------------- /src/stories/Header.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react-vite"; 2 | import { Header } from "./Header"; 3 | 4 | const meta: Meta = { 5 | title: "Example/Header", 6 | component: Header, 7 | parameters: { 8 | // More on Story layout: https://storybook.js.org/docs/react/configure/story-layout 9 | layout: "fullscreen", 10 | }, 11 | }; 12 | 13 | export default meta; 14 | type Story = StoryObj; 15 | 16 | export const LoggedIn: Story = { 17 | args: { 18 | user: { 19 | name: "Jane Doe", 20 | }, 21 | }, 22 | }; 23 | 24 | export const LoggedOut: Story = {}; 25 | -------------------------------------------------------------------------------- /src/components/PanelContent.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { SyntaxHighlighter } from "storybook/internal/components" 3 | 4 | interface PanelContentProps { 5 | code: string; 6 | showLineNumbers?: boolean; 7 | wrapLines?: boolean; 8 | } 9 | 10 | export const PanelContent: React.FC = ({ 11 | code, 12 | showLineNumbers = false, 13 | wrapLines = false, 14 | }) => ( 15 | 23 | {code} 24 | 25 | ); 26 | -------------------------------------------------------------------------------- /src/stories/header.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | border-bottom: 1px solid rgba(0, 0, 0, 0.1); 4 | padding: 15px 20px; 5 | display: flex; 6 | align-items: center; 7 | justify-content: space-between; 8 | } 9 | 10 | svg { 11 | display: inline-block; 12 | vertical-align: top; 13 | } 14 | 15 | h1 { 16 | font-weight: 700; 17 | font-size: 20px; 18 | line-height: 1; 19 | margin: 6px 0 6px 10px; 20 | display: inline-block; 21 | vertical-align: top; 22 | } 23 | 24 | button + button { 25 | margin-left: 10px; 26 | } 27 | 28 | .welcome { 29 | color: #333; 30 | font-size: 14px; 31 | margin-right: 10px; 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU Affero General Public License 2 | 3 | Copyright (c) 2022 Whitespace. 4 | 5 | This program is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU Affero General Public License as 7 | published by the Free Software Foundation, either version 3 of the 8 | License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Affero General Public License for more details. 14 | 15 | You should have received a copy of the GNU Affero General Public License 16 | along with this program. If not, see http://www.gnu.org/licenses/. 17 | -------------------------------------------------------------------------------- /src/stories/button.css: -------------------------------------------------------------------------------- 1 | .storybook-button { 2 | font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | font-weight: 700; 4 | border: 0; 5 | border-radius: 3em; 6 | cursor: pointer; 7 | display: inline-block; 8 | line-height: 1; 9 | } 10 | .storybook-button--primary { 11 | color: white; 12 | background-color: #1ea7fd; 13 | } 14 | .storybook-button--secondary { 15 | color: #333; 16 | background-color: transparent; 17 | box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; 18 | } 19 | .storybook-button--small { 20 | font-size: 12px; 21 | padding: 10px 16px; 22 | } 23 | .storybook-button--medium { 24 | font-size: 14px; 25 | padding: 11px 20px; 26 | } 27 | .storybook-button--large { 28 | font-size: 16px; 29 | padding: 12px 24px; 30 | } 31 | -------------------------------------------------------------------------------- /src/stories/Page.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/react-vite'; 2 | import { within, userEvent } from 'storybook/test'; 3 | 4 | import { Page } from './Page'; 5 | 6 | const meta: Meta = { 7 | title: 'Example/Page', 8 | component: Page, 9 | parameters: { 10 | // More on Story layout: https://storybook.js.org/docs/react/configure/story-layout 11 | layout: 'fullscreen', 12 | }, 13 | }; 14 | 15 | export default meta; 16 | type Story = StoryObj; 17 | 18 | export const LoggedOut: Story = {}; 19 | 20 | // More on interaction testing: https://storybook.js.org/docs/react/writing-tests/interaction-testing 21 | export const LoggedIn: Story = { 22 | play: async ({ canvasElement }) => { 23 | const canvas = within(canvasElement); 24 | const loginButton = await canvas.getByRole('button', { 25 | name: /Log in/i, 26 | }); 27 | await userEvent.click(loginButton); 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /src/stories/Button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './button.css'; 3 | 4 | interface ButtonProps { 5 | /** 6 | * Is this the principal call to action on the page? 7 | */ 8 | primary?: boolean; 9 | /** 10 | * What background color to use 11 | */ 12 | backgroundColor?: string; 13 | /** 14 | * How large should the button be? 15 | */ 16 | size?: 'small' | 'medium' | 'large'; 17 | /** 18 | * Button contents 19 | */ 20 | label: string; 21 | /** 22 | * Optional click handler 23 | */ 24 | onClick?: () => void; 25 | } 26 | 27 | /** 28 | * Primary UI component for user interaction 29 | */ 30 | export const Button = ({ 31 | primary = false, 32 | size = 'medium', 33 | backgroundColor, 34 | label, 35 | ...props 36 | }: ButtonProps) => { 37 | const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; 38 | return ( 39 | 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /src/stories/Button.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react-vite"; 2 | 3 | import { Button } from "./Button"; 4 | 5 | // More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export 6 | const meta: Meta = { 7 | title: "Example/Button", 8 | component: Button, 9 | // More on argTypes: https://storybook.js.org/docs/react/api/argtypes 10 | argTypes: { 11 | backgroundColor: { control: "color" }, 12 | }, 13 | tags: ["autodocs"], 14 | }; 15 | 16 | export default meta; 17 | type Story = StoryObj; 18 | 19 | // More on component templates: https://storybook.js.org/docs/react/writing-stories/introduction#using-args 20 | export const Primary: Story = { 21 | // More on args: https://storybook.js.org/docs/react/writing-stories/args 22 | args: { 23 | primary: true, 24 | label: "Button", 25 | }, 26 | }; 27 | 28 | export const Secondary: Story = { 29 | args: { 30 | label: "Button", 31 | }, 32 | }; 33 | 34 | export const Large: Story = { 35 | args: { 36 | size: "large", 37 | label: "Button", 38 | }, 39 | }; 40 | 41 | export const Small: Story = { 42 | args: { 43 | size: "small", 44 | label: "Button", 45 | }, 46 | }; 47 | -------------------------------------------------------------------------------- /src/stories/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /src/Panel.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | useAddonState, 4 | useChannel, 5 | useParameter, 6 | } from "storybook/internal/manager-api"; 7 | import { AddonPanel } from "storybook/internal/components"; 8 | import { ADDON_ID, EVENTS, PARAM_KEY } from "./constants"; 9 | import { PanelContent } from "./components/PanelContent"; 10 | 11 | interface PanelProps { 12 | active: boolean; 13 | } 14 | 15 | export const Panel: React.FC = (props) => { 16 | // https://storybook.js.org/docs/react/addons/addons-api#useaddonstate 17 | const [{ code }, setState] = useAddonState(ADDON_ID, { 18 | code: null, 19 | }); 20 | 21 | // https://storybook.js.org/docs/react/addons/addons-api#usechannel 22 | useChannel({ 23 | [EVENTS.CODE_UPDATE]: ({ code }) => { 24 | setState((state) => ({ ...state, code })); 25 | }, 26 | }); 27 | 28 | const parameters = useParameter(PARAM_KEY, { 29 | highlighter: { showLineNumbers: false, wrapLines: true }, 30 | }); 31 | const { 32 | highlighter: { showLineNumbers = false, wrapLines = true } = {}, 33 | } = parameters; 34 | 35 | return ( 36 | 37 | 42 | 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /src/stories/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /src/stories/page.css: -------------------------------------------------------------------------------- 1 | section { 2 | font-family: "Nunito Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 3 | font-size: 14px; 4 | line-height: 24px; 5 | padding: 48px 20px; 6 | margin: 0 auto; 7 | max-width: 600px; 8 | color: #333; 9 | } 10 | 11 | section h2 { 12 | font-weight: 700; 13 | font-size: 32px; 14 | line-height: 1; 15 | margin: 0 0 4px; 16 | display: inline-block; 17 | vertical-align: top; 18 | } 19 | 20 | section p { 21 | margin: 1em 0; 22 | } 23 | 24 | section a { 25 | text-decoration: none; 26 | color: #1ea7fd; 27 | } 28 | 29 | section ul { 30 | padding-left: 30px; 31 | margin: 1em 0; 32 | } 33 | 34 | section li { 35 | margin-bottom: 8px; 36 | } 37 | 38 | section .tip { 39 | display: inline-block; 40 | border-radius: 1em; 41 | font-size: 11px; 42 | line-height: 12px; 43 | font-weight: 700; 44 | background: #e7fdd8; 45 | color: #66bf3c; 46 | padding: 4px 12px; 47 | margin-right: 10px; 48 | vertical-align: top; 49 | } 50 | 51 | section .tip-wrapper { 52 | font-size: 13px; 53 | line-height: 20px; 54 | margin-top: 40px; 55 | margin-bottom: 40px; 56 | } 57 | 58 | section .tip-wrapper svg { 59 | display: inline-block; 60 | height: 12px; 61 | width: 12px; 62 | margin-right: 4px; 63 | vertical-align: top; 64 | margin-top: 3px; 65 | } 66 | 67 | section .tip-wrapper svg path { 68 | fill: #1ea7fd; 69 | } 70 | -------------------------------------------------------------------------------- /src/stories/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /src/withHTML.ts: -------------------------------------------------------------------------------- 1 | import { useChannel } from "storybook/internal/preview-api"; 2 | import type { 3 | Renderer, 4 | PartialStoryFn as StoryFunction, 5 | } from "storybook/internal/types"; 6 | import { EVENTS } from "./constants"; 7 | import { Parameters } from "./types"; 8 | 9 | export const withHTML = ( 10 | storyFn: StoryFunction, 11 | { 12 | parameters: { html: parameters = {} } = {}, 13 | }: { parameters?: { html?: Parameters } }, 14 | ) => { 15 | const emit = useChannel({}); 16 | 17 | setTimeout(() => { 18 | const rootSelector = parameters.root || "#storybook-root, #root"; 19 | const root = document.querySelector(rootSelector); 20 | let code: string = root ? root.innerHTML : `${rootSelector} not found.`; 21 | const { removeEmptyComments, removeComments, transform } = parameters; 22 | if (removeEmptyComments) { 23 | code = code.replace(//g, ""); 24 | } 25 | if (removeComments === true) { 26 | code = code.replace(//g, ""); 27 | } else if (removeComments instanceof RegExp) { 28 | code = code.replace(//g, (match, p1) => 29 | removeComments.test(p1) ? "" : match, 30 | ); 31 | } 32 | if (typeof transform === "function") { 33 | try { 34 | code = transform(code); 35 | } catch (e) { 36 | console.error(e); 37 | } 38 | } 39 | emit(EVENTS.CODE_UPDATE, { code, options: parameters }); 40 | }, 0); 41 | 42 | return storyFn(); 43 | }; 44 | -------------------------------------------------------------------------------- /src/stories/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /scripts/eject-typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zx 2 | 3 | // Copy TS files and delete src 4 | await $`cp -r ./src ./srcTS`; 5 | await $`rm -rf ./src`; 6 | await $`mkdir ./src`; 7 | 8 | // Install Babel and TS preset 9 | console.log(chalk.green` 10 | 11 | 🔃 Installing dependencies... 12 | 13 | `); 14 | await $`npm install --save-dev @babel/cli @babel/preset-typescript --ignore-scripts`; 15 | 16 | // Convert TS code to JS 17 | await $`babel --no-babelrc --presets @babel/preset-typescript ./srcTS -d ./src --extensions \".js,.jsx,.ts,.tsx\" --ignore "./srcTS/typings.d.ts"`; 18 | 19 | // Format the newly created .js files 20 | console.log(chalk.green` 21 | 22 | 💅 Format the newly created .js files... 23 | 24 | `); 25 | await $`prettier --write ./src`; 26 | 27 | // Add in minimal files required for the TS build setup 28 | console.log(chalk.green` 29 | 30 | ➕ Add minimal files required for the TS build setup 31 | 32 | `); 33 | await $`prettier --write ./src`; 34 | await $`touch ./src/dummy.ts`; 35 | await $`printf "export {};" >> ./src/dummy.ts`; 36 | 37 | await $`touch ./src/typings.d.ts`; 38 | await $`printf 'declare module "global";' >> ./src/typings.d.ts`; 39 | 40 | // Clean up 41 | await $`rm -rf ./srcTS`; 42 | console.log(chalk.green` 43 | 44 | 🧹 Clean up... 45 | 46 | `); 47 | await $`npm uninstall @babel/cli @babel/preset-typescript --ignore-scripts`; 48 | 49 | console.log( 50 | chalk.green.bold` 51 | TypeScript Ejection complete!`, 52 | chalk.green` 53 | Addon code converted with JS. The TypeScript build setup is still available in case you want to adopt TypeScript in the future. 54 | `, 55 | ); 56 | -------------------------------------------------------------------------------- /src/stories/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Repository Structure 4 | 5 | This repository makes use of [Yarn Workspaces][yarn-workspaces] to install the 6 | dependencies for both the library itself _and_ the example applications found in 7 | the `examples` directory. 8 | 9 | You can find the source code for the library within the `addon` directory. 10 | 11 | Example applications -- which are useful for verifying changes -- can be found 12 | within `examples`. 13 | 14 | ## Getting Started 15 | 16 | Once you have the repository cloned, you'll want to install the dependencies 17 | using 18 | 19 | ``` 20 | yarn install 21 | ``` 22 | 23 | This will take care of setting up everything you need to get started! 24 | 25 | ## Building the library 26 | 27 | The library source is found within `addon`; referenced sub-directories or 28 | commands in this section are relative to that directory. 29 | 30 | The source-code for the library can be found within the `src` sub-directory. 31 | Babel is used to compile the output to the adjacent `out` directory, which is 32 | _not_ part of version control. This can be done by running 33 | 34 | ``` 35 | yarn build 36 | ``` 37 | 38 | Additionally, files exist within the root of the library that re-export code 39 | from the `out` directory. This allows for nice clean imports for users of the 40 | library without them needing to know about the `out` directory. 41 | 42 | ## Running Example Apps 43 | 44 | You can run `yarn start` from within any of the example applications to start 45 | Storybook with the library added to it. This can be helpful for checking that 46 | changes to the library look correct! 47 | 48 | ## Publishing Releases 49 | 50 | TBD! 51 | 52 | [yarn-workspaces]: https://classic.yarnpkg.com/en/docs/workspaces/ 53 | -------------------------------------------------------------------------------- /src/stories/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Button } from './Button'; 4 | import './header.css'; 5 | 6 | type User = { 7 | name: string; 8 | }; 9 | 10 | interface HeaderProps { 11 | user?: User; 12 | onLogin: () => void; 13 | onLogout: () => void; 14 | onCreateAccount: () => void; 15 | } 16 | 17 | export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => ( 18 |
19 |
20 |
21 | 22 | 23 | 27 | 31 | 35 | 36 | 37 |

Acme

38 |
39 |
40 | {user ? ( 41 | <> 42 | 43 | Welcome, {user.name}! 44 | 45 |
54 |
55 |
56 | ); 57 | -------------------------------------------------------------------------------- /src/stories/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /src/stories/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /src/stories/Page.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Header } from './Header'; 4 | import './page.css'; 5 | 6 | type User = { 7 | name: string; 8 | }; 9 | 10 | export const Page: React.FC = () => { 11 | const [user, setUser] = React.useState(); 12 | 13 | return ( 14 |
15 |
setUser({ name: 'Jane Doe' })} 18 | onLogout={() => setUser(undefined)} 19 | onCreateAccount={() => setUser({ name: 'Jane Doe' })} 20 | /> 21 | 22 |
23 |

Pages in Storybook

24 |

25 | We recommend building UIs with a{' '} 26 | 27 | component-driven 28 | {' '} 29 | process starting with atomic components and ending with pages. 30 |

31 |

32 | Render pages with mock data. This makes it easy to build and review page states without 33 | needing to navigate to them in your app. Here are some handy patterns for managing page 34 | data in Storybook: 35 |

36 |
    37 |
  • 38 | Use a higher-level connected component. Storybook helps you compose such data from the 39 | "args" of child component stories 40 |
  • 41 |
  • 42 | Assemble data in the page component from your services. You can mock these services out 43 | using Storybook. 44 |
  • 45 |
46 |

47 | Get a guided tutorial on component-driven development at{' '} 48 | 49 | Storybook tutorials 50 | 51 | . Read more in the{' '} 52 | 53 | docs 54 | 55 | . 56 |

57 |
58 | Tip Adjust the width of the canvas with the{' '} 59 | 60 | 61 | 66 | 67 | 68 | Viewports addon in the toolbar 69 |
70 |
71 |
72 | ); 73 | }; 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Storybook Addon HTML 2 | 3 | This addon for Storybook adds a tab that displays the compiled HTML for each 4 | story. 5 | 6 | ![Animated preview](https://raw.githubusercontent.com/whitespace-se/storybook-addon-html/master/image.gif) 7 | 8 | ## Requirements 9 | 10 | ### Storybook 9.x 11 | 12 | Use version 8.x of this addon. 13 | 14 | ### Storybook 8.x 15 | 16 | Use version 7.x of this addon. 17 | 18 | ## Getting Started 19 | 20 | Install the addon and its dependencies. 21 | 22 | With NPM: 23 | 24 | ```sh 25 | npm i --save-dev @whitespace/storybook-addon-html 26 | ``` 27 | 28 | With Yarn: 29 | 30 | ```sh 31 | yarn add -D @whitespace/storybook-addon-html 32 | ``` 33 | 34 | With PNPM: 35 | 36 | ```sh 37 | pnpm add -D @whitespace/storybook-addon-html 38 | ``` 39 | 40 | ### Register addon 41 | 42 | ```js 43 | // .storybook/main.js 44 | 45 | module.exports = { 46 | // ... 47 | addons: [ 48 | "@whitespace/storybook-addon-html", 49 | // ... 50 | ], 51 | }; 52 | ``` 53 | 54 | ## Usage 55 | 56 | You can override the wrapper element selector used to grab the component HTML. 57 | 58 | ```js 59 | export const parameters = { 60 | html: { 61 | root: "#my-custom-wrapper", // default: #root 62 | }, 63 | }; 64 | ``` 65 | 66 | Some frameworks put comments inside the HTML. If you want to remove these you 67 | can use the `removeComments` parameter. Set it to `true` to remove all comments 68 | or set it to a regular expression that matches the content of the comments you 69 | want to remove. 70 | 71 | ```js 72 | export const parameters = { 73 | html: { 74 | removeComments: /^\s*remove me\s*$/, // default: false 75 | }, 76 | }; 77 | ``` 78 | 79 | You can also use the `removeEmptyComments` parameter to remove only empty 80 | comments like `` and ``. 81 | 82 | ```js 83 | export const parameters = { 84 | html: { 85 | removeEmptyComments: true, // default: false 86 | }, 87 | }; 88 | ``` 89 | 90 | You can override the `showLineNumbers` and `wrapLines` settings for the syntax 91 | highlighter by using the `highlighter` parameter: 92 | 93 | ```js 94 | export const parameters = { 95 | html: { 96 | highlighter: { 97 | showLineNumbers: true, // default: false 98 | wrapLines: false, // default: true 99 | }, 100 | }, 101 | }; 102 | ``` 103 | 104 | Another way of hiding unwanted code is to define the `transform` option. It 105 | allows you to perform any change to the output code, e.g. removing attributes 106 | injected by frameworks. 107 | 108 | ```js 109 | html: { 110 | transform: (code) => { 111 | // Remove attributes `_nghost` and `ng-reflect` injected by Angular: 112 | return code.replace(/(?:_nghost|ng-reflect).*?="[\S\s]*?"/g, ""); 113 | }; 114 | } 115 | ``` 116 | 117 | You can disable the HTML panel by setting the `disable` parameter to true. 118 | This will hide and disable the HTML addon in your stories. 119 | 120 | ```js 121 | html: { 122 | disable: true, // default: false 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /scripts/prepublish-checks.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zx 2 | 3 | import boxen from "boxen"; 4 | import dedent from "dedent"; 5 | import { readFile } from "node:fs/promises"; 6 | import { globalPackages as globalManagerPackages } from "storybook/internal/manager/globals"; 7 | import { globalPackages as globalPreviewPackages } from "storybook/internal/preview/globals"; 8 | 9 | const packageJson = await readFile("./package.json", "utf8").then(JSON.parse); 10 | 11 | const name = packageJson.name; 12 | const displayName = packageJson.storybook.displayName; 13 | 14 | let exitCode = 0; 15 | $.verbose = false; 16 | 17 | /** 18 | * Check that meta data has been updated 19 | */ 20 | if (name.includes("addon-kit") || displayName.includes("Addon Kit")) { 21 | console.error( 22 | boxen( 23 | dedent` 24 | ${chalk.red.bold("Missing metadata")} 25 | 26 | ${chalk.red(dedent`Your package name and/or displayName includes default values from the Addon Kit. 27 | The addon gallery filters out all such addons. 28 | 29 | Please configure appropriate metadata before publishing your addon. For more info, see: 30 | https://storybook.js.org/docs/react/addons/addon-catalog#addon-metadata`)}`, 31 | { padding: 1, borderColor: "red" }, 32 | ), 33 | ); 34 | 35 | exitCode = 1; 36 | } 37 | 38 | /** 39 | * Check that README has been updated 40 | */ 41 | const readmeTestStrings = 42 | "# Storybook Addon Kit|Click the \\*\\*Use this template\\*\\* button to get started.|https://user-images.githubusercontent.com/42671/106809879-35b32000-663a-11eb-9cdc-89f178b5273f.gif"; 43 | 44 | if ((await $`cat README.md | grep -E ${readmeTestStrings}`.exitCode) == 0) { 45 | console.error( 46 | boxen( 47 | dedent` 48 | ${chalk.red.bold("README not updated")} 49 | 50 | ${chalk.red(dedent`You are using the default README.md file that comes with the addon kit. 51 | Please update it to provide info on what your addon does and how to use it.`)} 52 | `, 53 | { padding: 1, borderColor: "red" }, 54 | ), 55 | ); 56 | 57 | exitCode = 1; 58 | } 59 | 60 | /** 61 | * Check that globalized packages are not incorrectly listed as peer dependencies 62 | */ 63 | const peerDependencies = Object.keys(packageJson.peerDependencies || {}); 64 | const globalPackages = [...globalManagerPackages, ...globalPreviewPackages]; 65 | peerDependencies.forEach((dependency) => { 66 | if (globalPackages.includes(dependency)) { 67 | console.error( 68 | boxen( 69 | dedent` 70 | ${chalk.red.bold("Unnecessary peer dependency")} 71 | 72 | ${chalk.red(dedent`You have a peer dependency on ${chalk.bold(dependency)} which is most likely unnecessary 73 | as that is provided by Storybook directly. 74 | Check the "bundling" section in README.md for more information. 75 | If you are absolutely sure you are doing it correct, you should remove this check from scripts/prepublish-checks.js.`)} 76 | `, 77 | { padding: 1, borderColor: "red" }, 78 | ), 79 | ); 80 | 81 | exitCode = 1; 82 | } 83 | }); 84 | 85 | process.exit(exitCode); 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@whitespace/storybook-addon-html", 3 | "version": "8.0.2", 4 | "description": "A Storybook addon that extracts and displays compiled syntax-highlighted HTML", 5 | "keywords": [ 6 | "storybook-addon", 7 | "html", 8 | "code", 9 | "popular", 10 | "storybook-addons" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/whitespace-se/storybook-addon-html" 15 | }, 16 | "type": "module", 17 | "author": "Whitespace ", 18 | "license": "AGPL-3.0-or-later", 19 | "main": "dist/cjs/index.js", 20 | "module": "dist/esm/index.js", 21 | "types": "dist/ts/index.d.ts", 22 | "exports": { 23 | ".": { 24 | "types": "./dist/index.d.ts", 25 | "import": "./dist/index.js", 26 | "require": "./dist/index.cjs" 27 | }, 28 | "./preview": { 29 | "types": "./dist/index.d.ts", 30 | "import": "./dist/preview.js", 31 | "require": "./dist/preview.cjs" 32 | }, 33 | "./manager": "./dist/manager.js", 34 | "./package.json": "./package.json" 35 | }, 36 | "files": [ 37 | "dist/**/*", 38 | "README.md", 39 | "*.js", 40 | "*.d.ts" 41 | ], 42 | "scripts": { 43 | "build": "tsup", 44 | "build:watch": "npm run build -- --watch", 45 | "test": "echo \"Error: no test specified\" && exit 1", 46 | "start": "run-p build:watch 'storybook --quiet'", 47 | "prerelease": "zx scripts/prepublish-checks.js", 48 | "release": "npm run build && auto shipit", 49 | "eject-ts": "zx scripts/eject-typescript.js", 50 | "storybook": "storybook dev -p 6006", 51 | "build-storybook": "storybook build", 52 | "format": "run-s format:*", 53 | "format:eslint": "eslint --fix '**/*.{js,jsx}' || true", 54 | "format:prettier": "prettier --write '**/*.{js,jsx,json,md,mdx,yml,html,css}'", 55 | "lint": "eslint '**/*.{js,jsx}'" 56 | }, 57 | "devDependencies": { 58 | "@storybook/addon-docs": "^9.0.0", 59 | "@storybook/addon-links": "^9.0.0", 60 | "@storybook/react-vite": "^9.0.0", 61 | "@types/node": "^18.15.0", 62 | "@types/react": "^18.2.65", 63 | "@types/react-dom": "^18.2.21", 64 | "@vitejs/plugin-react": "^4.2.1", 65 | "auto": "^11.1.1", 66 | "boxen": "^7.1.1", 67 | "dedent": "^1.5.1", 68 | "eslint": "^8.57.0", 69 | "eslint-plugin-import": "^2.29.1", 70 | "eslint-plugin-react": "^7.34.1", 71 | "npm-run-all": "^4.1.5", 72 | "prettier": "^3.0.0", 73 | "prompts": "^2.4.2", 74 | "react": "^18.2.0", 75 | "react-dom": "^18.2.0", 76 | "storybook": "^9.0.0", 77 | "tsup": "^8.0.2", 78 | "typescript": "^5.4.2", 79 | "vite": "^5.1.6", 80 | "zx": "^7.2.3" 81 | }, 82 | "peerDependencies": { 83 | "storybook": "^9.0.0" 84 | }, 85 | "publishConfig": { 86 | "access": "public" 87 | }, 88 | "bundler": { 89 | "exportEntries": [ 90 | "src/index.ts" 91 | ], 92 | "managerEntries": [ 93 | "src/manager.ts" 94 | ], 95 | "previewEntries": [ 96 | "src/preview.ts" 97 | ], 98 | "nodeEntries": [ 99 | "src/preset.ts" 100 | ] 101 | }, 102 | "storybook": { 103 | "displayName": "HTML Preview", 104 | "supportedFrameworks": [ 105 | "react", 106 | "vue", 107 | "angular", 108 | "web-components", 109 | "ember", 110 | "html", 111 | "svelte", 112 | "preact", 113 | "react-native" 114 | ], 115 | "icon": "https://avatars1.githubusercontent.com/u/10450088?s=400&u=b2a95469b7d2addf63366a93a17f0bd06f9894cc&v=4" 116 | }, 117 | "overrides": { 118 | "storybook": "$storybook" 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, type Options } from "tsup"; 2 | import { readFile } from "node:fs/promises"; 3 | import { globalPackages as globalManagerPackages } from "storybook/internal/manager/globals"; 4 | import { globalPackages as globalPreviewPackages } from "storybook/internal/preview/globals"; 5 | 6 | // The current browsers supported by Storybook v7 7 | const BROWSER_TARGET: Options["target"] = [ 8 | "chrome100", 9 | "safari15", 10 | "firefox91", 11 | ]; 12 | const NODE_TARGET: Options["target"] = ["node18"]; 13 | 14 | type BundlerConfig = { 15 | bundler?: { 16 | exportEntries?: string[]; 17 | nodeEntries?: string[]; 18 | managerEntries?: string[]; 19 | previewEntries?: string[]; 20 | }; 21 | }; 22 | 23 | export default defineConfig(async (options) => { 24 | // reading the three types of entries from package.json, which has the following structure: 25 | // { 26 | // ... 27 | // "bundler": { 28 | // "exportEntries": ["./src/index.ts"], 29 | // "managerEntries": ["./src/manager.ts"], 30 | // "previewEntries": ["./src/preview.ts"] 31 | // "nodeEntries": ["./src/preset.ts"] 32 | // } 33 | // } 34 | const packageJson = (await readFile("./package.json", "utf8").then( 35 | JSON.parse, 36 | )) as BundlerConfig; 37 | const { 38 | bundler: { 39 | exportEntries = [], 40 | managerEntries = [], 41 | previewEntries = [], 42 | nodeEntries = [], 43 | } = {}, 44 | } = packageJson; 45 | 46 | const commonConfig: Options = { 47 | splitting: false, 48 | minify: !options.watch, 49 | treeshake: true, 50 | sourcemap: true, 51 | clean: options.watch ? false : true, 52 | }; 53 | 54 | const configs: Options[] = []; 55 | 56 | // export entries are entries meant to be manually imported by the user 57 | // they are not meant to be loaded by the manager or preview 58 | // they'll be usable in both node and browser environments, depending on which features and modules they depend on 59 | if (exportEntries.length) { 60 | configs.push({ 61 | ...commonConfig, 62 | entry: exportEntries, 63 | dts: { 64 | resolve: true, 65 | }, 66 | format: ["esm", "cjs"], 67 | target: [...BROWSER_TARGET, ...NODE_TARGET], 68 | platform: "neutral", 69 | external: [...globalManagerPackages, ...globalPreviewPackages], 70 | }); 71 | } 72 | 73 | // manager entries are entries meant to be loaded into the manager UI 74 | // they'll have manager-specific packages externalized and they won't be usable in node 75 | // they won't have types generated for them as they're usually loaded automatically by Storybook 76 | if (managerEntries.length) { 77 | configs.push({ 78 | ...commonConfig, 79 | entry: managerEntries, 80 | format: ["esm"], 81 | target: BROWSER_TARGET, 82 | platform: "browser", 83 | external: globalManagerPackages, 84 | }); 85 | } 86 | 87 | // preview entries are entries meant to be loaded into the preview iframe 88 | // they'll have preview-specific packages externalized and they won't be usable in node 89 | // they'll have types generated for them so they can be imported when setting up Portable Stories 90 | if (previewEntries.length) { 91 | configs.push({ 92 | ...commonConfig, 93 | entry: previewEntries, 94 | dts: { 95 | resolve: true, 96 | }, 97 | format: ["esm", "cjs"], 98 | target: BROWSER_TARGET, 99 | platform: "browser", 100 | external: globalPreviewPackages, 101 | }); 102 | } 103 | 104 | // node entries are entries meant to be used in node-only 105 | // this is useful for presets, which are loaded by Storybook when setting up configurations 106 | // they won't have types generated for them as they're usually loaded automatically by Storybook 107 | if (nodeEntries.length) { 108 | configs.push({ 109 | ...commonConfig, 110 | entry: nodeEntries, 111 | format: ["cjs"], 112 | target: NODE_TARGET, 113 | platform: "node", 114 | }); 115 | } 116 | 117 | return configs; 118 | }); 119 | -------------------------------------------------------------------------------- /src/stories/Introduction.mdx: -------------------------------------------------------------------------------- 1 | import { Meta } from "@storybook/addon-docs/blocks"; 2 | import Code from "./assets/code-brackets.svg"; 3 | import Colors from "./assets/colors.svg"; 4 | import Comments from "./assets/comments.svg"; 5 | import Direction from "./assets/direction.svg"; 6 | import Flow from "./assets/flow.svg"; 7 | import Plugin from "./assets/plugin.svg"; 8 | import Repo from "./assets/repo.svg"; 9 | import StackAlt from "./assets/stackalt.svg"; 10 | 11 | 12 | 13 | 116 | 117 | # Welcome to Storybook 118 | 119 | Storybook helps you build UI components in isolation from your app's business logic, data, and context. 120 | That makes it easy to develop hard-to-reach states. Save these UI states as **stories** to revisit during development, testing, or QA. 121 | 122 | Browse example stories now by navigating to them in the sidebar. 123 | View their code in the `stories` directory to learn how they work. 124 | We recommend building UIs with a [**component-driven**](https://componentdriven.org) process starting with atomic components and ending with pages. 125 | 126 |
Configure
127 | 128 | 174 | 175 |
Learn
176 | 177 | 215 | 216 |
217 | TipEdit the Markdown in{" "} 218 | stories/Introduction.stories.mdx 219 |
220 | -------------------------------------------------------------------------------- /src/stories/assets/colors.svg: -------------------------------------------------------------------------------- 1 | illustration/colors -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### [8.0.2](https://github.com/whitespace-se/storybook-addon-html/compare/v8.0.1...v8.0.2) (2025-08-29) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * Wrong Storybook peer dep version ([70fa4cf](https://github.com/whitespace-se/storybook-addon-html/commit/70fa4cf3e8eedc9b5ce9737e0c1f6965ebc7367d)) 7 | 8 | ### [8.0.1](https://github.com/whitespace-se/storybook-addon-html/compare/v8.0.0...v8.0.1) (2025-08-28) 9 | 10 | ## [8.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v7.0.0...v8.0.0) (2025-08-28) 11 | 12 | 13 | ### ⚠ BREAKING CHANGES 14 | 15 | * Support Storybook 9 16 | 17 | ### Features 18 | 19 | * Support Storybook 9 ([68f6df1](https://github.com/whitespace-se/storybook-addon-html/commit/68f6df103ee58966e0d6393e18c8928c1ae1f3bd)) 20 | 21 | ## [7.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v6.1.1...v7.0.0) (2025-05-07) 22 | 23 | 24 | ### ⚠ BREAKING CHANGES 25 | 26 | * Refactor the code to use the syntax highlighter of Storybook (#137) 27 | 28 | ### Code Refactoring 29 | 30 | * Refactor the code to use the syntax highlighter of Storybook ([#137](https://github.com/whitespace-se/storybook-addon-html/issues/137)) ([ad191ec](https://github.com/whitespace-se/storybook-addon-html/commit/ad191ec7385fea6ec7017eb30585ec7c6e47089d)) 31 | 32 | ### [6.1.1](https://github.com/whitespace-se/storybook-addon-html/compare/v6.1.0...v6.1.1) (2024-05-11) 33 | 34 | 35 | ### Bug Fixes 36 | 37 | * update syntax-highlighter language option and correct type reference ([#126](https://github.com/whitespace-se/storybook-addon-html/issues/126)) ([a653292](https://github.com/whitespace-se/storybook-addon-html/commit/a653292b8bac979d51ca7b48c956b6fe783b9b4f)) 38 | 39 | ## [6.1.0](https://github.com/whitespace-se/storybook-addon-html/compare/v6.0.5...v6.1.0) (2024-05-07) 40 | 41 | 42 | ### Features 43 | 44 | * add `paramKey` property to panel object. ([#120](https://github.com/whitespace-se/storybook-addon-html/issues/120)) ([1506cad](https://github.com/whitespace-se/storybook-addon-html/commit/1506cad8482a03959e585c7cd8dbe86c4dd16fde)) 45 | 46 | ### [6.0.5](https://github.com/whitespace-se/storybook-addon-html/compare/v6.0.4...v6.0.5) (2024-04-11) 47 | 48 | 49 | ### Bug Fixes 50 | 51 | * Remove unused preset file ([2a8299d](https://github.com/whitespace-se/storybook-addon-html/commit/2a8299d196fa3e19954bc30e9875aee230640cd1)) 52 | 53 | ### [6.0.4](https://github.com/whitespace-se/storybook-addon-html/compare/v6.0.3...v6.0.4) (2024-04-02) 54 | 55 | ### [6.0.3](https://github.com/whitespace-se/storybook-addon-html/compare/v6.0.2...v6.0.3) (2024-04-02) 56 | 57 | 58 | ### Bug Fixes 59 | 60 | * Replace all instances of "my addon" ([693c60e](https://github.com/whitespace-se/storybook-addon-html/commit/693c60eb28c802c330d0c184aa3fd53c0a4295d5)) 61 | 62 | ### [6.0.2](https://github.com/whitespace-se/storybook-addon-html/compare/v6.0.1...v6.0.2) (2024-03-25) 63 | 64 | 65 | ### Bug Fixes 66 | 67 | * Remove reference to preset ([f7997e8](https://github.com/whitespace-se/storybook-addon-html/commit/f7997e82f10aec49a5e716584c0c03cd44a0ddbe)) 68 | 69 | ### [6.0.1](https://github.com/whitespace-se/storybook-addon-html/compare/6.0.0...v6.0.1) (2024-03-25) 70 | 71 | ## [6.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v5.1.4...6.0.0) (2024-03-25) 72 | 73 | 74 | ### ⚠ BREAKING CHANGES 75 | 76 | * Rewrite in Typescript with support for Storybook 8 and Prettier 3 based on latest addon kit 77 | 78 | ### Code Refactoring 79 | 80 | * Rewrite in Typescript with support for Storybook 8 and Prettier 3 based on latest addon kit ([4963646](https://github.com/whitespace-se/storybook-addon-html/commit/4963646a1b08eeb19cda90c36d036c11921060c0)) 81 | 82 | ### [5.1.4](https://github.com/whitespace-se/storybook-addon-html/compare/v5.1.3...v5.1.4) (2023-03-13) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * Incompatibility with Storybook 7.0 ([4751ec7](https://github.com/whitespace-se/storybook-addon-html/commit/4751ec73ff55cd9fb7a7a4e452ae8524e42797be)) 88 | 89 | ### [5.1.3](https://github.com/whitespace-se/storybook-addon-html/compare/v5.1.2...v5.1.3) (2023-03-10) 90 | 91 | ### [5.1.2](https://github.com/whitespace-se/storybook-addon-html/compare/v5.1.1...v5.1.2) (2023-03-10) 92 | 93 | 94 | ### Bug Fixes 95 | 96 | * Replace removed hljs theme ([d7204aa](https://github.com/whitespace-se/storybook-addon-html/commit/d7204aa57f66e102ea19719786c29a7115d97a8e)) 97 | 98 | ### [5.1.1](https://github.com/whitespace-se/storybook-addon-html/compare/v5.1.0...v5.1.1) (2022-12-15) 99 | 100 | 101 | ### Bug Fixes 102 | 103 | * Outdated peer dep ([81e74f6](https://github.com/whitespace-se/storybook-addon-html/commit/81e74f658b8e60e691a6631061960fc130a187d0)) 104 | 105 | ## [5.1.0](https://github.com/whitespace-se/storybook-addon-html/compare/v5.0.3...v5.1.0) (2022-12-09) 106 | 107 | 108 | ### Features 109 | 110 | * Add transform option for custom manipulation ([e7a35b8](https://github.com/whitespace-se/storybook-addon-html/commit/e7a35b87e9afc8d377460ee131c9501a14810b97)) 111 | 112 | 113 | ### Bug Fixes 114 | 115 | * Match multiline comments ([c23952b](https://github.com/whitespace-se/storybook-addon-html/commit/c23952b75f0e471fd5c50d1a94a5540a9c6c7ad2)) 116 | 117 | 118 | ### Reverts 119 | 120 | * Revert "ci: Remove autoit/conventional-commits" ([74628b2](https://github.com/whitespace-se/storybook-addon-html/commit/74628b2b3be2abe3bce0d7137e63a9ca1aea87a6)) 121 | 122 | ### [5.0.3](https://github.com/whitespace-se/storybook-addon-html/compare/v5.0.2...v5.0.3) (2022-11-11) 123 | 124 | ### [5.0.2](https://github.com/whitespace-se/storybook-addon-html/compare/v5.0.1...v5.0.2) (2022-11-11) 125 | 126 | 127 | ### Features 128 | 129 | * Add `removeComments` option ([5b4a6e6](https://github.com/whitespace-se/storybook-addon-html/commit/5b4a6e6cef0c53b528903eefd3bebd23963e4aa1)), closes [#73](https://github.com/whitespace-se/storybook-addon-html/issues/73) [#64](https://github.com/whitespace-se/storybook-addon-html/issues/64) 130 | 131 | ### [5.0.1](https://github.com/whitespace-se/storybook-addon-html/compare/v5.0.0...v5.0.1) (2022-11-11) 132 | 133 | 134 | ### ⚠ BREAKING CHANGES 135 | 136 | * Complete rewrite based on the official addon kit structure 137 | 138 | ### Code Refactoring 139 | 140 | * Complete rewrite based on the official addon kit structure ([836d4b9](https://github.com/whitespace-se/storybook-addon-html/commit/836d4b97bdbe52a321210e7d612c53b4f3c0c771)) 141 | 142 | ## [5.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v4.2.0...v5.0.0) (2021-03-26) 143 | 144 | ## [4.2.0](https://github.com/whitespace-se/storybook-addon-html/compare/v4.1.0...v4.2.0) (2021-01-07) 145 | 146 | 147 | ### Features 148 | 149 | * allow empty comments to be removed ([5cf46c0](https://github.com/whitespace-se/storybook-addon-html/commit/5cf46c0a1ff31ae4cf4e5b9a000436368e8df77c)) 150 | * allow overriding `showLineNumbers` and `wrapLines` for the highlighter ([121ffb6](https://github.com/whitespace-se/storybook-addon-html/commit/121ffb6260f5f1567d612a8f616d300dec53ed66)), closes [#21](https://github.com/whitespace-se/storybook-addon-html/issues/21) 151 | 152 | ## [4.1.0](https://github.com/whitespace-se/storybook-addon-html/compare/v4.0.2...v4.1.0) (2021-01-07) 153 | 154 | ### [4.0.2](https://github.com/whitespace-se/storybook-addon-html/compare/v4.0.1...v4.0.2) (2020-12-14) 155 | 156 | ### [4.0.1](https://github.com/whitespace-se/storybook-addon-html/compare/v4.0.0...v4.0.1) (2020-12-11) 157 | 158 | 159 | ### Bug Fixes 160 | 161 | * show error message when trying to import framework-specific module ([1ef9e1b](https://github.com/whitespace-se/storybook-addon-html/commit/1ef9e1b68f7757558de8d25e47b50dcc8a96b5d7)), closes [#31](https://github.com/whitespace-se/storybook-addon-html/issues/31) 162 | 163 | ## [4.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v3.0.0...v4.0.0) (2020-12-10) 164 | 165 | 166 | ### ⚠ BREAKING CHANGES 167 | 168 | * add preset and support for att frameworks 169 | 170 | ### Features 171 | 172 | * add preset and support for att frameworks ([51a33c8](https://github.com/whitespace-se/storybook-addon-html/commit/51a33c8b23870dd47ac899b98fb92427329ab971)) 173 | 174 | 175 | ### Bug Fixes 176 | 177 | * assign peer deps ([ae0dabc](https://github.com/whitespace-se/storybook-addon-html/commit/ae0dabc8f316612a9dfa4fe50062667b90643416)) 178 | * **examples/react:** simplify Whitespace logo ([4884b04](https://github.com/whitespace-se/storybook-addon-html/commit/4884b0490c081104d896db7e7afdcf92fe893ffb)) 179 | * re-add support for options via parameters ([ed19b93](https://github.com/whitespace-se/storybook-addon-html/commit/ed19b93ec6c7f3776e5e16866c7a87694d6ec758)) 180 | 181 | ## [3.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v2.0.1...v3.0.0) (2020-12-09) 182 | 183 | ### [2.0.1](https://github.com/whitespace-se/storybook-addon-html/compare/v2.0.0...v2.0.1) (2020-09-09) 184 | 185 | ## [2.0.0](https://github.com/whitespace-se/storybook-addon-html/compare/v1.2.2...v2.0.0) (2020-08-21) 186 | 187 | 188 | ### ⚠ BREAKING CHANGES 189 | 190 | * **deps:** Minimum supported Storybook version is now 6.X.X 191 | 192 | ### Bug Fixes 193 | 194 | * ensure code is shown on first render ([0f033b8](https://github.com/whitespace-se/storybook-addon-html/commit/0f033b8c77178d18e700cd5f105b1fa336a65d51)) 195 | * pin “Copy” button to bottom of panel ([ed0c7d4](https://github.com/whitespace-se/storybook-addon-html/commit/ed0c7d43b236427fb66995256972a31807a98d7b)) 196 | 197 | 198 | ### Miscellaneous Chores 199 | 200 | * **deps:** upgrade to support Storybook 6 ([2b049c9](https://github.com/whitespace-se/storybook-addon-html/commit/2b049c9de87216cedd399876a7bcb38770ef9e40)) 201 | 202 | ### [1.2.2](https://github.com/whitespace-se/storybook-addon-html/compare/v1.2.0...v1.2.2) (2020-05-09) 203 | 204 | ## 1.2.0 (2020-01-07) 205 | 206 | --------------------------------------------------------------------------------