Skip to content

Commit

Permalink
Storybook enhancements - prototyping + docs (primer#1747)
Browse files Browse the repository at this point in the history
* set up prototyping playground

* colorblock component

* add color picker

* update select to radio

* check focus state shortcut

* move stories from focus pr + add focus control

* add all form elements

* typo

* add toc, fix radio options

* fix dev script

* add focus state as class for theme testing

* fix radio example in playground
  • Loading branch information
langermank authored Nov 16, 2021
1 parent 104228f commit f824581
Show file tree
Hide file tree
Showing 21 changed files with 1,792 additions and 83 deletions.
111 changes: 55 additions & 56 deletions .vscode/story-template.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -7,71 +7,70 @@
"// import { StoryTemplateName } from './OtherStoryFile.stories' // import stories for component compositions",
"",
"export default {",
" title: 'Components/ComponentName',",
" excludeStories: ['ComponentTemplateName'],",
" argTypes: {",
" booleanExample: {",
" control: { type: 'boolean' },",
" description: 'true/false toggle to controls',",
" table: {",
" category: 'Pick one: CSS, HTML, Interactive'",
" }",
" },",
" selectExample: {",
" options: [0, 1, 2, 3], // iterator",
" mapping: ['string1', 'string2', 'string3', 'string4'], // values",
" control: {",
" type: 'select',",
" labels: ['string1-label', 'string2-label', 'string3-label', 'string4-label'] // public labels",
" },",
" description: 'select menu mapping to strings (example: use for variant class names)',",
" table: {",
" category: 'Pick one: CSS, HTML, Interactive'",
" }",
" },",
" stringExample: {",
" name: 'stringExample',",
" type: 'string',",
" description: 'text box control',",
" table: {",
" category: 'Pick one: CSS, HTML, Interactive'",
" }",
" },",
" children: {",
" description: 'creates a slot for children',",
" table: {",
" category: 'HTML'",
" }",
" },",
" title: 'Components/ComponentName',",
" excludeStories: ['ComponentTemplateName'],",
" layout: 'padded',",
" argTypes: {",
" booleanExample: {",
" control: {type: 'boolean'},",
" description: 'true/false toggle to controls',",
" table: {",
" category: 'Pick one: CSS, HTML, Interactive'",
" }",
" },",
" radioExample: {",
" options: ['string1', 'string2', 'string3', 'string4'],",
" control: {",
" type: 'inline-radio',",
" },",
" description: 'radio buttons mapping to strings (example: use for variant class names)',",
" table: {",
" category: 'Pick one: CSS, HTML, Interactive'",
" }",
" },",
" stringExample: {",
" name: 'stringExample',",
" type: 'string',",
" description: 'text box control',",
" table: {",
" category: 'Pick one: CSS, HTML, Interactive'",
" }",
" },",
" children: {",
" description: 'creates a slot for children',",
" table: {",
" category: 'HTML'",
" }",
" }",
" }",
"}",
"",
"// build every component case here in the template (private api)",
"export const ComponentTemplateName = ({ booleanExample, selectExample, stringExample, children }) => (",
" <div",
" // use clsx for multiple classnames",
" className={clsx('defaultClass', selectExample && `${selectExample}`, booleanExample && 'defaultClass--modifier')}",
" // use undefined for values that shouldn't be set if false",
" aria-hidden={booleanExample ? 'true' : undefined}",
" >",
" {/* use {children} for wrapper component templates */}",
" <>",
" {stringExample}",
" {children}",
" </>",
" </div>",
"export const ComponentTemplateName = ({booleanExample, radioExample, stringExample, children}) => (",
" <div",
" // use clsx for multiple classnames",
" className={clsx('defaultClass', radioExample && `radioExample`, booleanExample && 'defaultClass--modifier')}",
" // use undefined for values that shouldn't be set if false",
" // aria-hidden={booleanExample ? 'true' : undefined}",
" >",
" {/* use {children} for wrapper component templates */}",
" <>",
" {stringExample}",
" {children}",
" </>",
" </div>",
")",
"",
"// create a \"playground\" demo page that may set some defaults and allow story to access component controls",
"export const Playground = ComponentTemplateName.bind({})",
"Playground.args = {",
" stringExample: 'Default text',",
" booleanExample: false,",
" children: (",
" <>",
" <StoryTemplateName someProp=\"Use props from other stories\" />",
" </>",
" )",
" stringExample: 'Default text',",
" booleanExample: false",
" // children: (",
" // <>",
" // <StoryTemplateName {...StoryTemplateName.args} />",
" // </>",
" // )",
"}",
""
],
Expand Down
3 changes: 2 additions & 1 deletion docs/.storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
'@storybook/addon-essentials',
'@storybook/preset-scss',
'@whitespace/storybook-addon-html',
'storybook-addon-designs'
'storybook-addon-designs',
'storybook-color-picker'
]
}
10 changes: 10 additions & 0 deletions docs/.storybook/manager-head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<style>
{# storybook ui overrides #}
#color-picker {
max-width: 40vw;
}

.css-10x86lf-Colors {
width: 20ch !important;
}
</style>
16 changes: 15 additions & 1 deletion docs/.storybook/preview-head.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,26 @@
Helvetica Neue, sans-serif;
color: var(--color-fg-default);
background-color: var(--color-canvas-default);
padding: 0;
height: 100vh;
}

