-
Notifications
You must be signed in to change notification settings - Fork 1.3k
WIP: Button/Link API exploration #1874
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
Closed
Closed
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
9ebd6cd
begin button api refactor
langermank f15a0ac
setup button playground
langermank 14e9185
more config
langermank 1c67f02
stash meeting notes
langermank d148ec0
WIP
langermank 6cc2f68
slight refactor to handle trailingAction locked
langermank 3d88221
button group
langermank b0dba37
cleanup
langermank 479b49d
example sheet for review
langermank 1943667
most giant story of all time
langermank 871167c
lg button height, segment control discussion
langermank bf8efe2
play with tokens
langermank 488e665
design refinements
langermank 155ae23
Merge branch 'main' of https://github.com/primer/css into button-api
langermank a021941
support tag variation for pvc
langermank f67a1c2
tokens
langermank d2308e2
update invisible style
langermank 2b1c7c8
Merge branch 'main' into button-api
jonrohan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| import React from 'react' | ||
| import clsx from 'clsx' | ||
|
|
||
| export default { | ||
| title: 'Explorations/Button', | ||
| parameters: { | ||
| // 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: ['Button--secondary', 'Button--primary', 'Button--invisible', 'Button--danger'], // values | ||
| control: { | ||
| type: 'inline-radio', | ||
| labels: ['secondary', 'primary', 'invisible', 'danger'] | ||
| }, | ||
| table: { | ||
| category: 'CSS' | ||
| }, | ||
| description: 'Controls button color', | ||
| defaultValue: 'Button--secondary' | ||
| }, | ||
| size: { | ||
| options: [0, 1, 2], // iterator | ||
| mapping: [null, 'Button--small', 'Button--large'], // values | ||
| control: { | ||
| type: 'inline-radio', | ||
| labels: ['default [32px]', 'small [28px]', 'large [40px]'] | ||
| }, | ||
| table: { | ||
| category: 'CSS' | ||
| }, | ||
| description: 'Controls button height', | ||
| defaultValue: 0 | ||
| }, | ||
| visualPosition: { | ||
| options: [0, 1], // iterator | ||
| mapping: [null, 'Button-content--visualFixed'], // values | ||
| control: { | ||
| type: 'inline-radio', | ||
| labels: ['default', 'fixed'] | ||
| }, | ||
| table: { | ||
| category: 'CSS' | ||
| }, | ||
| description: | ||
| '[Name TBD!] Controls where the leading or trailing visuals position themselves in a fullWidth button (lock to text label or button bounds)', | ||
| defaultValue: 'Button-content--visualFixed' | ||
| }, | ||
| label: { | ||
| defaultValue: 'Button', | ||
| type: 'string', | ||
| name: 'label', | ||
| description: 'Visible button label', | ||
| table: { | ||
| category: 'Slot' | ||
| } | ||
| }, | ||
| ariaLabel: { | ||
| defaultValue: '', | ||
| type: 'string', | ||
| name: 'ariaLabel', | ||
| description: 'Hidden button label (in addition to visible label). Not required in all cases.', | ||
| table: { | ||
| category: 'Slot' | ||
| } | ||
| }, | ||
| disabled: { | ||
| defaultValue: false, | ||
| control: {type: 'boolean'}, | ||
| table: { | ||
| category: 'State' | ||
| } | ||
| }, | ||
| fullWidth: { | ||
| defaultValue: false, | ||
| control: {type: 'boolean'}, | ||
| description: 'Allow button to stretch and fill container', | ||
| table: { | ||
| category: 'CSS' | ||
| } | ||
| }, | ||
| leadingVisual: { | ||
| name: 'leadingVisual', | ||
| control: {type: 'boolean'}, | ||
| description: 'Slot for SVG icon or emoji (boolean only for testing purposes)', | ||
| defaultValue: false, | ||
| table: { | ||
| category: 'Slot' | ||
| } | ||
| }, | ||
| trailingVisual: { | ||
| name: 'trailingVisual', | ||
| control: {type: 'boolean'}, | ||
| description: 'Slot for SVG icon or emoji (boolean only for testing purposes)', | ||
| table: { | ||
| category: 'Slot' | ||
| }, | ||
| defaultValue: false | ||
| }, | ||
| trailingAction: { | ||
| defaultValue: false, | ||
| control: {type: 'boolean'}, | ||
| description: | ||
| 'Slot for SVG icon that indicates an action. Primarily used by other Primer components, like a DropdownMenu or overlay trigger (boolean only for testing purposes)', | ||
| table: { | ||
| category: 'Slot' | ||
| } | ||
| }, | ||
| pressed: { | ||
| defaultValue: false, | ||
| control: {type: 'boolean'}, | ||
| table: { | ||
| category: 'State' | ||
| } | ||
| }, | ||
| focusElement: { | ||
| control: {type: 'boolean'}, | ||
| description: 'set focus on one element', | ||
| table: { | ||
| category: 'State' | ||
| } | ||
| }, | ||
| active: { | ||
| control: {type: 'boolean'}, | ||
| description: 'set button to active state', | ||
| table: { | ||
| category: 'State' | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const focusMethod = function getFocus() { | ||
| // find the focusable element | ||
| var button = document.getElementsByTagName('button')[0] | ||
| // set focus on element | ||
| button.focus() | ||
| } | ||
|
|
||
| const star = ( | ||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"> | ||
| <path | ||
| fill-rule="evenodd" | ||
| d="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25z" | ||
| ></path> | ||
| </svg> | ||
| ) | ||
|
|
||
| const caret = ( | ||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"> | ||
| <path d="M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z"></path> | ||
| </svg> | ||
| ) | ||
|
|
||
| export const ButtonTemplate = ({ | ||
| label, | ||
| variant, | ||
| disabled, | ||
| size, | ||
| fullWidth, | ||
| leadingVisual, | ||
| trailingVisual, | ||
| trailingAction, | ||
| pressed, | ||
| focusElement, | ||
| active, | ||
| visualPosition, | ||
| className, | ||
| ariaLabel | ||
| }) => ( | ||
| <> | ||
| <button | ||
| disabled={disabled} | ||
| className={clsx( | ||
| 'Button', | ||
| className && `${className}`, | ||
| variant && `${variant}`, | ||
| size && `${size}`, | ||
| fullWidth && 'Button--fullWidth', | ||
| active && 'Button--active' | ||
| )} | ||
| aria-pressed={pressed ? pressed : undefined} | ||
| aria-label={ariaLabel ? ariaLabel : undefined} | ||
| > | ||
| {/* {leadingVisual && <span className="" dangerouslySetInnerHTML={{__html: leadingVisual}} />} */} | ||
| <span className={clsx(visualPosition && `${visualPosition}`, 'Button-content')}> | ||
| {leadingVisual && <span className="Button-visual Button-leadingVisual">{star}</span>} | ||
| <span className="Button-label">{label}</span> | ||
| {trailingVisual && <span className="Button-visual Button-trailingVisual">{star}</span>} | ||
| </span> | ||
| {trailingAction && <span className="Button-visual Button-trailingAction">{caret}</span>} | ||
| </button> | ||
| {focusElement && focusMethod()} | ||
| </> | ||
| ) | ||
|
|
||
| export const Playground = ButtonTemplate.bind({}) | ||
| Playground.args = { | ||
| focusElement: false, | ||
| active: false, | ||
| variant: 'Button--secondary', | ||
| leadingVisual: false, | ||
| trailingAction: false, | ||
| trailingVisual: false | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import React from 'react' | ||
| import clsx from 'clsx' | ||
| import {ButtonTemplate} from './Button.stories' | ||
| import {IconButtonTemplate} from './IconButton.stories' | ||
|
|
||
| export default { | ||
| title: 'Explorations/ButtonGroup', | ||
| excludeStories: ['ButtonGroupTemplate'], | ||
| layout: 'padded', | ||
| argTypes: {} | ||
| } | ||
|
|
||
| // build every component case here in the template (private api) | ||
| export const ButtonGroupTemplate = ({}) => ( | ||
| <div className="ButtonGroup"> | ||
| <ButtonTemplate label="Button 1" variant="Button--secondary" className="ButtonGroup-item" /> | ||
| <ButtonTemplate label="Button 2" variant="Button--secondary" className="ButtonGroup-item" pressed /> | ||
| <ButtonTemplate label="Button 3" variant="Button--secondary" className="ButtonGroup-item" /> | ||
| <IconButtonTemplate ariaLabel="label" visual variant="Button--secondary" className="ButtonGroup-item" /> | ||
| </div> | ||
| ) | ||
|
|
||
| export const Playground = ButtonGroupTemplate.bind({}) | ||
| Playground.args = {} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
@pksjce I made some grid and markup adjustments to Button to be able to support "locked" icon positioning. This basically takes
trailingActionout of the grid, as we've decided it will always be locked right even if other icons are not locked to the container. I think its too early in the design process to do a thorough code review but if you have any reservations here let me know!I always try and keep as many divs/spans out of a component as I can.. but I couldn't find a nicer way to both lock one icon to the right while centering the rest of the button contents.