mirror of
https://github.com/storybookjs/storybook.git
synced 2025-03-31 05:03:21 +08:00
Merge pull request #16178 from jpzwarte/web-components/generate-event-handlers
Web-components: Autogenerate action argTypes for events.
This commit is contained in:
commit
6fa7fd1a2f
@ -0,0 +1,448 @@
|
||||
{
|
||||
"schemaVersion": "1.0.0",
|
||||
"readme": "",
|
||||
"modules": [
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "demo-wc-card.js",
|
||||
"declarations": [],
|
||||
"exports": [
|
||||
{
|
||||
"kind": "custom-element-definition",
|
||||
"name": "demo-wc-card",
|
||||
"declaration": {
|
||||
"name": "DemoWcCard",
|
||||
"module": "/src/stories/misc/to-update/DemoWcCard.js"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "src/typings.d.ts",
|
||||
"declarations": [],
|
||||
"exports": []
|
||||
},
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "src/components/sb-button.ts",
|
||||
"declarations": [
|
||||
{
|
||||
"kind": "class",
|
||||
"description": "",
|
||||
"name": "SbButton",
|
||||
"cssProperties": [
|
||||
{
|
||||
"description": "Controls the color of bar",
|
||||
"name": "--sb-primary-color",
|
||||
"default": "#1ea7fd"
|
||||
}
|
||||
],
|
||||
"members": [
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "primary",
|
||||
"type": {
|
||||
"text": "boolean"
|
||||
},
|
||||
"description": "Set button in primary mode",
|
||||
"privacy": "public"
|
||||
},
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "backgroundColor",
|
||||
"type": {
|
||||
"text": "string"
|
||||
},
|
||||
"privacy": "public"
|
||||
},
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "size",
|
||||
"type": {
|
||||
"text": "'small' | 'medium' | 'large'"
|
||||
},
|
||||
"default": "'medium'",
|
||||
"privacy": "public"
|
||||
},
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "label",
|
||||
"default": "''",
|
||||
"privacy": "public"
|
||||
},
|
||||
{
|
||||
"kind": "method",
|
||||
"name": "onClick",
|
||||
"privacy": "private"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "sb-button:click",
|
||||
"type": {
|
||||
"text": "CustomEvent"
|
||||
},
|
||||
"description": "Custom event send when the button is clicked"
|
||||
}
|
||||
],
|
||||
"attributes": [
|
||||
{
|
||||
"type": {
|
||||
"text": "string"
|
||||
},
|
||||
"description": "Label of the button",
|
||||
"name": "label"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"text": "string"
|
||||
},
|
||||
"description": "Size of the button, can be \"small\", \"medium\" or \"large\"; default is \"medium\".",
|
||||
"name": "size"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"text": "string"
|
||||
},
|
||||
"description": "Color of the button's background",
|
||||
"name": "backgroundColor"
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"fieldName": "label"
|
||||
},
|
||||
{
|
||||
"name": "primary",
|
||||
"fieldName": "primary"
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"fieldName": "size"
|
||||
},
|
||||
{
|
||||
"name": "backgroundColor",
|
||||
"fieldName": "backgroundColor"
|
||||
}
|
||||
],
|
||||
"superclass": {
|
||||
"name": "LitElement",
|
||||
"package": "lit"
|
||||
},
|
||||
"tagName": "sb-button",
|
||||
"summary": "This is a simple Storybook Button",
|
||||
"customElement": true
|
||||
}
|
||||
],
|
||||
"exports": [
|
||||
{
|
||||
"kind": "js",
|
||||
"name": "SbButton",
|
||||
"declaration": {
|
||||
"name": "SbButton",
|
||||
"module": "src/components/sb-button.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "custom-element-definition",
|
||||
"name": "sb-button",
|
||||
"declaration": {
|
||||
"name": "SbButton",
|
||||
"module": "src/components/sb-button.ts"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "src/components/sb-header.ts",
|
||||
"declarations": [
|
||||
{
|
||||
"kind": "class",
|
||||
"description": "",
|
||||
"name": "SbHeader",
|
||||
"members": [
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "user",
|
||||
"type": {
|
||||
"text": "{}"
|
||||
},
|
||||
"privacy": "public"
|
||||
},
|
||||
{
|
||||
"kind": "method",
|
||||
"name": "dispatchCustomEvent",
|
||||
"privacy": "private",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "eventName",
|
||||
"type": {
|
||||
"text": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "method",
|
||||
"name": "logInOutButton",
|
||||
"privacy": "private"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"type": {
|
||||
"text": "CustomEvent"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"text": "CustomEvent"
|
||||
},
|
||||
"description": "Event send when user clicks on create account button",
|
||||
"name": "sb-header:createAccount"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"text": "CustomEvent"
|
||||
},
|
||||
"description": "Event send when user clicks on login button",
|
||||
"name": "sb-header:login"
|
||||
},
|
||||
{
|
||||
"type": {
|
||||
"text": "CustomEvent"
|
||||
},
|
||||
"description": "Event send when user clicks on logout button",
|
||||
"name": "sb-header:logout"
|
||||
}
|
||||
],
|
||||
"attributes": [
|
||||
{
|
||||
"type": {
|
||||
"text": "Object"
|
||||
},
|
||||
"description": "User of the app",
|
||||
"name": "user"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"fieldName": "user"
|
||||
}
|
||||
],
|
||||
"superclass": {
|
||||
"name": "LitElement",
|
||||
"package": "lit"
|
||||
},
|
||||
"tagName": "sb-header",
|
||||
"summary": "This is a simple Storybook Header",
|
||||
"customElement": true
|
||||
}
|
||||
],
|
||||
"exports": [
|
||||
{
|
||||
"kind": "js",
|
||||
"name": "SbHeader",
|
||||
"declaration": {
|
||||
"name": "SbHeader",
|
||||
"module": "src/components/sb-header.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "custom-element-definition",
|
||||
"name": "sb-header",
|
||||
"declaration": {
|
||||
"name": "SbHeader",
|
||||
"module": "src/components/sb-header.ts"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "src/components/sb-page.ts",
|
||||
"declarations": [
|
||||
{
|
||||
"kind": "class",
|
||||
"description": "",
|
||||
"name": "SbPage",
|
||||
"members": [
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "user",
|
||||
"type": {
|
||||
"text": "{}"
|
||||
},
|
||||
"privacy": "public"
|
||||
}
|
||||
],
|
||||
"attributes": [
|
||||
{
|
||||
"type": {
|
||||
"text": "Object"
|
||||
},
|
||||
"description": "User of the app",
|
||||
"name": "user"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"fieldName": "user"
|
||||
}
|
||||
],
|
||||
"superclass": {
|
||||
"name": "LitElement",
|
||||
"package": "lit"
|
||||
},
|
||||
"tagName": "sb-page",
|
||||
"summary": "This is a simple Storybook Page",
|
||||
"customElement": true
|
||||
}
|
||||
],
|
||||
"exports": [
|
||||
{
|
||||
"kind": "js",
|
||||
"name": "SbPage",
|
||||
"declaration": {
|
||||
"name": "SbPage",
|
||||
"module": "src/components/sb-page.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "custom-element-definition",
|
||||
"name": "sb-page",
|
||||
"declaration": {
|
||||
"name": "SbPage",
|
||||
"module": "src/components/sb-page.ts"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "src/stories/misc/to-update/DemoWcCard.js",
|
||||
"declarations": [
|
||||
{
|
||||
"kind": "class",
|
||||
"description": "This is a container looking like a card with a back and front side you can switch",
|
||||
"name": "DemoWcCard",
|
||||
"cssProperties": [
|
||||
{
|
||||
"description": "Header font size",
|
||||
"name": "--demo-wc-card-header-font-size"
|
||||
},
|
||||
{
|
||||
"description": "Font color for front",
|
||||
"name": "--demo-wc-card-front-color"
|
||||
},
|
||||
{
|
||||
"description": "Font color for back",
|
||||
"name": "--demo-wc-card-back-color"
|
||||
}
|
||||
],
|
||||
"cssParts": [
|
||||
{
|
||||
"description": "Front of the card",
|
||||
"name": "front"
|
||||
},
|
||||
{
|
||||
"description": "Back of the card",
|
||||
"name": "back"
|
||||
}
|
||||
],
|
||||
"slots": [
|
||||
{
|
||||
"description": "This is an unnamed slot (the default slot)",
|
||||
"name": ""
|
||||
}
|
||||
],
|
||||
"members": [
|
||||
{
|
||||
"kind": "method",
|
||||
"name": "toggle"
|
||||
},
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "backSide",
|
||||
"privacy": "public",
|
||||
"description": "Indicates that the back of the card is shown",
|
||||
"default": "false"
|
||||
},
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "header",
|
||||
"privacy": "public",
|
||||
"description": "Header message",
|
||||
"default": "'Your Message'"
|
||||
},
|
||||
{
|
||||
"kind": "field",
|
||||
"name": "rows",
|
||||
"privacy": "public",
|
||||
"description": "Data rows",
|
||||
"default": "[]"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "side-changed",
|
||||
"type": {
|
||||
"text": "CustomEvent"
|
||||
},
|
||||
"description": "Fires whenever it switches between front/back"
|
||||
}
|
||||
],
|
||||
"attributes": [
|
||||
{
|
||||
"name": "back-side",
|
||||
"fieldName": "backSide"
|
||||
},
|
||||
{
|
||||
"name": "header",
|
||||
"fieldName": "header"
|
||||
},
|
||||
{
|
||||
"name": "rows",
|
||||
"fieldName": "rows"
|
||||
}
|
||||
],
|
||||
"superclass": {
|
||||
"name": "LitElement",
|
||||
"package": "lit"
|
||||
},
|
||||
"tagName": "demo-wc-card",
|
||||
"customElement": true
|
||||
}
|
||||
],
|
||||
"exports": [
|
||||
{
|
||||
"kind": "js",
|
||||
"name": "DemoWcCard",
|
||||
"declaration": {
|
||||
"name": "DemoWcCard",
|
||||
"module": "src/stories/misc/to-update/DemoWcCard.js"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "javascript-module",
|
||||
"path": "src/stories/misc/to-update/demoWcCardStyle.css.js",
|
||||
"declarations": [
|
||||
{
|
||||
"kind": "variable",
|
||||
"name": "demoWcCardStyle"
|
||||
}
|
||||
],
|
||||
"exports": [
|
||||
{
|
||||
"kind": "js",
|
||||
"name": "demoWcCardStyle",
|
||||
"declaration": {
|
||||
"name": "demoWcCardStyle",
|
||||
"module": "src/stories/misc/to-update/demoWcCardStyle.css.js"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -2,23 +2,6 @@
|
||||
|
||||
exports[`web-components component properties lit-element-demo-card 1`] = `
|
||||
Object {
|
||||
"": Object {
|
||||
"description": "This is an unnamed slot (the default slot)",
|
||||
"name": "",
|
||||
"required": false,
|
||||
"table": Object {
|
||||
"category": "slots",
|
||||
"defaultValue": Object {
|
||||
"summary": undefined,
|
||||
},
|
||||
"type": Object {
|
||||
"summary": undefined,
|
||||
},
|
||||
},
|
||||
"type": Object {
|
||||
"name": "void",
|
||||
},
|
||||
},
|
||||
"--demo-wc-card-back-color": Object {
|
||||
"description": "Font color for back",
|
||||
"name": "--demo-wc-card-back-color",
|
||||
@ -155,6 +138,15 @@ Object {
|
||||
"name": "string",
|
||||
},
|
||||
},
|
||||
"onSideChanged": Object {
|
||||
"action": Object {
|
||||
"name": "side-changed",
|
||||
},
|
||||
"name": "onSideChanged",
|
||||
"table": Object {
|
||||
"disable": true,
|
||||
},
|
||||
},
|
||||
"rows": Object {
|
||||
"description": "Data rows",
|
||||
"name": "rows",
|
||||
|
@ -0,0 +1,50 @@
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
import global from 'global';
|
||||
import { extractArgTypes } from './custom-elements';
|
||||
import customElementsManifest from './__testfixtures__/custom-elements.json';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__: any;
|
||||
}
|
||||
}
|
||||
|
||||
const { window } = global;
|
||||
|
||||
describe('extractArgTypes', () => {
|
||||
beforeEach(() => {
|
||||
window.__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__ = customElementsManifest;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.__STORYBOOK_CUSTOM_ELEMENTS_MANIFEST__ = undefined;
|
||||
});
|
||||
|
||||
describe('events', () => {
|
||||
it('should map to an action event handler', () => {
|
||||
const { onSbHeaderCreateAccount } = extractArgTypes('sb-header');
|
||||
|
||||
expect(onSbHeaderCreateAccount).toEqual({
|
||||
name: 'onSbHeaderCreateAccount',
|
||||
action: { name: 'sb-header:createAccount' },
|
||||
table: { disable: true },
|
||||
});
|
||||
});
|
||||
|
||||
it('should map to a regular item', () => {
|
||||
const { 'sb-header:createAccount': item } = extractArgTypes('sb-header');
|
||||
|
||||
expect(item).toEqual({
|
||||
name: 'sb-header:createAccount',
|
||||
required: false,
|
||||
description: 'Event send when user clicks on create account button',
|
||||
type: { name: 'void' },
|
||||
table: {
|
||||
category: 'events',
|
||||
type: { summary: 'CustomEvent' },
|
||||
defaultValue: { summary: undefined },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -1,10 +1,10 @@
|
||||
import { getCustomElements, isValidComponent, isValidMetaData } from '@storybook/web-components';
|
||||
import { ArgTypes } from '@storybook/api';
|
||||
import { ArgType, ArgTypes } from '@storybook/api';
|
||||
import { logger } from '@storybook/client-logger';
|
||||
|
||||
interface TagItem {
|
||||
name: string;
|
||||
type: { text: string };
|
||||
type: { [key: string]: any };
|
||||
description: string;
|
||||
default?: any;
|
||||
kind?: string;
|
||||
@ -50,30 +50,57 @@ function mapData(data: TagItem[], category: string) {
|
||||
return (
|
||||
data &&
|
||||
data
|
||||
.filter((item) => !!item)
|
||||
.filter((item) => item && item.name)
|
||||
.reduce((acc, item) => {
|
||||
if (item.kind === 'method') return acc;
|
||||
|
||||
const type =
|
||||
category === 'properties' ? { name: item.type?.text || item.type } : { name: 'void' };
|
||||
acc[item.name] = {
|
||||
name: item.name,
|
||||
required: false,
|
||||
description: item.description,
|
||||
type,
|
||||
table: {
|
||||
category,
|
||||
type: { summary: item.type?.text || item.type },
|
||||
defaultValue: {
|
||||
summary: item.default !== undefined ? item.default : item.defaultValue,
|
||||
},
|
||||
},
|
||||
};
|
||||
switch (category) {
|
||||
case 'events':
|
||||
mapEvent(item).forEach((argType) => {
|
||||
acc[argType.name] = argType;
|
||||
});
|
||||
break;
|
||||
default:
|
||||
acc[item.name] = mapItem(item, category);
|
||||
break;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {} as ArgTypes)
|
||||
);
|
||||
}
|
||||
|
||||
function mapItem(item: TagItem, category: string): ArgType {
|
||||
const type =
|
||||
category === 'properties' ? { name: item.type?.text || item.type } : { name: 'void' };
|
||||
|
||||
return {
|
||||
name: item.name,
|
||||
required: false,
|
||||
description: item.description,
|
||||
type,
|
||||
table: {
|
||||
category,
|
||||
type: { summary: item.type?.text || item.type },
|
||||
defaultValue: {
|
||||
summary: item.default !== undefined ? item.default : item.defaultValue,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function mapEvent(item: TagItem): ArgType[] {
|
||||
let name = item.name
|
||||
.replace(/(-|_|:|\.|\s)+(.)?/g, (_match, _separator, chr: string) => {
|
||||
return chr ? chr.toUpperCase() : '';
|
||||
})
|
||||
.replace(/^([A-Z])/, (match) => match.toLowerCase());
|
||||
|
||||
name = `on${name.charAt(0).toUpperCase() + name.substr(1)}`;
|
||||
|
||||
return [{ name, action: { name: item.name }, table: { disable: true } }, mapItem(item, 'events')];
|
||||
}
|
||||
|
||||
const getMetaDataExperimental = (tagName: string, customElements: CustomElements) => {
|
||||
if (!isValidComponent(tagName) || !isValidMetaData(customElements)) {
|
||||
return null;
|
||||
|
@ -9,12 +9,30 @@ export default {
|
||||
component: 'sb-header',
|
||||
} as Meta;
|
||||
|
||||
const Template: Story<SbHeader> = ({ user }) => html`<sb-header .user="${user}"></sb-header>`;
|
||||
interface SbHeaderProps extends SbHeader {
|
||||
onSbHeaderCreateAccount: (event: Event) => void;
|
||||
onSbHeaderLogin: (event: Event) => void;
|
||||
onSbHeaderLogout: (event: Event) => void;
|
||||
}
|
||||
|
||||
export const LoggedIn: Story<SbHeader> = Template.bind({});
|
||||
const Template: Story<SbHeaderProps> = ({
|
||||
user,
|
||||
onSbHeaderCreateAccount,
|
||||
onSbHeaderLogin,
|
||||
onSbHeaderLogout,
|
||||
}) => {
|
||||
return html`<sb-header
|
||||
@sb-header:createAccount=${onSbHeaderCreateAccount}
|
||||
@sb-header:login=${onSbHeaderLogin}
|
||||
@sb-header:logout=${onSbHeaderLogout}
|
||||
.user=${user}
|
||||
></sb-header>`;
|
||||
};
|
||||
|
||||
export const LoggedIn: Story<SbHeaderProps> = Template.bind({});
|
||||
LoggedIn.args = {
|
||||
user: {},
|
||||
};
|
||||
|
||||
export const LoggedOut: Story<SbHeader> = Template.bind({});
|
||||
export const LoggedOut: Story<SbHeaderProps> = Template.bind({});
|
||||
LoggedOut.args = {};
|
||||
|
@ -104,10 +104,16 @@ export class SbHeader extends LitElement {
|
||||
|
||||
private logInOutButton() {
|
||||
return this.user
|
||||
? html`<sb-button size="small" @sb-button:click="${() => this.dispatchCustomEvent('logout')} "
|
||||
label = "Log out" </sb-button>`
|
||||
: html`<sb-button size="small" @sb-button:click="${() => this.dispatchCustomEvent('login')}"
|
||||
label="Log in" </sb-button>`;
|
||||
? html`<sb-button
|
||||
size="small"
|
||||
@sb-button:click="${() => this.dispatchCustomEvent('logout')}"
|
||||
label="Log out"
|
||||
></sb-button>`
|
||||
: html`<sb-button
|
||||
size="small"
|
||||
@sb-button:click="${() => this.dispatchCustomEvent('login')}"
|
||||
label="Log in"
|
||||
></sb-button>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user