├── .all-contributorsrc
├── .babelrc
├── .circleci
└── config.yml
├── .eslintrc
├── .github
└── workflows
│ ├── chromatic.yml
│ └── codeql-analysis.yml
├── .gitignore
├── .npmignore
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── example
├── .storybook
│ ├── .babelrc
│ ├── addons.js
│ └── config.js
├── components
│ └── simple.js
└── stories
│ ├── array.js
│ ├── decorator.js
│ ├── deep.js
│ ├── fragments.js
│ ├── functions.js
│ ├── index.js
│ ├── simple.js
│ └── withProps.js
├── netlify.toml
├── package.json
├── register.js
├── screenshot.png
├── src
├── __tests__
│ ├── __snapshots__
│ │ └── index.test.js.snap
│ └── index.test.js
├── constants.ts
├── index.tsx
├── jsx.tsx
├── register.tsx
├── renderer.tsx
└── types
│ ├── react-element-to-jsx-string.d.ts
│ └── storybook__ui.d.ts
├── storybook-jsx.png
├── storybook-jsx.sketch
├── storybook-jsx.svg
├── tsconfig.json
└── yarn.lock
/.all-contributorsrc:
--------------------------------------------------------------------------------
1 | {
2 | "projectName": "addon-jsx",
3 | "projectOwner": "storybookjs",
4 | "repoType": "github",
5 | "repoHost": "https://github.com",
6 | "files": [
7 | "README.md"
8 | ],
9 | "imageSize": 100,
10 | "commit": true,
11 | "commitConvention": "none",
12 | "contributors": [
13 | {
14 | "login": "wcastand",
15 | "name": "William",
16 | "avatar_url": "https://avatars3.githubusercontent.com/u/2178244?v=4",
17 | "profile": "https://wcastand.tech/",
18 | "contributions": [
19 | "code",
20 | "design",
21 | "ideas",
22 | "doc"
23 | ]
24 | },
25 | {
26 | "login": "hipstersmoothie",
27 | "name": "Andrew Lisowski",
28 | "avatar_url": "https://avatars3.githubusercontent.com/u/1192452?v=4",
29 | "profile": "http://hipstersmoothie.com",
30 | "contributions": [
31 | "code",
32 | "doc",
33 | "infra",
34 | "maintenance"
35 | ]
36 | },
37 | {
38 | "login": "ndelangen",
39 | "name": "Norbert de Langen",
40 | "avatar_url": "https://avatars2.githubusercontent.com/u/3070389?v=4",
41 | "profile": "https://github.com/ndelangen",
42 | "contributions": [
43 | "code",
44 | "doc"
45 | ]
46 | },
47 | {
48 | "login": "samouss",
49 | "name": "Samuel Vaillant",
50 | "avatar_url": "https://avatars2.githubusercontent.com/u/6513513?v=4",
51 | "profile": "https://github.com/samouss",
52 | "contributions": [
53 | "code",
54 | "doc"
55 | ]
56 | },
57 | {
58 | "login": "alexandrebodin",
59 | "name": "Alexandre BODIN",
60 | "avatar_url": "https://avatars2.githubusercontent.com/u/6065744?v=4",
61 | "profile": "https://twitter.com/_alexandrebodin",
62 | "contributions": [
63 | "code"
64 | ]
65 | },
66 | {
67 | "login": "stof",
68 | "name": "Christophe Coevoet",
69 | "avatar_url": "https://avatars0.githubusercontent.com/u/439401?v=4",
70 | "profile": "https://github.com/stof",
71 | "contributions": [
72 | "code"
73 | ]
74 | },
75 | {
76 | "login": "leonelgalan",
77 | "name": "Leonel Galán",
78 | "avatar_url": "https://avatars3.githubusercontent.com/u/727774?v=4",
79 | "profile": "http://www.leonelgalan.com",
80 | "contributions": [
81 | "code"
82 | ]
83 | },
84 | {
85 | "login": "Landerson352",
86 | "name": "Lincoln Anderson",
87 | "avatar_url": "https://avatars3.githubusercontent.com/u/5214462?v=4",
88 | "profile": "http://threefivetwo.com",
89 | "contributions": [
90 | "code"
91 | ]
92 | },
93 | {
94 | "login": "smollweide",
95 | "name": "Simon Mollweide",
96 | "avatar_url": "https://avatars2.githubusercontent.com/u/2912007?v=4",
97 | "profile": "https://github.com/smollweide",
98 | "contributions": [
99 | "code"
100 | ]
101 | },
102 | {
103 | "login": "lflpowell",
104 | "name": "lflpowell",
105 | "avatar_url": "https://avatars0.githubusercontent.com/u/37211236?v=4",
106 | "profile": "https://github.com/lflpowell",
107 | "contributions": [
108 | "code"
109 | ]
110 | },
111 | {
112 | "login": "expe-lbenychou",
113 | "name": "lionelbenychou",
114 | "avatar_url": "https://avatars1.githubusercontent.com/u/31204794?v=4",
115 | "profile": "https://github.com/expe-lbenychou",
116 | "contributions": [
117 | "code"
118 | ]
119 | },
120 | {
121 | "login": "breadadams",
122 | "name": "Brad Adams",
123 | "avatar_url": "https://avatars1.githubusercontent.com/u/5795227?v=4",
124 | "profile": "http://breadadams.com",
125 | "contributions": [
126 | "doc"
127 | ]
128 | },
129 | {
130 | "login": "arahansen",
131 | "name": "Andrew Hansen",
132 | "avatar_url": "https://avatars0.githubusercontent.com/u/8746094?v=4",
133 | "profile": "http://twitter.com/arahansen",
134 | "contributions": [
135 | "code"
136 | ]
137 | },
138 | {
139 | "login": "petermikitsh",
140 | "name": "Peter Mikitsh",
141 | "avatar_url": "https://avatars3.githubusercontent.com/u/1571918?v=4",
142 | "profile": "http://peter.mikit.sh",
143 | "contributions": [
144 | "doc",
145 | "code"
146 | ]
147 | },
148 | {
149 | "login": "lisamartin00",
150 | "name": "lisamartin00",
151 | "avatar_url": "https://avatars0.githubusercontent.com/u/6465955?v=4",
152 | "profile": "https://github.com/lisamartin00",
153 | "contributions": [
154 | "code"
155 | ]
156 | },
157 | {
158 | "login": "semihraifgurel",
159 | "name": "Semih Raif Gürel",
160 | "avatar_url": "https://avatars.githubusercontent.com/u/29544960?v=4",
161 | "profile": "https://github.com/semihraifgurel",
162 | "contributions": [
163 | "doc"
164 | ]
165 | },
166 | {
167 | "login": "leepowelldev",
168 | "name": "Lee Powell",
169 | "avatar_url": "https://avatars.githubusercontent.com/u/602052?v=4",
170 | "profile": "https://leepowell.dev",
171 | "contributions": [
172 | "infra",
173 | "code"
174 | ]
175 | },
176 | {
177 | "login": "jimmyandrade",
178 | "name": "Jimmy Andrade",
179 | "avatar_url": "https://avatars.githubusercontent.com/u/2307245?v=4",
180 | "profile": "http://jimmyandrade.com",
181 | "contributions": [
182 | "infra"
183 | ]
184 | }
185 | ],
186 | "contributorsPerLine": 7
187 | }
188 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "shippedProposals": true
7 | }
8 | ],
9 | "@babel/preset-react",
10 | "@babel/preset-typescript"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | defaults: &defaults
4 | working_directory: ~/storybook-addon-jsx
5 | docker:
6 | - image: circleci/node:latest-browsers
7 |
8 | jobs:
9 | install:
10 | <<: *defaults
11 | steps:
12 | - checkout
13 | - restore_cache:
14 | keys:
15 | # Find a cache corresponding to this specific package.json checksum
16 | # when this file is changed, this key will fail
17 | - storybook-addon-jsx-{{ .Branch }}-{{ checksum "yarn.lock" }}-{{ checksum ".circleci/config.yml" }}
18 | - storybook-addon-jsx-{{ .Branch }}-{{ checksum "yarn.lock" }}
19 | - storybook-addon-jsx-{{ .Branch }}
20 | # Find the most recent cache used from any branch
21 | - storybook-addon-jsx-master
22 | - storybook-addon-jsx-
23 | - run:
24 | name: Install Dependencies
25 | command: yarn install --frozen-lockfile
26 | - save_cache:
27 | key: storybook-addon-jsx-{{ .Branch }}-{{ checksum "yarn.lock" }}-{{ checksum ".circleci/config.yml" }}
28 | paths:
29 | - node_modules
30 | - ~/.cache/yarn
31 | - persist_to_workspace:
32 | root: .
33 | paths:
34 | - .
35 |
36 | test:
37 | <<: *defaults
38 | steps:
39 | - attach_workspace:
40 | at: ~/storybook-addon-jsx
41 | - run:
42 | name: Test
43 | command: yarn test
44 |
45 | lint:
46 | <<: *defaults
47 | steps:
48 | - attach_workspace:
49 | at: ~/storybook-addon-jsx
50 | - run:
51 | name: Lint
52 | command: yarn lint
53 |
54 | build:
55 | <<: *defaults
56 | steps:
57 | - attach_workspace:
58 | at: ~/storybook-addon-jsx
59 | - run:
60 | name: Build
61 | command: yarn build
62 | - persist_to_workspace:
63 | root: .
64 | paths:
65 | - .
66 |
67 | release:
68 | <<: *defaults
69 | steps:
70 | - attach_workspace:
71 | at: ~/storybook-addon-jsx
72 | - run:
73 | name: Release
74 | command: yarn run release
75 |
76 | workflows:
77 | version: 2
78 | build_and_test:
79 | jobs:
80 | - install
81 |
82 | - test:
83 | requires:
84 | - install
85 |
86 | - lint:
87 | requires:
88 | - install
89 |
90 | - build:
91 | requires:
92 | - install
93 |
94 | - release:
95 | requires:
96 | - lint
97 | - test
98 | - build
99 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@design-systems",
3 | "rules": {
4 | "no-undef": 0
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.github/workflows/chromatic.yml:
--------------------------------------------------------------------------------
1 | name: 'Chromatic'
2 | on: pull_request
3 |
4 | jobs:
5 | test:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v1
9 | - run: |
10 | yarn
11 | - uses: chromaui/action@v1
12 | with:
13 | appCode: qceepgaflpj
14 | token: ${{ secrets.GITHUB_TOKEN }}
15 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | name: "CodeQL"
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | # The branches below must be a subset of the branches above
8 | branches: [ master ]
9 | schedule:
10 | - cron: '35 3 * * 2'
11 |
12 | jobs:
13 | analyze:
14 | name: Analyze
15 | runs-on: ubuntu-latest
16 | permissions:
17 | actions: read
18 | contents: read
19 | security-events: write
20 |
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | language: [ 'javascript' ]
25 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
26 | # Learn more:
27 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
28 |
29 | steps:
30 | - name: Checkout repository
31 | uses: actions/checkout@v2
32 |
33 | # Initializes the CodeQL tools for scanning.
34 | - name: Initialize CodeQL
35 | uses: github/codeql-action/init@v1
36 | with:
37 | languages: ${{ matrix.language }}
38 | # If you wish to specify custom queries, you can do so here or in a config file.
39 | # By default, queries listed here will override any specified in a config file.
40 | # Prefix the list here with "+" to use these queries and those in the config file.
41 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
42 |
43 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
44 | # If this step fails, then you should remove it and run the build manually (see below)
45 | - name: Autobuild
46 | uses: github/codeql-action/autobuild@v1
47 |
48 | # ℹ️ Command-line programs to run using the OS shell.
49 | # 📚 https://git.io/JvXDl
50 |
51 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
52 | # and modify them (or add more) to build your code if your project
53 | # uses a compiled language
54 |
55 | #- run: |
56 | # make bootstrap
57 | # make release
58 |
59 | - name: Perform CodeQL Analysis
60 | uses: github/codeql-action/analyze@v1
61 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
3 | *.log
4 | .idea
5 | storybook-static
6 | .env
7 | .eslintcache
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | src
2 | .babelrc
3 | .vscode
4 | example
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Placez vos paramètres dans ce fichier pour remplacer les paramètres par défaut et les paramètres utilisateur.
2 | {
3 | "prettier.bracketSpacing": true,
4 | "prettier.semi": false,
5 | "prettier.singleQuote": true,
6 | "prettier.trailingComma": "all",
7 | "prettier.tabWidth": 2,
8 | "prettier.printWidth": 100,
9 | "editor.formatOnSave": true,
10 | "editor.tabSize": 2,
11 | "deepscan.enable": true
12 | }
13 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # v7.3.14 (Tue Sep 14 2021)
2 |
3 | #### 🐛 Bug Fix
4 |
5 | - Bump tar from 4.4.15 to 4.4.19 [#160](https://github.com/storybookjs/addon-jsx/pull/160) ([@dependabot[bot]](https://github.com/dependabot[bot]))
6 |
7 | #### Authors: 1
8 |
9 | - [@dependabot[bot]](https://github.com/dependabot[bot])
10 |
11 | ---
12 |
13 | # v7.3.13 (Tue Aug 24 2021)
14 |
15 | #### 🐛 Bug Fix
16 |
17 | - Bump tar from 4.4.13 to 4.4.15 [#157](https://github.com/storybookjs/addon-jsx/pull/157) ([@dependabot[bot]](https://github.com/dependabot[bot]))
18 | - Bump path-parse from 1.0.6 to 1.0.7 [#158](https://github.com/storybookjs/addon-jsx/pull/158) ([@dependabot[bot]](https://github.com/dependabot[bot]))
19 |
20 | #### Authors: 1
21 |
22 | - [@dependabot[bot]](https://github.com/dependabot[bot])
23 |
24 | ---
25 |
26 | # v7.3.12 (Tue Jun 22 2021)
27 |
28 | :tada: This release contains work from a new contributor! :tada:
29 |
30 | Thank you, Jimmy Andrade ([@jimmyandrade](https://github.com/jimmyandrade)), for all your work!
31 |
32 | #### 🐛 Bug Fix
33 |
34 | - ci: run CodeQL analysis [#156](https://github.com/storybookjs/addon-jsx/pull/156) ([@jimmyandrade](https://github.com/jimmyandrade))
35 | - Bump markdown-to-jsx from 6.10.3 to 6.11.4 [#125](https://github.com/storybookjs/addon-jsx/pull/125) ([@dependabot[bot]](https://github.com/dependabot[bot]))
36 | - Bump elliptic from 6.5.1 to 6.5.4 [#137](https://github.com/storybookjs/addon-jsx/pull/137) ([@dependabot[bot]](https://github.com/dependabot[bot]))
37 |
38 | #### Authors: 2
39 |
40 | - [@dependabot[bot]](https://github.com/dependabot[bot])
41 | - Jimmy Andrade ([@jimmyandrade](https://github.com/jimmyandrade))
42 |
43 | ---
44 |
45 | # v7.3.11 (Tue Jun 22 2021)
46 |
47 | #### 🐛 Bug Fix
48 |
49 | - Bump websocket-extensions from 0.1.3 to 0.1.4 [#111](https://github.com/storybookjs/addon-jsx/pull/111) ([@dependabot[bot]](https://github.com/dependabot[bot]))
50 | - Bump yargs-parser from 13.1.1 to 13.1.2 [#127](https://github.com/storybookjs/addon-jsx/pull/127) ([@dependabot[bot]](https://github.com/dependabot[bot]))
51 | - Bump nested-object-assign from 1.0.3 to 1.0.4 [#133](https://github.com/storybookjs/addon-jsx/pull/133) ([@dependabot[bot]](https://github.com/dependabot[bot]))
52 | - Bump ini from 1.3.5 to 1.3.8 [#136](https://github.com/storybookjs/addon-jsx/pull/136) ([@dependabot[bot]](https://github.com/dependabot[bot]))
53 | - Bump lodash from 4.17.15 to 4.17.21 [#143](https://github.com/storybookjs/addon-jsx/pull/143) ([@dependabot[bot]](https://github.com/dependabot[bot]))
54 | - Bump y18n from 4.0.0 to 4.0.3 [#147](https://github.com/storybookjs/addon-jsx/pull/147) ([@dependabot[bot]](https://github.com/dependabot[bot]))
55 | - Bump postcss from 7.0.18 to 7.0.36 [#155](https://github.com/storybookjs/addon-jsx/pull/155) ([@dependabot[bot]](https://github.com/dependabot[bot]))
56 | - Bump handlebars from 4.4.5 to 4.7.7 [#144](https://github.com/storybookjs/addon-jsx/pull/144) ([@dependabot[bot]](https://github.com/dependabot[bot]))
57 | - Bump ua-parser-js from 0.7.20 to 0.7.28 [#150](https://github.com/storybookjs/addon-jsx/pull/150) ([@dependabot[bot]](https://github.com/dependabot[bot]))
58 | - Bump url-parse from 1.4.7 to 1.5.1 [#151](https://github.com/storybookjs/addon-jsx/pull/151) ([@dependabot[bot]](https://github.com/dependabot[bot]))
59 | - Bump merge-deep from 3.0.2 to 3.0.3 [#154](https://github.com/storybookjs/addon-jsx/pull/154) ([@dependabot[bot]](https://github.com/dependabot[bot]))
60 |
61 | #### Authors: 1
62 |
63 | - [@dependabot[bot]](https://github.com/dependabot[bot])
64 |
65 | ---
66 |
67 | # v7.3.10 (Thu May 13 2021)
68 |
69 | #### 🐛 Bug Fix
70 |
71 | - Bump hosted-git-info from 2.8.5 to 2.8.9 [#152](https://github.com/storybookjs/addon-jsx/pull/152) ([@dependabot[bot]](https://github.com/dependabot[bot]))
72 |
73 | #### Authors: 1
74 |
75 | - [@dependabot[bot]](https://github.com/dependabot[bot])
76 |
77 | ---
78 |
79 | # v7.3.9 (Wed Apr 21 2021)
80 |
81 | #### 🐛 Bug Fix
82 |
83 | - Bump ssri from 6.0.1 to 6.0.2 [#148](https://github.com/storybookjs/addon-jsx/pull/148) ([@dependabot[bot]](https://github.com/dependabot[bot]))
84 |
85 | #### Authors: 1
86 |
87 | - [@dependabot[bot]](https://github.com/dependabot[bot])
88 |
89 | ---
90 |
91 | # v7.3.8 (Sun Apr 18 2021)
92 |
93 | #### 🐛 Bug Fix
94 |
95 | - Bump gitlog from 4.0.0 to 4.0.4 [#146](https://github.com/storybookjs/addon-jsx/pull/146) ([@dependabot[bot]](https://github.com/dependabot[bot]))
96 |
97 | #### Authors: 1
98 |
99 | - [@dependabot[bot]](https://github.com/dependabot[bot])
100 |
101 | ---
102 |
103 | # v7.3.7 (Wed Mar 31 2021)
104 |
105 | #### 🐛 Bug Fix
106 |
107 | - Support React 17 peer dependency [#142](https://github.com/storybookjs/addon-jsx/pull/142) ([@leepowelldev](https://github.com/leepowelldev))
108 |
109 | #### Authors: 1
110 |
111 | - Lee Powell ([@leepowelldev](https://github.com/leepowelldev))
112 |
113 | ---
114 |
115 | # v7.3.6 (Tue Feb 09 2021)
116 |
117 | #### 🐛 Bug Fix
118 |
119 | - fix copy button positioning on long jsx content [#135](https://github.com/storybookjs/addon-jsx/pull/135) ([@hipstersmoothie](https://github.com/hipstersmoothie))
120 |
121 | #### Authors: 1
122 |
123 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
124 |
125 | ---
126 |
127 | # v7.3.5 (Tue Feb 09 2021)
128 |
129 | :tada: This release contains work from a new contributor! :tada:
130 |
131 | Thank you, Semih Raif Gürel ([@semihraifgurel](https://github.com/semihraifgurel)), for all your work!
132 |
133 | #### 🐛 Bug Fix
134 |
135 | - Custom component name [#132](https://github.com/storybookjs/addon-jsx/pull/132) (semih@weptile.com)
136 |
137 | #### Authors: 1
138 |
139 | - Semih Raif Gürel ([@semihraifgurel](https://github.com/semihraifgurel))
140 |
141 | ---
142 |
143 | # v7.3.4 (Thu Aug 13 2020)
144 |
145 | #### 🐛 Bug Fix
146 |
147 | - hide default props as the default [#122](https://github.com/storybookjs/addon-jsx/pull/122) ([@hipstersmoothie](https://github.com/hipstersmoothie))
148 |
149 | #### Authors: 1
150 |
151 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
152 |
153 | ---
154 |
155 | # v7.3.3 (Fri Jul 17 2020)
156 |
157 | #### 🐛 Bug Fix
158 |
159 | - fix skip [#119](https://github.com/storybookjs/addon-jsx/pull/119) ([@hipstersmoothie](https://github.com/hipstersmoothie))
160 |
161 | #### Authors: 1
162 |
163 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
164 |
165 | ---
166 |
167 | # v7.3.2 (Wed Jul 15 2020)
168 |
169 | :tada: This release contains work from a new contributor! :tada:
170 |
171 | Thank you, null[@lisamartin00](https://github.com/lisamartin00), for all your work!
172 |
173 | #### 🐛 Bug Fix
174 |
175 | - Fix unique key prop warning [#117](https://github.com/storybookjs/addon-jsx/pull/117) ([@lisamartin00](https://github.com/lisamartin00))
176 |
177 | #### Authors: 1
178 |
179 | - [@lisamartin00](https://github.com/lisamartin00)
180 |
181 | ---
182 |
183 | # v7.3.1 (Fri Jul 10 2020)
184 |
185 | #### 🐛 Bug Fix
186 |
187 | - docs overhaul [#115](https://github.com/storybookjs/addon-jsx/pull/115) ([@hipstersmoothie](https://github.com/hipstersmoothie))
188 |
189 | #### Authors: 1
190 |
191 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
192 |
193 | ---
194 |
195 | # v7.3.0 (Fri Jun 05 2020)
196 |
197 | :tada: This release contains work from a new contributor! :tada:
198 |
199 | Thank you, Peter Mikitsh ([@petermikitsh](https://github.com/petermikitsh)), for all your work!
200 |
201 | #### 🚀 Enhancement
202 |
203 | - feat: disable jsx per story [#110](https://github.com/storybookjs/addon-jsx/pull/110) ([@petermikitsh](https://github.com/petermikitsh))
204 |
205 | #### 📝 Documentation
206 |
207 | - Update auto + add all-contributors [#108](https://github.com/storybookjs/addon-jsx/pull/108) ([@hipstersmoothie](https://github.com/hipstersmoothie))
208 |
209 | #### Authors: 2
210 |
211 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
212 | - Peter Mikitsh ([@petermikitsh](https://github.com/petermikitsh))
213 |
214 | ---
215 |
216 | # v7.2.3 (Tue Apr 14 2020)
217 |
218 | #### 🐛 Bug Fix
219 |
220 | - corral runaway useEffect [#104](https://github.com/storybookjs/addon-jsx/pull/104) ([@hipstersmoothie](https://github.com/hipstersmoothie))
221 |
222 | #### Authors: 1
223 |
224 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
225 |
226 | ---
227 |
228 | # v7.2.2 (Mon Apr 13 2020)
229 |
230 | #### 🐛 Bug Fix
231 |
232 | - fix children bug [#103](https://github.com/storybookjs/addon-jsx/pull/103) ([@hipstersmoothie](https://github.com/hipstersmoothie) [@github-actions[bot]](https://github.com/github-actions[bot]))
233 |
234 | #### Authors: 2
235 |
236 | - [@github-actions[bot]](https://github.com/github-actions[bot])
237 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
238 |
239 | ---
240 |
241 | # v7.2.1 (Sat Apr 11 2020)
242 |
243 | #### 🐛 Bug Fix
244 |
245 | - use stack to track last component [#102](https://github.com/storybookjs/addon-jsx/pull/102) ([@hipstersmoothie](https://github.com/hipstersmoothie))
246 |
247 | #### Authors: 1
248 |
249 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
250 |
251 | ---
252 |
253 | # v7.2.0 (Fri Apr 10 2020)
254 |
255 | #### 🚀 Enhancement
256 |
257 | - Show type info on hover [#101](https://github.com/storybookjs/addon-jsx/pull/101) ([@hipstersmoothie](https://github.com/hipstersmoothie))
258 |
259 | #### Authors: 1
260 |
261 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
262 |
263 | ---
264 |
265 | # v7.1.15 (Mon Mar 16 2020)
266 |
267 | #### 🐛 Bug Fix
268 |
269 | - Bump acorn from 5.7.3 to 5.7.4 [#99](https://github.com/storybookjs/addon-jsx/pull/99) ([@dependabot[bot]](https://github.com/dependabot[bot]))
270 |
271 | #### Authors: 1
272 |
273 | - [@dependabot[bot]](https://github.com/dependabot[bot])
274 |
275 | ---
276 |
277 | # v7.1.14 (Thu Jan 23 2020)
278 |
279 | #### 🐛 Bug Fix
280 |
281 | - feat: Upgrade react-element-to-jsx-string to latest version [#97](https://github.com/storybookjs/addon-jsx/pull/97) ([@leonelgalan](https://github.com/leonelgalan))
282 |
283 | #### Authors: 1
284 |
285 | - Leonel Galán ([@leonelgalan](https://github.com/leonelgalan))
286 |
287 | ---
288 |
289 | # v7.1.13 (Fri Oct 25 2019)
290 |
291 | #### 🐛 Bug Fix
292 |
293 | - [ImgBot] Optimize images [#93](https://github.com/storybookjs/addon-jsx/pull/93) ([@ImgBotApp](https://github.com/ImgBotApp))
294 |
295 | #### Authors: 1
296 |
297 | - Imgbot ([@ImgBotApp](https://github.com/ImgBotApp))
298 |
299 | ---
300 |
301 | # v7.1.12 (Wed Oct 23 2019)
302 |
303 | #### 🐛 Bug Fix
304 |
305 | - Use storybook syntax-highlighter [#92](https://github.com/storybookjs/addon-jsx/pull/92) ([@ndelangen](https://github.com/ndelangen) [@github-actions[bot]](https://github.com/github-actions[bot]))
306 |
307 | #### Authors: 2
308 |
309 | - Norbert de Langen ([@ndelangen](https://github.com/ndelangen))
310 | - [@github-actions[bot]](https://github.com/github-actions[bot])
311 |
312 | ---
313 |
314 | # v7.1.11 (Wed Oct 23 2019)
315 |
316 | #### 🐛 Bug Fix
317 |
318 | - UPGRADES [#91](https://github.com/storybookjs/addon-jsx/pull/91) ([@ndelangen](https://github.com/ndelangen) [@github-actions[bot]](https://github.com/github-actions[bot]))
319 |
320 | #### Authors: 2
321 |
322 | - Norbert de Langen ([@ndelangen](https://github.com/ndelangen))
323 | - [@github-actions[bot]](https://github.com/github-actions[bot])
324 |
325 | ---
326 |
327 | # v7.1.10 (Wed Oct 23 2019)
328 |
329 | #### 🐛 Bug Fix
330 |
331 | - Upgrade dependencies [#90](https://github.com/storybookjs/addon-jsx/pull/90) ([@stof](https://github.com/stof) [@ndelangen](https://github.com/ndelangen))
332 |
333 | #### Authors: 2
334 |
335 | - Christophe Coevoet ([@stof](https://github.com/stof))
336 | - Norbert de Langen ([@ndelangen](https://github.com/ndelangen))
337 |
338 | ---
339 |
340 | # v7.1.9 (Wed Oct 23 2019)
341 |
342 | #### ⚠️ Pushed to master
343 |
344 | - FIX ref to incorrect config path for storybook ([@ndelangen](https://github.com/ndelangen))
345 |
346 | #### Authors: 1
347 |
348 | - Norbert de Langen ([@ndelangen](https://github.com/ndelangen))
349 |
350 | ---
351 |
352 | # v7.1.7 (Wed Oct 23 2019)
353 |
354 | #### ⚠️ Pushed to master
355 |
356 | - ADD required build-storybook command for action to work ([@ndelangen](https://github.com/ndelangen))
357 | - ADD chromatic ([@ndelangen](https://github.com/ndelangen))
358 |
359 | #### Authors: 1
360 |
361 | - Norbert de Langen ([@ndelangen](https://github.com/ndelangen))
362 |
363 | ---
364 |
365 | # v7.1.6 (Sun Sep 01 2019)
366 |
367 | ---
368 |
369 | # v7.1.5 (Fri Jul 19 2019)
370 |
371 | ---
372 |
373 | # v7.1.3 (Fri Jul 19 2019)
374 |
375 | #### 🏠 Internal
376 |
377 | - move auto to CI [#82](https://github.com/storybookjs/addon-jsx/pull/82) ([@hipstersmoothie](https://github.com/hipstersmoothie))
378 | - Bump handlebars from 4.1.1 to 4.1.2 [#74](https://github.com/storybookjs/addon-jsx/pull/74) ([@dependabot[bot]](https://github.com/dependabot[bot]))
379 |
380 | #### Authors: 2
381 |
382 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
383 | - [@dependabot[bot]](https://github.com/dependabot[bot])
384 |
385 | ---
386 |
387 | # v7.1.2 (Sat Apr 27 2019)
388 |
389 | #### 🐛 Bug Fix
390 |
391 | - replace escaped quotes with single quotes for better rendering [#69](https://github.com/storybooks/addon-jsx/pull/69) ([@hipstersmoothie](https://github.com/hipstersmoothie))
392 |
393 | #### 📝 Documentation
394 |
395 | - add using with IE11 docs [#71](https://github.com/storybooks/addon-jsx/pull/71) ([@hipstersmoothie](https://github.com/hipstersmoothie))
396 | - add storyshot testing docs [#70](https://github.com/storybooks/addon-jsx/pull/70) ([@hipstersmoothie](https://github.com/hipstersmoothie))
397 |
398 | #### Authors: 1
399 |
400 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
401 |
402 | ---
403 |
404 | # v7.1.1 (Sat Apr 27 2019)
405 |
406 | #### 🐛 Bug Fix
407 |
408 | - fix key issue [#67](https://github.com/storybooks/addon-jsx/pull/67) ([@hipstersmoothie](https://github.com/hipstersmoothie))
409 |
410 | #### 🏠 Internal
411 |
412 | - update auto [#68](https://github.com/storybooks/addon-jsx/pull/68) ([@hipstersmoothie](https://github.com/hipstersmoothie))
413 |
414 | #### Authors: 1
415 |
416 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
417 |
418 | ---
419 |
420 | # v7.1.0 (Fri Mar 22 2019)
421 |
422 | #### 🚀 Enhancement
423 |
424 | - Theme support [#62](https://github.com/storybooks/addon-jsx/pull/62) ([@lflpowell](https://github.com/lflpowell) [@hipstersmoothie](https://github.com/hipstersmoothie))
425 |
426 | #### 🐛 Bug Fix
427 |
428 | - fix circle build [#63](https://github.com/storybooks/addon-jsx/pull/63) ([@hipstersmoothie](https://github.com/hipstersmoothie))
429 |
430 | #### 🏠 Internal
431 |
432 | - add released plugin to auto [#64](https://github.com/storybooks/addon-jsx/pull/64) ([@hipstersmoothie](https://github.com/hipstersmoothie))
433 |
434 | #### Authors: 2
435 |
436 | - [@lflpowell](https://github.com/lflpowell)
437 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
438 |
439 | ---
440 |
441 | # v7.0.2 (Wed Mar 20 2019)
442 |
443 | #### 🐛 Bug Fix
444 |
445 | - fix types [#61](https://github.com/storybooks/addon-jsx/pull/61) ([@hipstersmoothie](https://github.com/hipstersmoothie))
446 |
447 | #### 🏠 Internal
448 |
449 | - Add Fragment Tests [#57](https://github.com/storybooks/addon-jsx/pull/57) ([@hipstersmoothie](https://github.com/hipstersmoothie))
450 |
451 | #### Authors: 1
452 |
453 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
454 |
455 | ---
456 |
457 | # v7.0.1 (Mon Mar 18 2019)
458 |
459 | #### 🏠 Internal
460 |
461 | - add circle config [#56](https://github.com/storybooks/addon-jsx/pull/56) ([@hipstersmoothie](https://github.com/hipstersmoothie))
462 | - add tests for decorator [#55](https://github.com/storybooks/addon-jsx/pull/55) ([@hipstersmoothie](https://github.com/hipstersmoothie))
463 | - add type build [#53](https://github.com/storybooks/addon-jsx/pull/53) ([@hipstersmoothie](https://github.com/hipstersmoothie))
464 |
465 | #### 📝 Documentation
466 |
467 | - correct docs [#52](https://github.com/storybooks/addon-jsx/pull/52) ([@hipstersmoothie](https://github.com/hipstersmoothie))
468 |
469 | #### Authors: 1
470 |
471 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
472 |
473 | ---
474 |
475 | # v7.0.0 (Fri Mar 15 2019)
476 |
477 | #### 💥 Breaking Change
478 |
479 | - Works with v5 + Written in TypeScript + Decorator Support [#51](https://github.com/storybooks/addon-jsx/pull/51) ([@hipstersmoothie](https://github.com/hipstersmoothie))
480 |
481 | #### Authors: 1
482 |
483 | - Andrew Lisowski ([@hipstersmoothie](https://github.com/hipstersmoothie))
484 |
485 | ---
486 |
487 | # v5.1.1 (Fri Mar 15 2019)
488 |
489 | #### 🐛 Bug Fix
490 |
491 | - Move `active` check out of the `kind` condition [#49](https://github.com/storybooks/addon-jsx/pull/49) ([@Landerson352](https://github.com/Landerson352))
492 | - fix(register): pass Title directly to panel [#43](https://github.com/storybooks/addon-jsx/pull/43) (wuxx1045@umn.edu)
493 | - feat(render-jsx): add onBeforeRender option to manipulate jsx render output [#39](https://github.com/storybooks/addon-jsx/pull/39) ([@smollweide](https://github.com/smollweide))
494 | - Update README.md [#33](https://github.com/storybooks/addon-jsx/pull/33) ([@breadadams](https://github.com/breadadams))
495 | - Beautify html if template string is being displayed. [#29](https://github.com/storybooks/addon-jsx/pull/29) (alfredo.delgado@gmail.com)
496 | - Add support for Vue stories … [#27](https://github.com/storybooks/addon-jsx/pull/27) (ndelangen@me.com)
497 |
498 | #### ⚠️ Pushed to master
499 |
500 | - add auto ([@lisowski54@gmail.com](https://github.com/lisowski54@gmail.com))
501 | - 5.4.0 ([@ndelangen](https://github.com/ndelangen))
502 | - UPDATE dependencies ([@ndelangen](https://github.com/ndelangen))
503 | - 5.3.0 ([@adelgado@chewy.com](https://github.com/adelgado@chewy.com))
504 | - 5.2.0 ([@ndelangen](https://github.com/ndelangen))
505 | - ADD netlify command ([@ndelangen](https://github.com/ndelangen))
506 | - UPGRADE && format ([@ndelangen](https://github.com/ndelangen))
507 | - Update README.md ([@ndelangen](https://github.com/ndelangen))
508 | - Update README.md ([@ndelangen](https://github.com/ndelangen))
509 |
510 | #### Authors: 9
511 |
512 | - Lincoln Anderson ([@Landerson352](https://github.com/Landerson352))
513 | - wuxx1045@umn.edu
514 | - Simon Mollweide ([@smollweide](https://github.com/smollweide))
515 | - Brad Adams ([@breadadams](https://github.com/breadadams))
516 | - alfredo.delgado@gmail.com
517 | - ndelangen@me.com
518 | - [@lisowski54@gmail.com](https://github.com/lisowski54@gmail.com)
519 | - [@ndelangen](https://github.com/ndelangen)
520 | - [@adelgado@chewy.com](https://github.com/adelgado@chewy.com)
521 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Your Name.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Storybook-addon-jsx
5 |
6 |
7 | [](https://travis-ci.org/Kilix/storybook-addon-jsx)
8 | [](https://www.npmjs.com/package/storybook-addon-jsx)
9 | [](https://www.npmjs.com/package/storybook-addon-jsx)
10 |
11 | This Storybook addon shows you the JSX of the story.
12 | This preview works for Vue components as well.
13 | The outputted JSX will reflect any changes made to the storybok by knobs or controls.
14 |
15 | 
16 |
17 | ## Getting started
18 |
19 | ### Installation
20 |
21 | First install the addon from `npm`:
22 |
23 | ```sh
24 | npm i --save-dev storybook-addon-jsx
25 | # or
26 | yarn add --dev storybook-addon-jsx
27 | ```
28 |
29 | ### Configuration
30 |
31 | For the latest storybook all you need to do is add the addon to your `.storybook/main.js`:
32 |
33 | ```js
34 | module.exports = {
35 | addons: ['storybook-addon-jsx']
36 | };
37 | ```
38 |
39 | If you are using storybook@5.x or lower you will need to add the following to `.storybook/addons.js`:
40 |
41 | ```js
42 | import 'storybook-addon-jsx/register';
43 | ```
44 |
45 | ### Usage
46 |
47 | Import it into your stories file and then use it when you write stories:
48 |
49 | ```js
50 | import React from "react";
51 | import { storiesOf } from "@storybook/react";
52 | import { jsxDecorator } from "storybook-addon-jsx";
53 |
54 | import { TestComponent } from './TestComponent':
55 |
56 | export default {
57 | title: "Components/TestComponent",
58 | decorators: [jsxDecorator],
59 | };
60 |
61 | export const Paris = () => (
62 |
63 | Hello
64 |
65 | );
66 |
67 | export const Orleans = () => Hello ;
68 | ```
69 |
70 | Or to configure it globally add the `jsxDecorator` to your `.storybook/preview.js`:
71 |
72 | ```js
73 | const { addDecorator } = require('@storybook/react');
74 | const { jsxDecorator } = require('storybook-addon-jsx');
75 |
76 | addDecorator(jsxDecorator);
77 | ```
78 |
79 | #### Vue
80 |
81 | You can also use this addon with `@storybook/vue`.
82 |
83 | **`.storybook/preview.js`**
84 |
85 | ```js
86 | import { configure, addDecorator } from '@storybook/vue';
87 | import { jsxDecorator } from 'storybook-addon-jsx';
88 |
89 | addDecorator(jsxDecorator);
90 | ```
91 |
92 | If a Vue story defines its view with a template string then it will be displayed.
93 |
94 | ```js
95 | import { storiesOf } from '@storybook/vue';
96 |
97 | storiesOf('Vue', module).add('template property', () => ({
98 | template: `
`
99 | }));
100 | ```
101 |
102 | ## Options
103 |
104 | ### JSX
105 |
106 | This addon support all options from [react-element-to-jsx-string](https://github.com/algolia/react-element-to-jsx-string) as well as the following options.
107 |
108 | - `skip` (default: 0) : Skip element in your component to display
109 |
110 | ```javascript
111 | export default {
112 | title: 'Components/TestComponent',
113 | parameters: {
114 | jsx: { skip: 1 }
115 | }
116 | };
117 | ```
118 |
119 | - `onBeforeRender(domString: string) => string` (default: undefined) : function that receives the dom as a string before render.
120 |
121 | ```js
122 | export default {
123 | title: 'Components/TestComponent',
124 | parameters: {
125 | jsx: {
126 | onBeforeRender: domString => {
127 | if (domString.search('dangerouslySetInnerHTML') < 0) {
128 | return '';
129 | }
130 |
131 | try {
132 | domString = /(dangerouslySetInnerHTML={{)([^}}]*)/.exec(domString)[2];
133 | domString = /(')([^']*)/.exec(domString)[2];
134 | } catch (err) {}
135 |
136 | return domString;
137 | }
138 | }
139 | }
140 | };
141 | ```
142 |
143 | - `displayName` (default: 0) : You can manually name the components that use useMemo or useRef.
144 |
145 | ```javascript
146 | export default {
147 | title: 'Components/TestComponent',
148 | parameters: {
149 | jsx: {
150 | displayName: () => 'CustomName'
151 | }
152 | }
153 | };
154 | ```
155 |
156 | ### Disable JSX Addon
157 |
158 | If enabled globally, the JSX addon can be disabled on individual stories:
159 |
160 | ```jsx
161 | export const Simple = () => Hello
;
162 |
163 | Simple.story = {
164 | parameters: {
165 | jsx: {
166 | disable: true
167 | }
168 | }
169 | };
170 | ```
171 |
172 | ### Vue Options
173 |
174 | - `enableBeautify` (default: true) : Beautify the template string
175 | - All HTML options from [js-beautify](https://github.com/beautify-web/js-beautify#css--html)
176 |
177 | ## Global Options
178 |
179 | To configure global options for this plugin, add the following to your `config.js`.
180 |
181 | ```js
182 | import { addParameters } from '@storybook/react';
183 |
184 | addParameters({
185 | jsx: {
186 | // your options
187 | }
188 | });
189 | ```
190 |
191 | ## Function Props
192 |
193 | If you provide a funtion to one of your props `storybook-addon-jsx` will display that functions `toString` result.
194 | This is usaully very ugly.
195 | To override this include the following util function that will print an easiy to read string.
196 |
197 | ```tsx
198 | /**
199 | * Overrides the toString on a function so that it addon-jsx prints
200 | * the callbacks in a copy-paste-able way.
201 | */
202 | export const callback = (fn: T): T => {
203 | /** A toString to render the function in storybook */
204 | // eslint-disable-next-line no-param-reassign
205 | fn.toString = () => '() => {}';
206 | return fn;
207 | };
208 | ```
209 |
210 | This works well with the `@storybook/addon-actions` too.
211 |
212 | ```tsx
213 | export ExampleStory = () => (
214 |
215 | )
216 | ```
217 |
218 | ## Including DocGen Information
219 |
220 | This addon will display prop type information while hovering over a component or prop.
221 | This is accomplished through [a babel plugin](https://github.com/storybookjs/babel-plugin-react-docgen) in the default storybook configuration.
222 | To use the docgen information for TypeScript components you must include be using [a typescript docgen loader](https://github.com/strothj/react-docgen-typescript-loader)
223 |
224 | ```js
225 | import { addParameters } from '@storybook/react';
226 |
227 | addParameters({
228 | jsx: {
229 | // your options
230 | }
231 | });
232 | ```
233 |
234 | ### TypeScript Monorepo DocGen
235 |
236 | In a TypeScript monorepo you will probably be importing components through package names.
237 | In this situation storybook will load your compiled typescript and lose information about the props.
238 |
239 | One solution to get around this is to add a unique property to your component's `package.json` that points directly at the TypeScript source.
240 | We can then set storybook's webpack configuration to look for this property first, which will allow the TypeScript loader to insert docgen information.
241 |
242 | In your component's `package.json`:
243 |
244 | ```jsonc
245 | {
246 | // Can be any string you want, here we choose "source"
247 | "source": "src/index.tsx"
248 | }
249 | ```
250 |
251 | Then in your webpack config for storybook:
252 |
253 | ```js
254 | config.resolve.mainFields = ['source', 'module', 'main'];
255 | ```
256 |
257 | ## Testing with storyshots
258 |
259 | If you are using the `addWithJSX` method you will need to include `storybook-addon-jsx` in your test file.
260 |
261 | ```js
262 | import initStoryshots from '@storybook/addon-storyshots';
263 | import { setAddon } from '@storybook/react';
264 | import JSXAddon from 'storybook-addon-jsx';
265 |
266 | setAddon(JSXAddon);
267 |
268 | initStoryshots({
269 | /* configuration options */
270 | });
271 | ```
272 |
273 | ## Usage with IE11
274 |
275 | Some of the dependencies that this package has use APIs not available in IE11.
276 | To get around this you can add the following to your `webpack.config.js` file
277 | (your paths might be slightly different):
278 |
279 | ```js
280 | config.module.rules.push({
281 | test: /\.js/,
282 | include: path.resolve(__dirname, '../node_modules/stringify-object'),
283 | use: [
284 | {
285 | loader: 'babel-loader',
286 | options: {
287 | presets: ['env']
288 | }
289 | }
290 | ]
291 | });
292 | ```
293 |
294 | ## Contributors ✨
295 |
296 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
297 |
298 |
299 |
300 |
301 |
327 |
328 |
329 |
330 |
331 |
332 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
333 |
--------------------------------------------------------------------------------
/example/.storybook/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "shippedProposals": true
7 | }
8 | ],
9 | "@babel/preset-react"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/example/.storybook/addons.js:
--------------------------------------------------------------------------------
1 | import '../../register';
2 | import '@storybook/addon-options/register';
3 | import 'storybook-addon-react-docgen/register';
4 |
--------------------------------------------------------------------------------
/example/.storybook/config.js:
--------------------------------------------------------------------------------
1 | import { configure, setAddon, addDecorator } from '@storybook/react';
2 | import { withOptions } from '@storybook/addon-options';
3 | import { withPropsTable } from 'storybook-addon-react-docgen';
4 | import JSXAddon from '../../lib/index';
5 |
6 | setAddon(JSXAddon);
7 | addDecorator(withPropsTable);
8 |
9 | function loadStories() {
10 | require('../stories');
11 | }
12 |
13 | withOptions({
14 | brandTitle: 'CUSTOM-OPTIONS',
15 | brandUrl: 'https://github.com/kadirahq/storybook-addon-options'
16 | });
17 |
18 | configure(loadStories, module);
19 |
--------------------------------------------------------------------------------
/example/components/simple.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { storiesOf } from '@storybook/react';
4 |
5 | /** A simple component */
6 | export const Simple = ({ children }) => (
7 |
8 | Hello
9 | {children}
10 |
11 | );
12 |
13 | Simple.propTypes = {
14 | /** A test string */
15 | foo: PropTypes.string.isRequired,
16 | /** A test string */
17 | test: PropTypes.string,
18 | /** A test boolean */
19 | value: PropTypes.bool
20 | };
21 |
22 | Simple.defaultProps = {
23 | value: false
24 | };
25 |
26 | export default Simple;
27 |
--------------------------------------------------------------------------------
/example/stories/array.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 |
4 | const Component = () =>
;
5 | const Simple = props => (
6 |
7 | Hello
8 | {props.children}
9 |
10 | );
11 |
12 | storiesOf('Children Array', module)
13 | .addWithJSX(
14 | 'Simple Array',
15 | () => (
16 |
20 | ),
21 | { skip: 1 }
22 | )
23 | .addWithJSX(
24 | 'Array with function',
25 | () => (
26 |
27 |
28 |
29 | {Component()}
30 |
31 | ),
32 | { skip: 1 }
33 | )
34 | .addWithJSX(
35 | 'Array with nested component',
36 | () => (
37 |
38 |
39 |
40 | hello
41 |
42 |
43 | ),
44 | { skip: 1 }
45 | );
46 |
--------------------------------------------------------------------------------
/example/stories/decorator.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { jsxDecorator } from '../../lib/index';
4 |
5 | const Component = () =>
;
6 | const Simple = props => (
7 |
8 | Hello
9 | {props.children}
10 |
11 | );
12 |
13 | storiesOf('Decorator', module)
14 | .addDecorator(jsxDecorator)
15 | .add(
16 | 'Simple Array',
17 | () => (
18 |
22 | ),
23 | { skip: 1 }
24 | )
25 | .add(
26 | 'Array with function',
27 | () => (
28 |
29 |
30 |
31 | {Component()}
32 |
33 | ),
34 | { skip: 1 }
35 | )
36 | .add(
37 | 'Array with nested component',
38 | () => (
39 |
40 |
41 |
42 | hello
43 |
44 |
45 | ),
46 | { skip: 1 }
47 | );
48 |
--------------------------------------------------------------------------------
/example/stories/deep.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 |
4 | const Deep = ({ children }) => (
5 |
6 |
7 |
8 |
9 | Hello
10 | {children ? children : null}
11 |
12 |
13 |
14 |
15 | );
16 |
17 | storiesOf('Deep Test', module)
18 | .addWithJSX('No children - No options', () => (
19 |
20 |
21 |
24 |
25 |
26 | Hello
27 |
28 |
29 |
30 |
31 |
32 | ))
33 | .addWithJSX(
34 | 'No children - Rename',
35 | () => (
36 |
37 |
38 |
39 |
40 | Hello
41 |
42 |
43 |
44 |
45 |
46 | ),
47 | {
48 | displayName: () => 'Renamed'
49 | }
50 | )
51 | .addWithJSX('With children - No options', () => (
52 |
53 |
54 |
55 |
56 | Hello
57 |
58 |
59 |
60 |
61 |
62 | ))
63 | .addWithJSX(
64 | 'With children - Skip',
65 | () => (
66 |
67 |
68 |
69 |
70 | Hello
71 |
72 |
73 |
74 |
75 |
76 | ),
77 | { skip: 1 }
78 | )
79 | .addWithJSX(
80 | 'With children - Skip and rename',
81 | () => (
82 |
83 |
84 |
87 |
88 |
89 | Hello
90 |
91 |
92 |
93 |
94 |
95 | ),
96 | { skip: 1, displayName: () => 'Renamed' }
97 | );
98 |
--------------------------------------------------------------------------------
/example/stories/fragments.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 | import { jsxDecorator } from '../../lib/index';
4 |
5 | storiesOf('Fragments', module)
6 | .addDecorator(jsxDecorator)
7 | .add('Simple Fragment', () => (
8 |
9 |
10 |
11 |
12 | ))
13 | .add('Array', () => [
,
])
14 | .add('Fragment Shorthand', () => (
15 | <>
16 |
17 |
18 | >
19 | ));
20 |
--------------------------------------------------------------------------------
/example/stories/functions.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 |
4 | class Simple extends React.Component {
5 | render() {
6 | return (
7 |
8 | {typeof this.props.children === 'function'
9 | ? this.props.children()
10 | : this.props.children}
11 |
12 | );
13 | }
14 | }
15 | const withErrors = BaseComponent => props => {
16 | const style = { color: 'red' };
17 | return ;
18 | };
19 |
20 | const SimpleWithErrors = withErrors(Simple);
21 |
22 | storiesOf('Function as a children', module)
23 | .addWithJSX('No options', () => {() => World } )
24 | .addWithJSX('Skip', () => {() => World } , {
25 | skip: 1
26 | })
27 | .addWithJSX(
28 | 'Skip and Rename',
29 | () => {() => World } ,
30 | { skip: 1, displayName: () => 'Renamed' }
31 | )
32 | .addWithJSX('Deep function - No options', () => (
33 |
34 | {() => (
35 |
36 | World
37 |
38 | )}
39 |
40 | ))
41 | .addWithJSX(
42 | 'Deep function - Skip',
43 | () => (
44 |
45 | {() => (
46 |
47 | World
48 |
49 | )}
50 |
51 | ),
52 | { skip: 2 }
53 | );
54 |
--------------------------------------------------------------------------------
/example/stories/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { setAddon } from '@storybook/react';
3 |
4 | import './simple';
5 | import './deep';
6 | import './decorator';
7 | import './functions';
8 | import './fragments';
9 | import './array';
10 | import './withProps';
11 |
--------------------------------------------------------------------------------
/example/stories/simple.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 |
4 | const Simple = ({ children }) => (
5 |
6 | Hello
7 | {children}
8 |
9 | );
10 |
11 | storiesOf('Simple Test', module)
12 | .addWithJSX('No children - No options', () => )
13 | .addWithJSX('No children - Rename', () => , {
14 | displayName: 'Renamed'
15 | })
16 | .addWithJSX('With children - No options', () => (
17 |
18 | World
19 |
20 | ))
21 | .addWithJSX(
22 | 'With children - Skip',
23 | () => (
24 |
25 | World
26 |
27 | ),
28 | { skip: 1 }
29 | )
30 | .addWithJSX(
31 | 'With children - Skip and rename',
32 | () => (
33 |
34 | World
35 |
36 | ),
37 | { skip: 1, displayName: 'Renamed' }
38 | )
39 | .addWithJSX('Data strings', () => (
40 |
41 | ));
42 |
--------------------------------------------------------------------------------
/example/stories/withProps.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { storiesOf } from '@storybook/react';
3 |
4 | import Simple from '../components/simple';
5 |
6 | storiesOf('With Props', module)
7 | .addWithJSX('No children - No options', () => )
8 | .addWithJSX(
9 | 'No children - Rename',
10 | () => ,
11 | {
12 | displayName: 'Renamed'
13 | }
14 | )
15 | .addWithJSX('With children - No options', () => (
16 |
17 | World
18 |
19 | ))
20 | .addWithJSX(
21 | 'With children - Skip',
22 | () => (
23 |
24 |
25 |
26 |
27 |
28 | ),
29 | { skip: 1 }
30 | )
31 | .addWithJSX(
32 | 'With children - Skip and rename',
33 | () => (
34 |
35 |
36 | World
37 |
38 |
39 | ),
40 | { skip: 1, displayName: () => 'Renamed' }
41 | )
42 | .addWithJSX(
43 | 'With dangerouslySetInnerHTML - onBeforeRender',
44 | () => (
45 |
46 |
47 | '
50 | }}
51 | />
52 |
53 |
54 | ),
55 | {
56 | skip: 1,
57 | onBeforeRender: domString => {
58 | if (domString.search('dangerouslySetInnerHTML') < 0) {
59 | return '';
60 | }
61 | try {
62 | domString = /(dangerouslySetInnerHTML={{)([^}}]*)/.exec(domString)[2];
63 | domString = /(')([^']*)/.exec(domString)[2];
64 | } catch (err) {}
65 | return domString;
66 | }
67 | }
68 | );
69 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "storybook-static"
3 | command = "yarn prepare && yarn netlify"
4 | [build.environment]
5 | NODE_VERSION = "10"
6 | YARN_VERSION = "1.12.3"
7 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "storybook-addon-jsx",
3 | "version": "7.3.14",
4 | "description": "Display the JSX of the story",
5 | "repository": "storybookjs/addon-jsx",
6 | "license": "MIT",
7 | "author": "Andrew Lisowski ",
8 | "main": "lib/index.js",
9 | "scripts": {
10 | "prebuild": "rimraf lib",
11 | "build": "babel src --out-dir lib --ignore spec.js,test.js --extensions .ts --extensions .js --extensions .tsx && npm run build:types",
12 | "build-storybook": "build-storybook -c ./example/.storybook",
13 | "build:dev": "babel -w src --out-dir lib --ignore spec.js,test.js --extensions .ts --extensions .js --extensions .tsx",
14 | "build:types": "tsc -p tsconfig.json",
15 | "lint": "eslint --cache src --ext ts --ext tsx",
16 | "netlify": "build-storybook -c ./example/.storybook",
17 | "prepare": "yarn build",
18 | "release": "auto shipit",
19 | "storybook": "start-storybook -p 9009 -c ./example/.storybook",
20 | "test": "yarn test:all",
21 | "test:all": "jest src",
22 | "test:dev": "jest src --watch"
23 | },
24 | "husky": {
25 | "hooks": {
26 | "pre-commit": "lint-staged"
27 | }
28 | },
29 | "lint-staged": {
30 | "*.{js,json,css,md}": [
31 | "prettier --write",
32 | "git add"
33 | ]
34 | },
35 | "prettier": {
36 | "singleQuote": true
37 | },
38 | "jest": {
39 | "testURL": "http://localhost"
40 | },
41 | "dependencies": {
42 | "copy-to-clipboard": "^3.0.8",
43 | "js-beautify": "^1.8.8",
44 | "react-element-to-jsx-string": "^14.3.1",
45 | "storybook-pretty-props": "^1.0.3"
46 | },
47 | "devDependencies": {
48 | "@auto-it/all-contributors": "^9.34.1",
49 | "@auto-it/first-time-contributor": "^9.34.1",
50 | "@babel/cli": "^7.1.2",
51 | "@babel/core": "^7.1.6",
52 | "@babel/preset-env": "^7.1.0",
53 | "@babel/preset-react": "^7.0.0",
54 | "@babel/preset-typescript": "^7.3.3",
55 | "@design-systems/eslint-config": "^1.4.15",
56 | "@storybook/addon-options": "^5.0.3",
57 | "@storybook/addon-storyshots": "^5.0.3",
58 | "@storybook/addons": "^5.2.5",
59 | "@storybook/channels": "^5.2.5",
60 | "@storybook/components": "^5.2.5",
61 | "@storybook/core-events": "^5.2.5",
62 | "@storybook/react": "^5.0.3",
63 | "@storybook/theming": "^5.2.5",
64 | "@types/js-beautify": "^1.8.0",
65 | "@types/react": "^16.8.8",
66 | "@types/storybook__react": "^4.0.1",
67 | "all-contributors-cli": "^6.14.2",
68 | "auto": "^9.34.1",
69 | "babel-core": "^7.0.0-bridge.0",
70 | "babel-jest": "^24.5.0",
71 | "babel-loader": "^8.0.6",
72 | "eslint": "^6.8.0",
73 | "husky": "^3.0.9",
74 | "jest": "^24.5.0",
75 | "lint-staged": "^9.4.2",
76 | "prettier": "^1.15.2",
77 | "prop-types": "^15.6.2",
78 | "react": "^16.11.0",
79 | "react-docgen-typescript-loader": "^3.7.2",
80 | "react-dom": "^16.11.0",
81 | "react-test-renderer": "^16.11.0",
82 | "regenerator-runtime": "^0.13.3",
83 | "rimraf": "^3.0.0",
84 | "storybook-addon-react-docgen": "^1.2.32",
85 | "typescript": "^3.3.3333"
86 | },
87 | "peerDependencies": {
88 | "@storybook/addons": ">= 5.x",
89 | "@storybook/channels": ">= 5.x",
90 | "@storybook/components": ">= 5.x",
91 | "@storybook/core-events": ">= 5.x",
92 | "@storybook/theming": ">= 5.x",
93 | "react": "^16.2.0 || ^17.0.0",
94 | "react-dom": "^16.2.0 || ^17.0.0"
95 | },
96 | "auto": {
97 | "plugins": [
98 | "npm",
99 | "released",
100 | "first-time-contributor",
101 | "all-contributors"
102 | ]
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/register.js:
--------------------------------------------------------------------------------
1 | require('./lib/register.js');
2 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storybookjs/addon-jsx/61f84631e1c4334cf138d1814f9476e0fe6386f9/screenshot.png
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/index.test.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Storyshots Children Array Array with function 1`] = `
4 |
11 | `;
12 |
13 | exports[`Storyshots Children Array Array with nested component 1`] = `
14 |
15 |
16 |
17 |
18 | Hello
19 |
20 |
21 | hello
22 |
23 |
24 |
25 | `;
26 |
27 | exports[`Storyshots Children Array Simple Array 1`] = `
28 |
32 | `;
33 |
34 | exports[`Storyshots Decorator Array with function 1`] = `
35 |
40 | `;
41 |
42 | exports[`Storyshots Decorator Array with nested component 1`] = `
43 |
44 |
45 |
46 |
47 | Hello
48 |
49 |
50 | hello
51 |
52 |
53 |
54 | `;
55 |
56 | exports[`Storyshots Decorator Simple Array 1`] = `
57 |
61 | `;
62 |
63 | exports[`Storyshots Deep Test No children - No options 1`] = `
64 |
65 |
66 |
67 |
68 | Deeper
69 |
70 |
71 |
72 |
73 |
74 | Hello
75 |
76 |
77 |
78 |
79 |
80 |
81 | Hello
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | `;
92 |
93 | exports[`Storyshots Deep Test No children - Rename 1`] = `
94 |
95 |
96 |
97 |
98 |
99 | Hello
100 |
101 |
102 |
103 |
104 |
105 |
106 | Hello
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 | `;
117 |
118 | exports[`Storyshots Deep Test With children - No options 1`] = `
119 |
120 |
121 |
122 |
123 |
124 | Hello
125 |
126 |
127 |
128 |
129 |
130 |
131 | Hello
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | `;
142 |
143 | exports[`Storyshots Deep Test With children - Skip 1`] = `
144 |
145 |
146 |
147 |
148 |
149 | Hello
150 |
151 |
152 |
153 |
154 |
155 |
156 | Hello
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 | `;
167 |
168 | exports[`Storyshots Deep Test With children - Skip and rename 1`] = `
169 |
170 |
171 |
172 |
173 | Deeper
174 |
175 |
176 |
177 |
178 |
179 | Hello
180 |
181 |
182 |
183 |
184 |
185 |
186 | Hello
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 | `;
197 |
198 | exports[`Storyshots Fragments Array 1`] = `
199 | Array [
200 |
,
201 |
,
202 | ]
203 | `;
204 |
205 | exports[`Storyshots Fragments Fragment Shorthand 1`] = `
206 | Array [
207 |
,
208 |
,
209 | ]
210 | `;
211 |
212 | exports[`Storyshots Fragments Simple Fragment 1`] = `
213 | Array [
214 |
,
215 |
,
216 | ]
217 | `;
218 |
219 | exports[`Storyshots Function as a children Deep function - No options 1`] = `
220 |
221 |
222 |
223 | World
224 |
225 |
226 |
227 | `;
228 |
229 | exports[`Storyshots Function as a children Deep function - Skip 1`] = `
230 |
231 |
232 |
233 | World
234 |
235 |
236 |
237 | `;
238 |
239 | exports[`Storyshots Function as a children No options 1`] = `
240 |
241 |
242 | World
243 |
244 |
245 | `;
246 |
247 | exports[`Storyshots Function as a children Skip 1`] = `
248 |
249 |
250 | World
251 |
252 |
253 | `;
254 |
255 | exports[`Storyshots Function as a children Skip and Rename 1`] = `
256 |
257 |
258 | World
259 |
260 |
261 | `;
262 |
263 | exports[`Storyshots Simple Test Data strings 1`] = `
264 |
269 | `;
270 |
271 | exports[`Storyshots Simple Test No children - No options 1`] = `
272 |
273 |
274 | Hello
275 |
276 |
277 | `;
278 |
279 | exports[`Storyshots Simple Test No children - Rename 1`] = `
280 |
281 |
282 | Hello
283 |
284 |
285 | `;
286 |
287 | exports[`Storyshots Simple Test With children - No options 1`] = `
288 |
289 |
290 | Hello
291 |
292 |
293 | World
294 |
295 |
296 | `;
297 |
298 | exports[`Storyshots Simple Test With children - Skip 1`] = `
299 |
300 |
301 | Hello
302 |
303 |
304 | World
305 |
306 |
307 | `;
308 |
309 | exports[`Storyshots Simple Test With children - Skip and rename 1`] = `
310 |
311 |
312 | Hello
313 |
314 |
315 | World
316 |
317 |
318 | `;
319 |
320 | exports[`Storyshots With Props No children - No options 1`] = `
321 |
322 |
323 | Hello
324 |
325 |
326 | `;
327 |
328 | exports[`Storyshots With Props No children - Rename 1`] = `
329 |
330 |
331 | Hello
332 |
333 |
334 | `;
335 |
336 | exports[`Storyshots With Props With children - No options 1`] = `
337 |
338 |
339 | Hello
340 |
341 |
342 | World
343 |
344 |
345 | `;
346 |
347 | exports[`Storyshots With Props With children - Skip 1`] = `
348 |
349 |
350 | Hello
351 |
352 |
353 |
354 | Hello
355 |
356 |
357 |
358 |
359 | `;
360 |
361 | exports[`Storyshots With Props With children - Skip and rename 1`] = `
362 |
363 |
364 | Hello
365 |
366 |
367 |
368 | Hello
369 |
370 |
371 | World
372 |
373 |
374 |
375 | `;
376 |
377 | exports[`Storyshots With Props With dangerouslySetInnerHTML - onBeforeRender 1`] = `
378 |
379 |
380 | Hello
381 |
382 |
383 |
384 | Hello
385 |
386 |
",
390 | }
391 | }
392 | />
393 |
394 |
395 | `;
396 |
--------------------------------------------------------------------------------
/src/__tests__/index.test.js:
--------------------------------------------------------------------------------
1 | import initStoryshots from '@storybook/addon-storyshots';
2 |
3 | global.requestAnimationFrame = function(callback) {
4 | setTimeout(callback, 0);
5 | };
6 |
7 | initStoryshots({
8 | configPath: './example/.storybook'
9 | });
10 |
--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------
1 | export const ADDON_ID = 'kadira/jsx';
2 | export const ADDON_PANEL = `${ADDON_ID}/panel`;
3 |
4 | const ADD_JSX = `${ADDON_ID}/add_jsx`;
5 |
6 | export const EVENTS = { ADD_JSX };
7 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-underscore-dangle, @typescript-eslint/no-explicit-any */
2 |
3 | import React from 'react';
4 | import {
5 | addons,
6 | makeDecorator,
7 | StoryContext,
8 | StoryFn,
9 | StoryApi,
10 | ClientStoryApi
11 | } from '@storybook/addons';
12 | import reactElementToJSXString, { Options } from 'react-element-to-jsx-string';
13 | import { html as beautifyHTML } from 'js-beautify';
14 |
15 | import { EVENTS } from './constants';
16 | import { ComponentMap } from './renderer';
17 |
18 | export declare const addDecorator: ClientStoryApi['addDecorator'];
19 | export declare type DecoratorFn = Parameters[0];
20 |
21 | type VueComponent = {
22 | /** The template for the Vue component */
23 | template?: string;
24 | };
25 |
26 | interface JSXOptions extends HTMLBeautifyOptions {
27 | /** How many wrappers to skip when rendering the jsx */
28 | skip?: number;
29 | /** Whether to show the function in the jsx tab */
30 | showFunctions?: boolean;
31 | /** Whether to format HTML or Vue markup */
32 | enableBeautify?: boolean;
33 | /** Override the display name used for a component */
34 | displayName?: string | Options['displayName'];
35 | /** A function ran before the story is rendered */
36 | onBeforeRender?(dom: string): string;
37 | }
38 |
39 | /** Run the user supplied onBeforeRender function if it exists */
40 | const applyBeforeRender = (domString: string, options: JSXOptions) => {
41 | if (typeof options.onBeforeRender !== 'function') {
42 | return domString;
43 | }
44 |
45 | return options.onBeforeRender(domString);
46 | };
47 |
48 | /** Apply the users parameters and render the jsx for a story */
49 | const renderJsx = (code: React.ReactElement, options: Required) => {
50 | let renderedJSX = code;
51 | let Type = renderedJSX.type;
52 |
53 | for (let i = 0; i < options.skip; i++) {
54 | if (typeof renderedJSX === 'undefined') {
55 | // eslint-disable-next-line no-console
56 | console.warn('Cannot skip undefined element');
57 | return;
58 | }
59 |
60 | if (React.Children.count(renderedJSX) > 1) {
61 | // eslint-disable-next-line no-console
62 | console.warn('Trying to skip an array of elements');
63 | return;
64 | }
65 |
66 | if (typeof renderedJSX.props.children === 'undefined') {
67 | // eslint-disable-next-line no-console
68 | console.warn('Not enough children to skip elements.');
69 |
70 | if (typeof Type === 'function' && Type.name === '') {
71 | renderedJSX = ;
72 | }
73 | } else if (typeof renderedJSX.props.children === 'function') {
74 | renderedJSX = renderedJSX.props.children();
75 | } else {
76 | renderedJSX = renderedJSX.props.children;
77 | }
78 | }
79 |
80 | if (typeof renderedJSX === 'undefined') {
81 | // eslint-disable-next-line no-console
82 | return console.warn('Too many skip or undefined component');
83 | }
84 |
85 | while (typeof Type === 'function' && Type.name === '') {
86 | renderedJSX = ;
87 | Type = renderedJSX.type;
88 | }
89 |
90 | const ooo =
91 | typeof options.displayName === 'string'
92 | ? {
93 | ...options,
94 | showFunctions: true,
95 | displayName: () => options.displayName
96 | }
97 | : options;
98 |
99 | return React.Children.map(renderedJSX, c => {
100 | let string = applyBeforeRender(
101 | reactElementToJSXString(c, ooo as Options),
102 | options
103 | );
104 | const matches = string.match(/\S+=\\"([^"]*)\\"/g);
105 |
106 | if (matches) {
107 | matches.forEach(match => {
108 | string = string.replace(match, match.replace(/"/g, "'"));
109 | });
110 | }
111 |
112 | return string;
113 | }).join('\n');
114 | };
115 |
116 | /** Extract the docs for all components used in a story */
117 | const getDocs = (story: React.ReactElement) => {
118 | const types: ComponentMap = {};
119 |
120 | /** Walk the story for components */
121 | function extract(innerChildren: React.ReactElement) {
122 | if (!innerChildren) {
123 | return;
124 | }
125 |
126 | if (Array.isArray(innerChildren)) {
127 | innerChildren.forEach(extract);
128 | return;
129 | }
130 |
131 | if (innerChildren.props && innerChildren.props.children) {
132 | extract(innerChildren.props.children);
133 | }
134 |
135 | Object.values(innerChildren.props || {}).forEach(prop => {
136 | extract(prop as React.ReactElement);
137 | });
138 |
139 | if (typeof innerChildren.type !== 'string' && innerChildren.type) {
140 | const childType = innerChildren.type as any;
141 | const name: string = childType.displayName || childType.name;
142 |
143 | if (name && !types[name]) {
144 | types[name] = childType.__docgenInfo;
145 | }
146 | }
147 | }
148 |
149 | extract(story);
150 |
151 | return types;
152 | };
153 |
154 | const defaultOpts = {
155 | skip: 0,
156 | showDefaultProps: true,
157 | showFunctions: true,
158 | enableBeautify: true
159 | };
160 |
161 | /** Extract components from story and emit them to the panel */
162 | export const jsxDecorator = makeDecorator({
163 | name: 'jsx',
164 | parameterName: 'jsx',
165 | wrapper: (storyFn: any, parameters: StoryContext) => {
166 | const story: ReturnType & VueComponent = storyFn();
167 |
168 | const channel = addons.getChannel();
169 |
170 | const options = {
171 | ...defaultOpts,
172 | ...((parameters && parameters.parameters.jsx) || {})
173 | } as Required;
174 |
175 | let components: ComponentMap = {};
176 | let jsx = '';
177 |
178 | if (story.template) {
179 | if (options.enableBeautify) {
180 | jsx = beautifyHTML(story.template, options);
181 | } else {
182 | jsx = story.template;
183 | }
184 | } else {
185 | const rendered = renderJsx(story, options);
186 |
187 | if (rendered) {
188 | jsx = rendered;
189 | components = getDocs(story);
190 | }
191 | }
192 |
193 | channel.emit(EVENTS.ADD_JSX, (parameters || {}).id, jsx, components);
194 |
195 | return story;
196 | }
197 | });
198 |
199 | export default {
200 | addWithJSX(this: StoryApi, kind: string, storyFn: StoryFn) {
201 | return this.add(kind, context => jsxDecorator(storyFn, context));
202 | }
203 | };
204 |
--------------------------------------------------------------------------------
/src/jsx.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ActionBar, SyntaxHighlighter } from '@storybook/components';
3 | import { styled } from '@storybook/theming';
4 | import copy from 'copy-to-clipboard';
5 |
6 | import { Listener } from './register';
7 | import jsxRenderer, { ComponentMap } from './renderer';
8 |
9 | const Container = styled.div(({ theme }) => ({
10 | padding: theme.layoutMargin
11 | }));
12 |
13 | interface JSXProps {
14 | /** Whether the panel is active */
15 | active: boolean;
16 | ob(listener: Listener): void;
17 | }
18 |
19 | /** The panel that renders the jsx for the story */
20 | const JSX = ({ ob, active }: JSXProps) => {
21 | const [current, setCurrent] = React.useState(undefined);
22 | const [jsx, setJsx] = React.useState>(
23 | {}
24 | );
25 |
26 | React.useEffect(() => {
27 | ob({
28 | next: type => {
29 | if (type === 'jsx') {
30 | return (id: string, newJsx: string, components: ComponentMap) =>
31 | setJsx({ ...jsx, [id]: [newJsx, components] });
32 | }
33 |
34 | return setCurrent;
35 | }
36 | });
37 | // eslint-disable-next-line react-hooks/exhaustive-deps
38 | }, []);
39 |
40 | const [code, components] = current && jsx[current] ? jsx[current] : ['', {}];
41 |
42 | const copyJsx = React.useCallback(() => copy(code), [code]);
43 |
44 | return active ? (
45 | <>
46 |
47 |
53 | {code}
54 |
55 |
56 |
64 | >
65 | ) : null;
66 | };
67 |
68 | export default JSX;
69 |
--------------------------------------------------------------------------------
/src/register.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { addons } from '@storybook/addons';
3 | import { STORY_RENDERED } from '@storybook/core-events';
4 | import Channel from '@storybook/channels';
5 |
6 | import JSX from './jsx';
7 | import { ComponentMap } from './renderer';
8 | import { ADDON_ID, ADDON_PANEL, EVENTS } from './constants';
9 |
10 | export interface Listener {
11 | next(
12 | scope: 'current' | 'jsx'
13 | ): typeof scope extends 'current'
14 | ? (id: string) => void
15 | : (id: string, jsx: string, components: ComponentMap) => void;
16 | }
17 |
18 | /** A function that lets the panel listen to storybook event */
19 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
20 | const observable = (channel: Channel, api: any) => (listener: Listener) => {
21 | channel.on(EVENTS.ADD_JSX, listener.next('jsx'));
22 | api.on(STORY_RENDERED, listener.next('current'));
23 | };
24 |
25 | addons.register(ADDON_ID, api => {
26 | const ob = observable(addons.getChannel(), api);
27 |
28 | addons.addPanel(ADDON_PANEL, {
29 | title: 'JSX',
30 | render: ({ active }) =>
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/renderer.tsx:
--------------------------------------------------------------------------------
1 | import React, { ComponentProps } from 'react';
2 | import { WithTooltip, TooltipMessage } from '@storybook/components';
3 | import PrettyPropType from 'storybook-pretty-props';
4 |
5 | type StyleSheet = Record;
6 | export type ComponentMap = Record<
7 | string,
8 | {
9 | /** The description of the component */
10 | description?: string;
11 | /** The display name of the component */
12 | displayName: string;
13 | /** The children of the component */
14 | children: (Node | string)[];
15 | /** The props of the component */
16 | props?: Record<
17 | string,
18 | {
19 | /** Whether the prop is required */
20 | required?: boolean;
21 | /** The description of the prop */
22 | description?: string;
23 | /** The type of the prop */
24 | type: ComponentProps['propType'];
25 | }
26 | >;
27 | }
28 | >;
29 |
30 | /** Combine the classnames and the stylesheet into a style prop */
31 | function createStyleObject(
32 | classNames: string[],
33 | elementStyle: React.CSSProperties,
34 | stylesheet: StyleSheet
35 | ) {
36 | return classNames.reduce((styleObject, className) => {
37 | return { ...styleObject, ...stylesheet[className] };
38 | }, elementStyle);
39 | }
40 |
41 | /** Join and array of classnames into one */
42 | function createClassNameString(classNames: string[]) {
43 | return classNames.join(' ');
44 | }
45 |
46 | interface Node {
47 | /** The type of node */
48 | type: string;
49 | /** The HTML tag to use to render the node */
50 | tagName: string;
51 | /** Properties of the HTML node to create */
52 | properties: {
53 | /** The classNames to put on the node */
54 | className: string[];
55 | /** The style object to put on the node */
56 | style?: React.CSSProperties;
57 | };
58 | /** The children of the HTML node to create */
59 | children: React.ReactNode;
60 | /** The value of the node to create */
61 | value?: string;
62 | }
63 |
64 | /** Render the rows of children to HTML nodes or text */
65 | function createChildren(
66 | components: ComponentMap,
67 | stylesheet: StyleSheet,
68 | useInlineStyles?: boolean
69 | ) {
70 | let childrenCount = 0;
71 |
72 | return (children: Node[]) => {
73 | childrenCount += 1;
74 |
75 | return children.map((child, i) =>
76 | // eslint-disable-next-line @typescript-eslint/no-use-before-define
77 | createElement({
78 | node: child,
79 | stylesheet,
80 | useInlineStyles,
81 | components,
82 | key: `code-segment-${childrenCount}-${i}`
83 | })
84 | );
85 | };
86 | }
87 |
88 | interface CreateElementOptions {
89 | /** The node to create */
90 | node: Node;
91 | /** A react key to apply to the node */
92 | key: string;
93 | /** The stylesheet to use to style the highlighted output */
94 | stylesheet?: StyleSheet;
95 | /** A map of component used in the story and their docs */
96 | components: ComponentMap;
97 | /** Whether to inline all of the styles in the highlighted output */
98 | useInlineStyles?: boolean;
99 | /** The style object to put on the node */
100 | style?: React.CSSProperties;
101 | }
102 |
103 | const componentStack: string[] = [];
104 |
105 | /** Transform a row of highlighted output into an HTML node */
106 | function createElement({
107 | node,
108 | stylesheet = {},
109 | components,
110 | style = {},
111 | useInlineStyles,
112 | key
113 | }: CreateElementOptions) {
114 | const { properties, type, tagName, value } = node;
115 |
116 | if (type === 'text') {
117 | return value;
118 | }
119 |
120 | if (tagName) {
121 | const TagName = tagName as keyof JSX.IntrinsicElements;
122 | const childrenCreator = createChildren(
123 | components,
124 | stylesheet,
125 | useInlineStyles
126 | );
127 | const nonStylesheetClassNames =
128 | useInlineStyles &&
129 | properties.className &&
130 | properties.className.filter(className => !stylesheet[className]);
131 | const className =
132 | nonStylesheetClassNames && nonStylesheetClassNames.length
133 | ? nonStylesheetClassNames
134 | : '';
135 | const props = useInlineStyles
136 | ? {
137 | ...properties,
138 | ...{
139 | className: className ? createClassNameString(className) : className
140 | },
141 | style: createStyleObject(
142 | properties.className,
143 | { ...properties.style, ...style },
144 | stylesheet
145 | )
146 | }
147 | : {
148 | ...properties,
149 | className: createClassNameString(properties.className)
150 | };
151 | const children = childrenCreator(node.children as Node[]);
152 |
153 | const lastComponent = componentStack[componentStack.length - 1] || '';
154 | const name = typeof children[0] === 'string' ? children[0] : '';
155 | const hasDocs =
156 | props.className.includes('class-name') ||
157 | props.className.includes('attr-name');
158 |
159 | if (hasDocs) {
160 | let message;
161 | let title;
162 |
163 | if (props.className.includes('class-name')) {
164 | const docs = components[name] || {};
165 |
166 | if (docs.description) {
167 | title = children;
168 | message = {docs.description}
;
169 | }
170 |
171 | componentStack.push(name);
172 | } else if (lastComponent.match(/^[A-Z]/)) {
173 | const { props: componentProps = {} } = components[lastComponent] || {};
174 | const docs = componentProps[name] || {};
175 |
176 | if (docs.type || docs.description || docs.required) {
177 | title = (
178 |
179 | {children}
180 | {docs.required && (
181 |
Required
182 | )}
183 |
184 | );
185 | message = (
186 |
187 |
190 | {docs.description}
191 |
192 | );
193 | }
194 | }
195 |
196 | if (title) {
197 | return (
198 | }
203 | >
204 |
205 | {children}
206 |
207 |
208 | );
209 | }
210 | } else if (name === '/>' || name === '>') {
211 | componentStack.pop();
212 | }
213 |
214 | return (
215 |
216 | {children}
217 |
218 | );
219 | }
220 | }
221 |
222 | interface RenderRows {
223 | /** A row to render in the highlighted output */
224 | rows: Node[];
225 | /** The stylesheet to use to style the highlighted output */
226 | stylesheet: StyleSheet;
227 | /** Whether to inline all of the styles in the highlighted output */
228 | useInlineStyles?: boolean;
229 | }
230 |
231 | /** Render a row from the react-syntax-highlighter output */
232 | const jsxRenderer = (components: ComponentMap) => ({
233 | rows,
234 | stylesheet,
235 | useInlineStyles
236 | }: RenderRows) =>
237 | rows.map((node, i) =>
238 | createElement({
239 | node,
240 | stylesheet,
241 | useInlineStyles,
242 | components,
243 | key: `code-segement${i}`
244 | })
245 | );
246 |
247 | export default jsxRenderer;
248 |
--------------------------------------------------------------------------------
/src/types/react-element-to-jsx-string.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'react-element-to-jsx-string' {
2 | export interface Options {
3 | showFunctions?: boolean;
4 | displayName?(): string;
5 | }
6 |
7 | export default function render(
8 | element: React.ReactNode,
9 | options: Options
10 | ): string;
11 | }
12 |
--------------------------------------------------------------------------------
/src/types/storybook__ui.d.ts:
--------------------------------------------------------------------------------
1 | declare module '@storybook/ui/dist/core/context';
2 |
--------------------------------------------------------------------------------
/storybook-jsx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storybookjs/addon-jsx/61f84631e1c4334cf138d1814f9476e0fe6386f9/storybook-jsx.png
--------------------------------------------------------------------------------
/storybook-jsx.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/storybookjs/addon-jsx/61f84631e1c4334cf138d1814f9476e0fe6386f9/storybook-jsx.sketch
--------------------------------------------------------------------------------
/storybook-jsx.svg:
--------------------------------------------------------------------------------
1 | JSX
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "lib": ["es2017", "dom"],
5 | "jsx": "react",
6 | "moduleResolution": "node",
7 | // "allowSyntheticDefaultImports": true,
8 | "esModuleInterop": true,
9 | "downlevelIteration": true,
10 | "noUnusedLocals": true,
11 | "noUnusedParameters": true,
12 | "outDir": "dist",
13 | "declarationDir": "lib",
14 | "emitDeclarationOnly": true,
15 | "preserveConstEnums": true,
16 | "removeComments": false,
17 | "skipLibCheck": true,
18 | "sourceMap": true,
19 | "strict": true,
20 | "typeRoots": ["src/types/", "node_modules/@types/"]
21 | },
22 | "include": ["src/**/*.ts", "src/**/*.tsx", "typings/**/*"]
23 | }
24 |
--------------------------------------------------------------------------------