Add Figma integration to Storybook (#12259)

This commit is contained in:
Felix Becker 2020-07-16 18:58:11 +02:00 committed by GitHub
parent 4ef8892591
commit 94d93114e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 319 additions and 192 deletions

View File

@ -4,7 +4,7 @@ const { DefinePlugin, ProgressPlugin } = require('webpack')
const config = {
stories: ['../**/*.story.tsx'],
addons: ['@storybook/addon-knobs', '@storybook/addon-actions', '@storybook/addon-options'],
addons: ['@storybook/addon-knobs', '@storybook/addon-actions', '@storybook/addon-options', 'storybook-addon-designs'],
/**
* @param config {import('webpack').Configuration}
* @returns {import('webpack').Configuration}

View File

@ -4,6 +4,7 @@ import { withInfo } from '@storybook/addon-info'
import { withKnobs } from '@storybook/addon-knobs'
import { addDecorator } from '@storybook/react'
import { setLinkComponent, AnchorLink } from '../shared/src/components/Link'
import { withDesign } from 'storybook-addon-designs'
setLinkComponent(AnchorLink)
@ -12,5 +13,6 @@ setLinkComponent(AnchorLink)
addDecorator(withInfo({ header: false, propTables: false }))
addDecorator(withKnobs)
addDecorator((storyFn, context) => withConsole()(storyFn)(context))
addDecorator(withDesign)
configureActions({ depth: 100, limit: 20 })

View File

@ -237,6 +237,7 @@
"sinon": "^9.0.2",
"socket.io": "^2.3.0",
"socket.io-client": "^2.3.0",
"storybook-addon-designs": "^5.4.0",
"string-width": "^4.2.0",
"style-loader": "^1.2.1",
"stylelint": "^13.6.1",

View File

@ -0,0 +1,21 @@
declare module '@storybook/addons' {
interface Parameters {
design?: DesignParameters | DesignParameters[]
}
}
export interface DesignParameters {
type: 'figma' | 'iframe' | 'image' | 'link' | 'pdf'
url: string
/**
* Change the name of the tab
*/
name?: string
options?: {
/**
* @default 'panel'
*/
renderTarget?: 'tab' | 'panel'
}
}

View File

@ -14,6 +14,7 @@ import { highlightCodeSafe } from '../../../shared/src/util/markdown'
import { Form } from '../components/Form'
import openColor from 'open-color'
import { Menu, MenuButton, MenuList, MenuLink } from '@reach/menu-button'
import 'storybook-addon-designs'
const semanticColors = ['primary', 'secondary', 'success', 'danger', 'warning', 'info', 'merged'] as const
@ -296,24 +297,33 @@ add('Layout', () => (
</>
))
add('Alerts', () => (
<>
<h1>Alerts</h1>
<p>
Provide contextual feedback messages for typical user actions with the handful of available and flexible
alert messages.
</p>
{semanticColors.map(semantic => (
<div key={semantic} className={classNames('alert', `alert-${semantic}`)}>
A simple {semantic} alert check it out! It can also contain{' '}
<a href="" className="alert-link" onClick={flow(preventDefault, action('alert link clicked'))}>
links like this
</a>
.
</div>
))}
</>
))
add(
'Alerts',
() => (
<>
<h1>Alerts</h1>
<p>
Provide contextual feedback messages for typical user actions with the handful of available and flexible
alert messages.
</p>
{semanticColors.map(semantic => (
<div key={semantic} className={classNames('alert', `alert-${semantic}`)}>
A simple {semantic} alert check it out! It can also contain{' '}
<a href="" className="alert-link" onClick={flow(preventDefault, action('alert link clicked'))}>
links like this
</a>
.
</div>
))}
</>
),
{
design: {
type: 'figma',
url: 'https://www.figma.com/file/BkY8Ak997QauG0Iu2EqArv/Sourcegraph-Components?node-id=127%3A4',
},
}
)
add('Badges', () => (
<>
@ -329,46 +339,55 @@ add('Badges', () => (
</>
))
add('Buttons', () => (
<>
<h1>Buttons</h1>
<p>
Use Bootstraps custom button styles for actions in forms, dialogs, and more with support for multiple
sizes, states, and more.{' '}
<a href="https://getbootstrap.com/docs/4.5/components/buttons/">Bootstrap documentation</a>
</p>
<p>
{semanticColors.map(semantic => (
<React.Fragment key={semantic}>
<button
type="button"
key={semantic}
className={classNames('btn', `btn-${semantic}`)}
onClick={flow(preventDefault, action('button clicked'))}
>
{startCase(semantic)}
</button>{' '}
</React.Fragment>
))}
</p>
add(
'Buttons',
() => (
<>
<h1>Buttons</h1>
<p>
Use Bootstraps custom button styles for actions in forms, dialogs, and more with support for multiple
sizes, states, and more.{' '}
<a href="https://getbootstrap.com/docs/4.5/components/buttons/">Bootstrap documentation</a>
</p>
<p>
{semanticColors.map(semantic => (
<React.Fragment key={semantic}>
<button
type="button"
key={semantic}
className={classNames('btn', `btn-${semantic}`)}
onClick={flow(preventDefault, action('button clicked'))}
>
{startCase(semantic)}
</button>{' '}
</React.Fragment>
))}
</p>
<h2>Disabled</h2>
<p>
<button type="button" className="btn btn-primary" disabled={true}>
I am disabled
</button>{' '}
<button type="button" className="btn btn-secondary" disabled={true}>
I am disabled
</button>
</p>
<h2>Disabled</h2>
<p>
<button type="button" className="btn btn-primary" disabled={true}>
I am disabled
</button>{' '}
<button type="button" className="btn btn-secondary" disabled={true}>
I am disabled
</button>
</p>
<h2>Links</h2>
<p>Links can be made to look like buttons too.</p>
<a href="https://example.com" className="btn btn-secondary" target="_blank" rel="noopener noreferrer">
I am a link
</a>
</>
))
<h2>Links</h2>
<p>Links can be made to look like buttons too.</p>
<a href="https://example.com" className="btn btn-secondary" target="_blank" rel="noopener noreferrer">
I am a link
</a>
</>
),
{
design: {
type: 'figma',
url: 'https://www.figma.com/file/BkY8Ak997QauG0Iu2EqArv/Sourcegraph-Components?node-id=35%3A11',
},
}
)
add('Dropdowns', () => (
<>
@ -435,153 +454,177 @@ add('Input groups', () => (
</>
))
add('Forms', () => (
<>
<h1>Forms</h1>
<p>
Forms are validated using native HTML validation. Submit the below form with invalid input to try it out.{' '}
<a href="https://getbootstrap.com/docs/4.5/components/forms/" target="_blank" rel="noopener noreferrer">
Bootstrap documentation
</a>
</p>
<Form onSubmit={preventDefault}>
<div className="form-group">
<label htmlFor="example-email-input">Email address</label>
<input
type="email"
className="form-control"
id="example-email-input"
aria-describedby="email-help"
placeholder="me@example.com"
/>
<small id="email-help" className="form-text text-muted">
We'll never share your email with anyone else.
</small>
</div>
<div className="form-group">
<label htmlFor="example-input-password">Password</label>
<input type="password" className="form-control" id="example-input-password" />
</div>
<div className="form-group">
<label htmlFor="example-example-select">Example select</label>
<select id="example-select" className="form-control">
<option>Option A</option>
<option>Option B</option>
<option>Option C</option>
</select>
</div>
<div className="form-group">
<label htmlFor="example-textarea">Example textarea</label>
<textarea className="form-control" id="example-textarea" rows={3} />
</div>
<div className="form-group form-check">
<input type="checkbox" className="form-check-input" id="exampleCheck1" />
<label className="form-check-label" htmlFor="exampleCheck1">
Check me out
</label>
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</Form>
<h2 className="mt-3">Disabled</h2>
<Form>
<fieldset disabled={true}>
add(
'Forms',
() => (
<>
<h1>Forms</h1>
<p>
Forms are validated using native HTML validation. Submit the below form with invalid input to try it
out.{' '}
<a href="https://getbootstrap.com/docs/4.5/components/forms/" target="_blank" rel="noopener noreferrer">
Bootstrap documentation
</a>
</p>
<Form onSubmit={preventDefault}>
<div className="form-group">
<label htmlFor="disabledTextInput">Disabled input</label>
<input type="text" id="disabledTextInput" className="form-control" placeholder="Disabled input" />
<label htmlFor="example-email-input">Email address</label>
<input
type="email"
className="form-control"
id="example-email-input"
aria-describedby="email-help"
placeholder="me@example.com"
/>
<small id="email-help" className="form-text text-muted">
We'll never share your email with anyone else.
</small>
</div>
<div className="form-group">
<label htmlFor="disabledSelect">Disabled select menu</label>
<select id="disabledSelect" className="form-control">
<option>Disabled select</option>
<label htmlFor="example-input-password">Password</label>
<input type="password" className="form-control" id="example-input-password" />
</div>
<div className="form-group">
<label htmlFor="example-example-select">Example select</label>
<select id="example-select" className="form-control">
<option>Option A</option>
<option>Option B</option>
<option>Option C</option>
</select>
</div>
<div className="form-group">
<div className="form-check">
<input
className="form-check-input"
type="checkbox"
id="disabledFieldsetCheck"
disabled={true}
/>
<label className="form-check-label" htmlFor="disabledFieldsetCheck">
Can't check this
</label>
</div>
<label htmlFor="example-textarea">Example textarea</label>
<textarea className="form-control" id="example-textarea" rows={3} />
</div>
<div className="form-group form-check">
<input type="checkbox" className="form-check-input" id="exampleCheck1" />
<label className="form-check-label" htmlFor="exampleCheck1">
Check me out
</label>
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</fieldset>
</Form>
</Form>
<h2 className="mt-3">Readonly</h2>
<input className="form-control" type="text" value="I'm a readonly value" readOnly={true} />
<h2 className="mt-3">Disabled</h2>
<Form>
<fieldset disabled={true}>
<div className="form-group">
<label htmlFor="disabledTextInput">Disabled input</label>
<input
type="text"
id="disabledTextInput"
className="form-control"
placeholder="Disabled input"
/>
</div>
<div className="form-group">
<label htmlFor="disabledSelect">Disabled select menu</label>
<select id="disabledSelect" className="form-control">
<option>Disabled select</option>
</select>
</div>
<div className="form-group">
<div className="form-check">
<input
className="form-check-input"
type="checkbox"
id="disabledFieldsetCheck"
disabled={true}
/>
<label className="form-check-label" htmlFor="disabledFieldsetCheck">
Can't check this
</label>
</div>
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</fieldset>
</Form>
<h2 className="mt-3">Sizing</h2>
<p>Form controls can be made smaller or larger for rare use cases, like a select inside a dropdown menu.</p>
<div className="d-flex">
<div>
<input className="form-control form-control-lg mb-1" type="text" placeholder="Large input" />
<input className="form-control mb-1" type="text" placeholder="Default input" />
<input className="form-control form-control-sm mb-1" type="text" placeholder="Small input" />
<h2 className="mt-3">Readonly</h2>
<input className="form-control" type="text" value="I'm a readonly value" readOnly={true} />
<h2 className="mt-3">Sizing</h2>
<p>Form controls can be made smaller or larger for rare use cases, like a select inside a dropdown menu.</p>
<div className="d-flex">
<div>
<input className="form-control form-control-lg mb-1" type="text" placeholder="Large input" />
<input className="form-control mb-1" type="text" placeholder="Default input" />
<input className="form-control form-control-sm mb-1" type="text" placeholder="Small input" />
</div>
<div className="ml-2">
<select className="form-control form-control-lg mb-1">
<option>Large select</option>
</select>
<select className="form-control mb-1">
<option>Default select</option>
</select>
<select className="form-control form-control-sm mb-1">
<option>Small select</option>
</select>
</div>
</div>
<div className="ml-2">
<select className="form-control form-control-lg mb-1">
<option>Large select</option>
</select>
<select className="form-control mb-1">
<option>Default select</option>
</select>
<select className="form-control form-control-sm mb-1">
<option>Small select</option>
</select>
</>
),
{
design: {
type: 'figma',
url: 'https://www.figma.com/file/BkY8Ak997QauG0Iu2EqArv/Sourcegraph-Components?node-id=30%3A24',
},
}
)
add(
'Cards',
() => (
<>
<h1>Cards</h1>
<p>
A card is a flexible and extensible content container. It includes options for headers and footers, a
wide variety of content, contextual background colors, and powerful display options.{' '}
<a href="https://getbootstrap.com/docs/4.5/components/card/">Bootstrap documentation</a>
</p>
<h2>Examples</h2>
<div className="card mb-3">
<div className="card-body">This is some text within a card body.</div>
</div>
</div>
</>
))
add('Cards', () => (
<>
<h1>Cards</h1>
<p>
A card is a flexible and extensible content container. It includes options for headers and footers, a wide
variety of content, contextual background colors, and powerful display options.{' '}
<a href="https://getbootstrap.com/docs/4.5/components/card/">Bootstrap documentation</a>
</p>
<h2>Examples</h2>
<div className="card mb-3">
<div className="card-body">This is some text within a card body.</div>
</div>
<div className="card mb-3" style={{ maxWidth: '18rem' }}>
<div className="card-body">
<h3 className="card-title">Card title</h3>
<p className="card-text">
Some quick example text to build on the card title and make up the bulk of the card's content.
</p>
<button type="button" className="btn btn-primary">
Do something
</button>
<div className="card mb-3" style={{ maxWidth: '18rem' }}>
<div className="card-body">
<h3 className="card-title">Card title</h3>
<p className="card-text">
Some quick example text to build on the card title and make up the bulk of the card's content.
</p>
<button type="button" className="btn btn-primary">
Do something
</button>
</div>
</div>
</div>
<div className="card">
<div className="card-header">Featured</div>
<div className="card-body">
<h3 className="card-title">Special title treatment</h3>
<p className="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="https://example.com" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
Go somewhere
</a>
<div className="card">
<div className="card-header">Featured</div>
<div className="card-body">
<h3 className="card-title">Special title treatment</h3>
<p className="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="https://example.com" target="_blank" rel="noopener noreferrer" className="btn btn-primary">
Go somewhere
</a>
</div>
</div>
</div>
</>
))
</>
),
{
design: {
type: 'figma',
url: 'https://www.figma.com/file/BkY8Ak997QauG0Iu2EqArv/Sourcegraph-Components?node-id=109%3A2',
},
}
)
add('List groups', () => (
<>

View File

@ -32,8 +32,18 @@ const commonProps = subtypeOf<Partial<VersionContextDropdownProps>>()({
setVersionContext,
})
add('No context selected', () => <VersionContextDropdown {...commonProps} versionContext={undefined} />)
add('Context selected', () => <VersionContextDropdown {...commonProps} versionContext="test 1" />)
add('No context selected', () => <VersionContextDropdown {...commonProps} versionContext={undefined} />, {
design: {
type: 'figma',
url: 'https://www.figma.com/file/Sax8ctk8GhvWd0vrzkHSDK/Version-Contexts?node-id=97%3A175',
},
})
add('Context selected', () => <VersionContextDropdown {...commonProps} versionContext="test 1" />, {
design: {
type: 'figma',
url: 'https://www.figma.com/file/Sax8ctk8GhvWd0vrzkHSDK/Version-Contexts?node-id=95%3A22516',
},
})
add('Selected context appears at the top of the list', () => (
<VersionContextDropdown {...commonProps} versionContext="test 3" />
))

View File

@ -16,7 +16,13 @@ import { MemoryRouter } from 'react-router'
import webStyles from '../SourcegraphWebApp.scss'
const { add } = storiesOf('web/RepogroupPage', module)
.addParameters({ percy: { widths: [993] } })
.addParameters({
percy: { widths: [993] },
design: {
type: 'figma',
url: 'https://www.figma.com/file/Xc4M24VTQq8itU0Lgb1Wwm/RFC-159-Visual-Design?node-id=66%3A611',
},
})
.addDecorator(story => (
<>
<style>{webStyles}</style>

View File

@ -2303,7 +2303,8 @@
integrity sha512-KWxkyphmlwam8kfYPSmoitKQRMGQCsr1ZRmNZgijT7ABKaVyk/+I5ezt2J213tM04Hi0vyg4L7iH1VCkNvm2Jw==
"@sourcegraph/extension-api-types@link:packages/@sourcegraph/extension-api-types":
version "2.1.0"
version "0.0.0"
uid ""
"@sourcegraph/prettierrc@^3.0.3":
version "3.0.3"
@ -14320,7 +14321,7 @@ lodash.memoize@^4.1.2:
resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.once@^4.0.0:
lodash.once@^4.0.0, lodash.once@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
@ -14548,6 +14549,11 @@ make-error@^1.1.1:
resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
make-event-props@^1.1.0:
version "1.2.0"
resolved "https://registry.npmjs.org/make-event-props/-/make-event-props-1.2.0.tgz#96b87d88919533b8f8934b58b4c3d5679459a0cf"
integrity sha512-BmWFkm/jZzVH9A0tEBdkjAARUz/eha+5IRyfOndeSMKRadkgR5DawoBHoRwLxkYmjJOI5bHkXKpaZocxj+dKgg==
make-fetch-happen@^5.0.0:
version "5.0.2"
resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd"
@ -14853,6 +14859,11 @@ meow@^7.0.1:
type-fest "^0.13.1"
yargs-parser "^18.1.3"
merge-class-names@^1.1.1:
version "1.3.0"
resolved "https://registry.npmjs.org/merge-class-names/-/merge-class-names-1.3.0.tgz#c4cdc1a981a81dd9afc27aa4287e912a337c5dee"
integrity sha512-k0Qaj36VBpKgdc8c188LEZvo6v/zzry/FUufwopWbMSp6/knfVFU/KIB55/hJjeIpg18IH2WskXJCRnM/1BrdQ==
merge-deep@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2"
@ -15464,6 +15475,11 @@ node-dir@^0.1.10:
dependencies:
minimatch "^3.0.2"
node-ensure@^0.0.0:
version "0.0.0"
resolved "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
integrity sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc=
node-environment-flags@1.0.6:
version "1.0.6"
resolved "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088"
@ -16857,6 +16873,14 @@ pbkdf2@^3.0.3:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
pdfjs-dist@2.1.266:
version "2.1.266"
resolved "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.1.266.tgz#cded02268b389559e807f410d2a729db62160026"
integrity sha512-Jy7o1wE3NezPxozexSbq4ltuLT0Z21ew/qrEiAEeUZzHxMHGk4DUV1D7RuCXg5vJDvHmjX1YssN+we9QfRRgXQ==
dependencies:
node-ensure "^0.0.0"
worker-loader "^2.0.0"
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
@ -18228,6 +18252,18 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-pdf@^4.0.5:
version "4.1.0"
resolved "https://registry.npmjs.org/react-pdf/-/react-pdf-4.1.0.tgz#fcb874f28050fe9593c4e04652c7bff94bb1acf9"
integrity sha512-SYwkWc+vRQHfrpDls3DOgn4G+wT0mYGJRor20e28GPRW8VB+6o8WqZ4QZxsl50z+dKM7UscXFnK/02eN3NXi2g==
dependencies:
"@babel/runtime" "^7.0.0"
lodash.once "^4.1.1"
make-event-props "^1.1.0"
merge-class-names "^1.1.1"
pdfjs-dist "2.1.266"
prop-types "^15.6.2"
react-popper-tooltip@^2.8.3:
version "2.8.3"
resolved "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.8.3.tgz#1c63e7473a96362bd93be6c94fa404470a265197"
@ -20169,7 +20205,8 @@ sourcegraph@^24.0.0:
integrity sha512-PlGvkdBy5r5iHdKAVNY/jsPgWb3oY+2iAdIQ3qR83UHhvBFVgoctDAnyfJ1eMstENY3etBWtAJ8Kleoar3ecaA==
"sourcegraph@link:packages/sourcegraph-extension-api":
version "24.7.0"
version "0.0.0"
uid ""
space-separated-tokens@^1.0.0:
version "1.1.2"
@ -20413,6 +20450,13 @@ store2@^2.7.1:
resolved "https://registry.npmjs.org/store2/-/store2-2.7.1.tgz#22070b7dc04748a792fc6912a58ab99d3a21d788"
integrity sha512-zzzP5ZY6QWumnAFV6kBRbS44pUMcpZBNER5DWUe1HETlaKXqLcCQxbNu6IHaKr1pUsjuhUGBdOy8sWKmMkL6pQ==
storybook-addon-designs@^5.4.0:
version "5.4.0"
resolved "https://registry.npmjs.org/storybook-addon-designs/-/storybook-addon-designs-5.4.0.tgz#f1a40d27766ec5c1603a8d333c54270ed1609f65"
integrity sha512-1tW5a956pHaDA3hrDRZFborJibGmu/rYviacrBmNG8QoW4TFnsu80qPfOKbkG0b/vbnqh7WukTRVh2UE8ZoMDw==
dependencies:
react-pdf "^4.0.5"
storybook-chromatic@^2.2.2:
version "2.2.2"
resolved "https://registry.npmjs.org/storybook-chromatic/-/storybook-chromatic-2.2.2.tgz#eade5178f334d6dd173dbe980c902ae90e727cb0"