.theme-wrap {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
height: 100vh;
}

.theme-wrap .story-wrap {
padding: 1rem;
height: unset;
}

.sb-main-padded .theme-wrap {
margin: -1rem;
}

.sb-main-padded div:not(.theme-wrap) > [data-dark-theme] {
margin: -1rem;
padding: 1rem;
}
</style>
1 change: 1 addition & 0 deletions docs/.storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import '../../src/docs.scss'
import '../../src/index.scss'
import '../../src/base/index.scss'
import '../src/stories/helpers/storybook-styles.scss'
import renderToHTML from '../src/stories/helpers/code-snippet-html-helper'

const customViewports = {
Expand Down
5 changes: 3 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"develop": "ln -sf ../dist . && gatsby develop -H 0.0.0.0",
"build-content": "gatsby build --prefix-paths",
"build": "./script/now-build.sh && ./script/build-storybook.sh",
"storybook": "start-storybook -p 6006",
"storybook": "NODE_ENV=test start-storybook -p 6006",
"build-storybook": "./script/build-storybook.sh"
},
"dependencies": {
Expand Down Expand Up @@ -58,6 +58,7 @@
"@storybook/react": "6.3.12",
"@whitespace/storybook-addon-html": "^5.0.0",
"babel-loader": "^8.2.3",
"storybook-addon-designs": "6.2.0"
"storybook-addon-designs": "6.2.0",
"storybook-color-picker": "2.1.4"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default {
options: [0, 1, 2], // iterator
mapping: ['', 'ActionList-content--sizeMedium', 'ActionList-content--sizeLarge'], // values
control: {
type: 'select',
type: 'inline-radio',
labels: ['default', 'medium', 'large']
},
description: 'small (default), medium, large',
Expand Down
160 changes: 151 additions & 9 deletions docs/src/stories/components/Button/Button.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,173 @@ export default {
design: {
type: 'figma',
url: 'https://www.figma.com/file/GCvY3Qv8czRgZgvl1dG6lp/Primer-Web?node-id=4371%3A7128'
}
},
layout: 'padded'
},

excludeStories: ['ButtonTemplate'],
argTypes: {
variant: {
options: [0, 1, 2, 3], // iterator
mapping: [null, 'btn-primary', 'btn-outline', 'btn-danger'], // values
options: [0, 1, 2, 3, 4, 5, 6, 7], // iterator
mapping: [
null,
'btn-primary',
'btn-outline',
'btn-danger',
'btn-link',
'btn-invisible',
'btn-with-count',
'btn-octicon'
], // values
control: {
type: 'select',
labels: ['default', 'primary', 'outline', 'danger']
labels: ['default', 'primary', 'outline', 'danger', 'link', 'invisible', 'close', 'with-count', 'icon-only']
},
defaultValue: ''
table: {
category: 'CSS'
}
},
size: {
options: [0, 1, 2], // iterator
mapping: [null, 'btn-sm', 'btn-large'], // values
control: {
type: 'select',
labels: ['default', 'small', 'large']
},
table: {
category: 'CSS'
}
},
label: {
defaultValue: 'Button',
type: 'string',
name: 'label',
description: 'string'
description: 'string',
table: {
category: 'HTML'
}
},
disabled: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'Interactive'
}
},
fullWidth: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
closeBtn: {
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
leadingVisual: {
name: 'leadingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
trailingVisual: {
name: 'trailingVisual',
type: 'string',
description: 'Paste [Octicon](https://primer.style/octicons/) in control field',
table: {
category: 'HTML'
}
},
trailingAction: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
selected: {
defaultValue: false,
control: {type: 'boolean'},
table: {
category: 'CSS'
}
},
focusElement: {
control: {type: 'boolean'},
description: 'set focus on one element',
table: {
category: 'Interactive'
}
},
focusAllElements: {
control: {type: 'boolean'},
description: 'set focus on all elements for viewing in all themes',
table: {
category: 'Interactive'
}
}
}
}

const Template = ({label, variant}) => (
const focusMethod = function getFocus() {
// find the focusable element
var button = document.getElementsByTagName('button')[0]
// set focus on element
button.focus()
}

export const ButtonTemplate = ({
label,
variant,
disabled,
size,
fullWidth,
leadingVisual,
trailingVisual,
trailingAction,
selected,
closeBtn,
focusElement,
focusAllElements
}) => (
<>
<button className={clsx('btn', variant && `${variant}`)}>{label}</button>
<button
disabled={disabled}
className={clsx(
'btn',
variant && `${variant}`,
size && `${size}`,
fullWidth && 'btn-block',
closeBtn && 'close-button',
focusAllElements && 'focus'
)}
aria-selected={selected}
>
{leadingVisual && <span className="" dangerouslySetInnerHTML={{__html: leadingVisual}} />}
<span>{label}</span>
{trailingVisual && <span className="" dangerouslySetInnerHTML={{__html: trailingVisual}} />}
{trailingAction && <span class="dropdown-caret"></span>}
{closeBtn && (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
<path
fill-rule="evenodd"
d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"
></path>
</svg>
)}
</button>
{focusElement && focusMethod()}
</>
)

export const Button = Template.bind({})
export const Playground = ButtonTemplate.bind({})
Playground.args = {
closeBtn: false,
focusElement: false,
focusAllElements: false
}
Loading

0 comments on commit f824581

Please sign in to comment.