diff --git a/code/frameworks/vue3-vite/preset.js b/code/frameworks/vue3-vite/preset.js index b27b9a283650..a83f95279e7f 100644 --- a/code/frameworks/vue3-vite/preset.js +++ b/code/frameworks/vue3-vite/preset.js @@ -1,2 +1 @@ -console.log('vue3-vite preset!'); module.exports = require('./dist/preset'); diff --git a/code/frameworks/web-components-vite/README.md b/code/frameworks/web-components-vite/README.md new file mode 100644 index 000000000000..9c68eca98041 --- /dev/null +++ b/code/frameworks/web-components-vite/README.md @@ -0,0 +1 @@ +# Storybook for Web components diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json new file mode 100644 index 000000000000..d8285652806a --- /dev/null +++ b/code/frameworks/web-components-vite/package.json @@ -0,0 +1,86 @@ +{ + "name": "@storybook/web-components-vite", + "version": "7.0.0-alpha.34", + "description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.", + "keywords": [ + "storybook" + ], + "homepage": "https://github.com/storybookjs/storybook/tree/main/frameworks/web-components-vite", + "bugs": { + "url": "https://github.com/storybookjs/storybook/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/storybookjs/storybook.git", + "directory": "frameworks/web-components-vite" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + }, + "license": "MIT", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" + }, + "./preset": { + "require": "./dist/preset.js", + "import": "./dist/preset.mjs", + "types": "./dist/preset.d.ts" + }, + "./package.json": { + "require": "./package.json", + "import": "./package.json", + "types": "./package.json" + } + }, + "main": "dist/index.js", + "module": "dist/index.mjs", + "types": "dist/index.d.ts", + "files": [ + "dist/**/*", + "types/**/*", + "README.md", + "*.js", + "*.d.ts" + ], + "scripts": { + "check": "tsc --noEmit", + "prep": "../../../scripts/prepare/bundle.ts" + }, + "dependencies": { + "@storybook/addons": "7.0.0-alpha.34", + "@storybook/builder-vite": "7.0.0-alpha.34", + "@storybook/channel-postmessage": "7.0.0-alpha.34", + "@storybook/channel-websocket": "7.0.0-alpha.34", + "@storybook/client-api": "7.0.0-alpha.34", + "@storybook/core-server": "7.0.0-alpha.34", + "@storybook/node-logger": "7.0.0-alpha.34", + "@storybook/preview-web": "7.0.0-alpha.34", + "@storybook/web-components": "7.0.0-alpha.34", + "@vitejs/plugin-vue": "^3.0.3", + "magic-string": "^0.26.1", + "vite": "3" + }, + "devDependencies": { + "@types/node": "^14.14.20 || ^16.0.0", + "typescript": "~4.6.3", + "vite": "^3.1.0" + }, + "engines": { + "node": "^14.18 || >=16" + }, + "publishConfig": { + "access": "public" + }, + "bundler": { + "entries": [ + "./src/index.ts", + "./src/preset.ts" + ], + "platform": "node" + }, + "gitHead": "02c013c33186479017098d532a18ff8654b91f1f" +} diff --git a/code/frameworks/web-components-vite/preset.js b/code/frameworks/web-components-vite/preset.js new file mode 100644 index 000000000000..a83f95279e7f --- /dev/null +++ b/code/frameworks/web-components-vite/preset.js @@ -0,0 +1 @@ +module.exports = require('./dist/preset'); diff --git a/code/frameworks/web-components-vite/src/index.ts b/code/frameworks/web-components-vite/src/index.ts new file mode 100644 index 000000000000..535432f3e0d4 --- /dev/null +++ b/code/frameworks/web-components-vite/src/index.ts @@ -0,0 +1,9 @@ +// exports for builder-vite +export { createChannel as createPostMessageChannel } from '@storybook/channel-postmessage'; +export { createChannel as createWebSocketChannel } from '@storybook/channel-websocket'; +export { addons } from '@storybook/addons'; +export { composeConfigs, PreviewWeb } from '@storybook/preview-web'; +export { ClientApi } from '@storybook/client-api'; + +export * from '@storybook/web-components'; +export type { StorybookConfig } from '@storybook/builder-vite'; diff --git a/code/frameworks/web-components-vite/src/preset.ts b/code/frameworks/web-components-vite/src/preset.ts new file mode 100644 index 000000000000..53f4bcd5479e --- /dev/null +++ b/code/frameworks/web-components-vite/src/preset.ts @@ -0,0 +1,7 @@ +import type { StorybookConfig } from '@storybook/builder-vite'; + +export const addons: StorybookConfig['addons'] = ['@storybook/web-components']; + +export const core: StorybookConfig['core'] = { + builder: '@storybook/builder-vite', +}; diff --git a/code/frameworks/web-components-vite/tsconfig.json b/code/frameworks/web-components-vite/tsconfig.json new file mode 100644 index 000000000000..534e4ddd108a --- /dev/null +++ b/code/frameworks/web-components-vite/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "./src", + "types": ["node"], + "resolveJsonModule": true + }, + "include": ["src/**/*"], + "exclude": ["src/**/*.test.*", "src/**/__testfixtures__/**"] +} diff --git a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts index 836b1f11585e..7b8cbc00e99f 100644 --- a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts +++ b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts @@ -35,11 +35,11 @@ const packagesMap: Record = { }, '@storybook/svelte': { webpack5: '@storybook/svelte-webpack5', - // TODO: bring this back once we have the svelte-vite package vite: '@storybook/svelte-vite', }, '@storybook/web-components': { webpack5: '@storybook/web-components-webpack5', + vite: '@storybook/web-components-vite', }, '@storybook/html': { webpack5: '@storybook/html-webpack5', diff --git a/code/lib/cli/src/repro-templates.ts b/code/lib/cli/src/repro-templates.ts index 58359f5ece83..fe49b9814420 100644 --- a/code/lib/cli/src/repro-templates.ts +++ b/code/lib/cli/src/repro-templates.ts @@ -94,6 +94,29 @@ const svelteViteTemplates = { // } }; +const litViteTemplates = { + 'lit-vite/default-js': { + name: 'Lit Vite (JS)', + script: 'yarn create vite . --template lit', + cadence: [] as any, + expected: { + framework: '@storybook/web-components-vite', + renderer: '@storybook/web-components', + builder: '@storybook/builder-vite', + }, + }, + 'lit-vite/default-ts': { + name: 'Lit Vite (TS)', + script: 'yarn create vite . --template lit-ts', + cadence: [] as any, + expected: { + framework: '@storybook/web-components-vite', + renderer: '@storybook/web-components', + builder: '@storybook/builder-vite', + }, + }, +}; + const vueCliTemplates = { 'vue-cli/default-js': { name: 'Vue-CLI (Default JS)', @@ -124,6 +147,7 @@ export default { ...reactViteTemplates, ...vue3ViteTemplates, ...svelteViteTemplates, + ...litViteTemplates, ...vueCliTemplates, // FIXME: missing documentation.json // 'angular/latest': { diff --git a/code/lib/cli/src/versions.ts b/code/lib/cli/src/versions.ts index fe0c35d62141..a214dfaf59d1 100644 --- a/code/lib/cli/src/versions.ts +++ b/code/lib/cli/src/versions.ts @@ -77,6 +77,7 @@ export default { '@storybook/vue3-webpack5': '7.0.0-alpha.34', '@storybook/web-components': '7.0.0-alpha.34', '@storybook/web-components-webpack5': '7.0.0-alpha.34', + '@storybook/web-components-vite': '7.0.0-alpha.34', sb: '7.0.0-alpha.34', storybook: '7.0.0-alpha.34', }; diff --git a/code/package.json b/code/package.json index 7afc2e6ffbd5..065164eb7861 100644 --- a/code/package.json +++ b/code/package.json @@ -234,6 +234,7 @@ "@storybook/vue3-vite": "workspace:*", "@storybook/vue3-webpack5": "workspace:*", "@storybook/web-components": "workspace:*", + "@storybook/web-components-vite": "workspace:*", "@storybook/web-components-webpack5": "workspace:*", "@testing-library/dom": "^7.29.4", "@testing-library/jest-dom": "^5.11.9", diff --git a/code/renderers/web-components/src/config.ts b/code/renderers/web-components/src/config.ts index 83d74fd4d9d9..db7cf8f12a34 100644 --- a/code/renderers/web-components/src/config.ts +++ b/code/renderers/web-components/src/config.ts @@ -2,4 +2,4 @@ import { parameters as docsParams } from './docs/config'; export const parameters = { framework: 'web-components' as const, ...docsParams }; export { decorators, argTypesEnhancers } from './docs/config'; -export { renderToDOM } from './render'; +export { render, renderToDOM } from './render'; diff --git a/code/renderers/web-components/src/docs/sourceDecorator.test.ts b/code/renderers/web-components/src/docs/sourceDecorator.test.ts index e08f0f3dee55..e516b915000f 100644 --- a/code/renderers/web-components/src/docs/sourceDecorator.test.ts +++ b/code/renderers/web-components/src/docs/sourceDecorator.test.ts @@ -1,5 +1,6 @@ +/* eslint-disable import/extensions */ import { html } from 'lit-html'; -import { styleMap } from 'lit-html/directives/style-map'; +import { styleMap } from 'lit-html/directives/style-map.js'; import { addons, useEffect } from '@storybook/addons'; import { SNIPPET_RENDERED } from '@storybook/docs-tools'; import type { StoryContext } from '../types'; diff --git a/code/renderers/web-components/src/render.ts b/code/renderers/web-components/src/render.ts index 8347d2002397..5696e983a2df 100644 --- a/code/renderers/web-components/src/render.ts +++ b/code/renderers/web-components/src/render.ts @@ -3,16 +3,33 @@ import global from 'global'; import { dedent } from 'ts-dedent'; -import { render } from 'lit-html'; +import { render as litRender, html } from 'lit-html'; // Keep `.js` extension to avoid issue with Webpack (related to export map?) // eslint-disable-next-line import/extensions import { isTemplateResult } from 'lit-html/directive-helpers.js'; import { simulatePageLoad, simulateDOMContentLoaded } from '@storybook/preview-web'; import type { RenderContext } from '@storybook/store'; +import { ArgsStoryFn } from '@storybook/csf'; import { WebComponentsFramework } from './types'; const { Node } = global; +export const render: ArgsStoryFn = (args, context) => { + const { id, component } = context; + if (!component) { + throw new Error( + `Unable to render story ${id} as the component annotation is missing from the default export` + ); + } + + // FIXME: replace by one of + // - https://github.com/lit/lit/pull/1960 + // - https://github.com/open-wc/open-wc/pull/2398 + const argProps = Object.entries(args).map(([key, val]) => `.${key}=${val}`); + + return html`<${component} ${argProps.join(' ')}>`; +}; + export function renderToDOM( { storyFn, kind, name, showMain, showError, forceRemount }: RenderContext, domElement: Element @@ -29,7 +46,7 @@ export function renderToDOM( } const renderTo = domElement.querySelector('[id="root-inner"]'); - render(element, renderTo); + litRender(element, renderTo); simulatePageLoad(domElement); } else if (typeof element === 'string') { domElement.innerHTML = element; diff --git a/code/renderers/web-components/template/components/Button.js b/code/renderers/web-components/template/components/Button.js new file mode 100644 index 000000000000..f8fa7f0eb27b --- /dev/null +++ b/code/renderers/web-components/template/components/Button.js @@ -0,0 +1,22 @@ +/* eslint-disable import/extensions */ +import { html } from 'lit-html'; +import { styleMap } from 'lit-html/directives/style-map.js'; +import './button.css'; + +/** + * Primary UI component for user interaction + */ +export const Button = ({ primary, backgroundColor = null, size, label, onClick }) => { + const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; + + return html` + + `; +}; diff --git a/code/renderers/web-components/template/components/Pre.js b/code/renderers/web-components/template/components/Pre.js new file mode 100644 index 000000000000..6ef56f08d22a --- /dev/null +++ b/code/renderers/web-components/template/components/Pre.js @@ -0,0 +1,14 @@ +/* eslint-disable import/extensions */ +import { html } from 'lit-html'; +import { styleMap } from 'lit-html/directives/style-map.js'; + +/** + * Helper component for rendering text or data + */ +export const Pre = ({ style, object, text }) => + html` +
+      ${object ? JSON.stringify(object, null, 2) : text}
+    
+ `; diff --git a/code/renderers/web-components/template/components/button.css b/code/renderers/web-components/template/components/button.css new file mode 100644 index 000000000000..dc91dc76370b --- /dev/null +++ b/code/renderers/web-components/template/components/button.css @@ -0,0 +1,30 @@ +.storybook-button { + font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: 700; + border: 0; + border-radius: 3em; + cursor: pointer; + display: inline-block; + line-height: 1; +} +.storybook-button--primary { + color: white; + background-color: #1ea7fd; +} +.storybook-button--secondary { + color: #333; + background-color: transparent; + box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset; +} +.storybook-button--small { + font-size: 12px; + padding: 10px 16px; +} +.storybook-button--medium { + font-size: 14px; + padding: 11px 20px; +} +.storybook-button--large { + font-size: 16px; + padding: 12px 24px; +} diff --git a/code/renderers/web-components/template/components/index.js b/code/renderers/web-components/template/components/index.js new file mode 100644 index 000000000000..45cb33280525 --- /dev/null +++ b/code/renderers/web-components/template/components/index.js @@ -0,0 +1,6 @@ +import globalThis from 'global'; + +import { Button } from './Button'; +import { Pre } from './Pre'; + +globalThis.Components = { Button, Pre }; diff --git a/code/renderers/web-components/template/stories/README.md b/code/renderers/web-components/template/stories/README.md new file mode 100644 index 000000000000..37d8743baec7 --- /dev/null +++ b/code/renderers/web-components/template/stories/README.md @@ -0,0 +1 @@ +Placeholder until we write some render-specific stories diff --git a/code/workspace.json b/code/workspace.json index 75534b115d1e..0bfacb1bbbfa 100644 --- a/code/workspace.json +++ b/code/workspace.json @@ -401,6 +401,11 @@ "type": "library", "implicitDependencies": [] }, + "@storybook/web-components-vite": { + "root": "frameworks/web-components-vite", + "type": "library", + "implicitDependencies": [] + }, "@storybook/web-components-webpack5": { "root": "frameworks/web-components-webpack5", "type": "library", diff --git a/code/yarn.lock b/code/yarn.lock index c8662fd4d0eb..0a85b3209e85 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -8667,6 +8667,7 @@ __metadata: "@storybook/vue3-vite": "workspace:*" "@storybook/vue3-webpack5": "workspace:*" "@storybook/web-components": "workspace:*" + "@storybook/web-components-vite": "workspace:*" "@storybook/web-components-webpack5": "workspace:*" "@testing-library/dom": ^7.29.4 "@testing-library/jest-dom": ^5.11.9 @@ -9233,6 +9234,27 @@ __metadata: languageName: unknown linkType: soft +"@storybook/web-components-vite@workspace:*, @storybook/web-components-vite@workspace:frameworks/web-components-vite": + version: 0.0.0-use.local + resolution: "@storybook/web-components-vite@workspace:frameworks/web-components-vite" + dependencies: + "@storybook/addons": 7.0.0-alpha.34 + "@storybook/builder-vite": 7.0.0-alpha.34 + "@storybook/channel-postmessage": 7.0.0-alpha.34 + "@storybook/channel-websocket": 7.0.0-alpha.34 + "@storybook/client-api": 7.0.0-alpha.34 + "@storybook/core-server": 7.0.0-alpha.34 + "@storybook/node-logger": 7.0.0-alpha.34 + "@storybook/preview-web": 7.0.0-alpha.34 + "@storybook/web-components": 7.0.0-alpha.34 + "@types/node": ^14.14.20 || ^16.0.0 + "@vitejs/plugin-vue": ^3.0.3 + magic-string: ^0.26.1 + typescript: ~4.6.3 + vite: ^3.1.0 + languageName: unknown + linkType: soft + "@storybook/web-components-webpack5@workspace:*, @storybook/web-components-webpack5@workspace:frameworks/web-components-webpack5": version: 0.0.0-use.local resolution: "@storybook/web-components-webpack5@workspace:frameworks/web-components-webpack5" diff --git a/scripts/sandbox.ts b/scripts/sandbox.ts index f1d85de6f6ac..cdc12469723e 100644 --- a/scripts/sandbox.ts +++ b/scripts/sandbox.ts @@ -552,9 +552,7 @@ async function main() { if (require.main === module) { main().catch((err) => { - logger.error('🚨 An error occurred when executing "sandbox":'); - - logger.error(err); + logger.error(err.message); process.exit(1); }); } diff --git a/scripts/utils/exec.ts b/scripts/utils/exec.ts index b3e1af6c3129..16e30bc899b5 100644 --- a/scripts/utils/exec.ts +++ b/scripts/utils/exec.ts @@ -27,7 +27,7 @@ export const exec = async ( const defaultOptions: Options = { shell: true, - stdout: debug ? 'inherit' : 'ignore', + stdout: debug ? 'inherit' : 'pipe', }; let currentChild: ExecaChildProcess; @@ -51,8 +51,7 @@ export const exec = async ( } catch (err) { if (!err.killed) { logger.error(chalk.red(`An error occurred while executing: \`${command}\``)); - logger.error(err); - logger.log(errorMessage); + logger.log(`${errorMessage}\n`); } throw err;