-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Web-components: Add typescript types and CLI template #12395
Changes from 8 commits
a4eb172
9a96e22
e956b0b
aa23127
c27ba99
f335859
bee5bb1
9009066
431d209
6853044
f674915
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Args as DefaultArgs, Annotations, BaseMeta, BaseStory } from '@storybook/addons'; | ||
import { StoryFnHtmlReturnType } from './types'; | ||
|
||
export { Args, ArgTypes, Parameters, StoryContext } from '@storybook/addons'; | ||
|
||
/** | ||
* Metadata to configure the stories for a component. | ||
* | ||
* @see [Default export](https://storybook.js.org/docs/formats/component-story-format/#default-export) | ||
*/ | ||
export type Meta<Args = DefaultArgs> = BaseMeta<string> & Annotations<Args, StoryFnHtmlReturnType>; | ||
|
||
/** | ||
* Story function that represents a component example. | ||
* | ||
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports) | ||
*/ | ||
export type Story<Args = DefaultArgs> = BaseStory<Args, StoryFnHtmlReturnType> & | ||
Annotations<Args, StoryFnHtmlReturnType>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './dist/client/preview/types-6-0.d'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Story, Meta } from '@storybook/web-components'; | ||
import { Button, ButtonProps } from './Button'; | ||
|
||
export default { | ||
title: 'Example/Button', | ||
argTypes: { | ||
backgroundColor: { control: 'color' }, | ||
onClick: { action: 'onClick' }, | ||
}, | ||
} as Meta; | ||
|
||
const Template: Story<Partial<ButtonProps>> = (args) => Button(args); | ||
|
||
export const Primary = Template.bind({}); | ||
Primary.args = { | ||
primary: true, | ||
label: 'Button', | ||
}; | ||
|
||
export const Secondary = Template.bind({}); | ||
Secondary.args = { | ||
label: 'Button', | ||
}; | ||
|
||
export const Large = Template.bind({}); | ||
Large.args = { | ||
size: 'large', | ||
label: 'Button', | ||
}; | ||
|
||
export const Small = Template.bind({}); | ||
Small.args = { | ||
size: 'small', | ||
label: 'Button', | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { html } from 'lit-html'; | ||
import './button.css'; | ||
|
||
export interface ButtonProps { | ||
/** | ||
* Is this the principal call to action on the page? | ||
*/ | ||
primary?: boolean; | ||
/** | ||
* What background color to use | ||
*/ | ||
backgroundColor?: string; | ||
/** | ||
* How large should the button be? | ||
*/ | ||
size?: 'small' | 'medium' | 'large'; | ||
/** | ||
* Button contents | ||
*/ | ||
label: string; | ||
/** | ||
* Optional click handler | ||
*/ | ||
onClick?: () => void; | ||
} | ||
/** | ||
* Primary UI component for user interaction | ||
*/ | ||
export const Button = ({ primary, backgroundColor, size, label, onClick }: ButtonProps) => { | ||
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; | ||
|
||
return html` | ||
<button | ||
type="button" | ||
class=${['storybook-button', `storybook-button--${size || 'medium'}`, mode].join(' ')} | ||
style=${backgroundColor && { backgroundColor }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be aligned with lit best practice we should use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a web component expert but if I'm right, there's other options than lit-html, we tried to limit this dependency in the code we provide. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I get that. I wasn't sure either, we want it to be as generic as possible so it isn't tied into one library. I've since realised too I wasn't quite right as in lit we wouldn't even set this property. We could just leave it as an example if you want to keep it generic though |
||
@click=${onClick} | ||
> | ||
${label} | ||
</button> | ||
`; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Story, Meta } from '@storybook/web-components'; | ||
import { Header, HeaderProps } from './Header'; | ||
|
||
export default { | ||
title: 'Example/Header', | ||
} as Meta; | ||
|
||
const Template: Story<Partial<HeaderProps>> = (args) => Header(args); | ||
|
||
export const LoggedIn = Template.bind({}); | ||
LoggedIn.args = { | ||
user: {}, | ||
}; | ||
|
||
export const LoggedOut = Template.bind({}); | ||
LoggedOut.args = {}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { html } from 'lit-html'; | ||
|
||
import { Button } from './Button'; | ||
import './header.css'; | ||
|
||
export interface HeaderProps { | ||
user?: {}; | ||
onLogin: () => void; | ||
onLogout: () => void; | ||
onCreateAccount: () => void; | ||
} | ||
|
||
export const Header = ({ user, onLogin, onLogout, onCreateAccount }: HeaderProps) => html` | ||
<header> | ||
<div class="wrapper"> | ||
<div> | ||
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"> | ||
<g fill="none" fillRule="evenodd"> | ||
<path | ||
d="M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z" | ||
fill="#FFF" | ||
/> | ||
<path | ||
d="M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z" | ||
fill="#555AB9" | ||
/> | ||
<path | ||
d="M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z" | ||
fill="#91BAF8" | ||
/> | ||
</g> | ||
</svg> | ||
<h1>Acme</h1> | ||
</div> | ||
<div> | ||
${user | ||
? Button({ size: 'small', onClick: onLogout, label: 'Log out' }) | ||
: html`${Button({ | ||
size: 'small', | ||
onClick: onLogin, | ||
label: 'Log in', | ||
})} | ||
${Button({ | ||
primary: true, | ||
size: 'small', | ||
onClick: onCreateAccount, | ||
label: 'Sign up', | ||
})}`} | ||
</div> | ||
</div> | ||
</header> | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Story, Meta } from '@storybook/web-components'; | ||
import { Page, PageProps } from './Page'; | ||
import * as HeaderStories from './Header.stories'; | ||
|
||
export default { | ||
title: 'Example/Page', | ||
} as Meta; | ||
|
||
const Template: Story<Partial<PageProps>> = (args) => Page(args); | ||
|
||
export const LoggedIn = Template.bind({}); | ||
LoggedIn.args = { | ||
...HeaderStories.LoggedIn.args, | ||
}; | ||
|
||
export const LoggedOut = Template.bind({}); | ||
LoggedOut.args = { | ||
...HeaderStories.LoggedOut.args, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { html } from 'lit-html'; | ||
import { Header } from './Header'; | ||
import './page.css'; | ||
|
||
export interface PageProps { | ||
user?: {}; | ||
onLogin: () => void; | ||
onLogout: () => void; | ||
onCreateAccount: () => void; | ||
} | ||
|
||
export const Page = ({ user, onLogin, onLogout, onCreateAccount }: PageProps) => html` | ||
<article> | ||
${Header({ | ||
user, | ||
onLogin, | ||
onLogout, | ||
onCreateAccount, | ||
})} | ||
|
||
<section> | ||
<h2>Pages in Storybook</h2> | ||
<p> | ||
We recommend building UIs with a | ||
<a href="https://componentdriven.org" target="_blank" rel="noopener noreferrer"> | ||
<strong>component-driven</strong> </a | ||
>process starting with atomic components and ending with pages. | ||
</p> | ||
<p> | ||
Render pages with mock data. This makes it easy to build and review page states without | ||
needing to navigate to them in your app. Here are some handy patterns for managing page data | ||
in Storybook: | ||
</p> | ||
<ul> | ||
<li> | ||
Use a higher-level connected component. Storybook helps you compose such data from the | ||
"args" of child component stories | ||
</li> | ||
<li> | ||
Assemble data in the page component from your services. You can mock these services out | ||
using Storybook. | ||
</li> | ||
</ul> | ||
<p> | ||
Get a guided tutorial on component-driven development at | ||
<a href="https://www.learnstorybook.com" target="_blank" rel="noopener noreferrer"> | ||
Learn Storybook | ||
</a> | ||
. Read more in the | ||
<a href="https://storybook.js.org/docs" target="_blank" rel="noopener noreferrer"> | ||
docs | ||
</a> | ||
. | ||
</p> | ||
<div className="tip-wrapper"> | ||
<span className="tip">Tip</span> Adjust the width of the canvas with the | ||
<svg width="10" height="10" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"> | ||
<g fill="none" fillRule="evenodd"> | ||
<path | ||
d="M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z" | ||
id="a" | ||
fill="#999" | ||
/> | ||
</g> | ||
</svg> | ||
Viewports addon in the toolbar | ||
</div> | ||
</section> | ||
</article> | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -299,4 +299,4 @@ | |
] | ||
] | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should make all properties here optional or
ButtonProps
should be exported as a partial type (type ButtonProps = Partial<{...}>
). To simplify all the references to just ButtonPropsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial means you can skip mandatory properties. Which is not what we want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does but my point is everywhere we reference this, we use Partial anyway. So we should probably solve the problem at the interface here rather than every time it gets used (which could mean using partial here or just making the properties optional).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have the same interface for all frameworks. Do you have an example of where Partial would bring value ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not arguing FOR partial im telling you its used already in this PR:
in the stories.
which in every other framework's stories would instead be:
so i was just trying to point out that maybe instead of using partial, we should make the optional properties in
ButtonProps
optional. If that's all of them, fine, or consider using partial when defining the type rather than when using it.