Skip to content
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

SegmentedControl #2083

Merged
merged 44 commits into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
48b39d5
Add SegmentedControl
simurai May 18, 2022
c25185f
Fix dividers
simurai May 18, 2022
af466be
Follow Figma spec
simurai May 19, 2022
ec54b85
Create famous-moles-bow.md
simurai May 19, 2022
d2e7738
Rename item to button
simurai May 26, 2022
9d052fb
Rename visual to icon
simurai May 26, 2022
f99cab2
Rename text to label
simurai May 26, 2022
746a284
Use new size and typography tokens
simurai May 26, 2022
20f4ca5
Support IconOnly
simurai May 30, 2022
539e249
Add icon only when narrow variant
simurai May 30, 2022
2828547
Increase touch target
simurai May 31, 2022
d387489
Add disabled state
simurai May 31, 2022
856d2af
Avoid size increase when item becomes bold
simurai May 31, 2022
065151c
Add loading state
simurai May 31, 2022
4089e1a
Lint
simurai May 31, 2022
f2057fa
Add more templates
simurai Jun 1, 2022
5a522c9
Use Primitives
simurai Jun 1, 2022
f9e5a20
Merge branch 'main' into segmented-control
simurai Jun 1, 2022
2b6206a
Lint
simurai Jun 1, 2022
6db93a2
Use variable
simurai Jun 1, 2022
829a386
yarn add @primer/[email protected]
simurai Jun 4, 2022
c004088
Update Primitives
simurai Jun 4, 2022
49c6357
Address accessibility feedback
simurai Jun 4, 2022
46e545b
Remove loading state
simurai Jun 4, 2022
3831e4b
Rename to leadingVisual
simurai Jun 4, 2022
4ee0844
Rename label to text
simurai Jun 4, 2022
abf3153
Remove shadow
simurai Jun 4, 2022
a90d72b
Change to inset
simurai Jun 4, 2022
2994f39
Merge branch 'main' into segmented-control
simurai Jun 4, 2022
3d98ee8
Update transitions
simurai Jun 10, 2022
92e53f1
Use SegmentedControl-button--selected class instead of aria
simurai Jun 10, 2022
912039f
Remove disabled prop
simurai Jun 10, 2022
fb6807f
Keep $width-md for now
simurai Jun 10, 2022
2af922d
Add min-width
simurai Jun 10, 2022
5d1517e
Fix divider for selected item
simurai Jun 10, 2022
660aa5b
Add inset hover style
simurai Jul 20, 2022
c7077df
Keep dividers
simurai Jul 20, 2022
e3baab2
Disable hover/active state when selected
simurai Jul 20, 2022
a39eaaf
Fix a few more things
simurai Jul 20, 2022
be4188c
Lint
simurai Jul 20, 2022
70b7019
Merge branch 'main' into segmented-control
simurai Jul 20, 2022
147c07c
yarn add @primer/[email protected]
simurai Jul 20, 2022
b426825
yarn add @primer/primitives@^7.9.0
simurai Jul 21, 2022
9b2bf73
Merge branch 'main' into segmented-control
simurai Jul 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/famous-moles-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@primer/css": patch
---

Add `SegmentedControl` component
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from 'react'
import {SegmentedControlButtonTemplate} from './SegmentedControlButton.stories' // import stories for component compositions

export default {
title: 'Components/SegmentedControl',
parameters: {
layout: 'padded'
},
excludeStories: ['BasicTemplate', 'IconsAndLabelsTemplate', 'IconsOnlyTemplate'],
controls: { expanded: true },
argTypes: {
ariaLabel: {
type: 'string',
description: 'Aria label',
},
disabled: {
control: {type: 'boolean'},
description: 'disabled',
},
fullWidth: {
control: {type: 'boolean'},
description: 'full width',
},
iconOnlyWhenNarrow: {
control: {type: 'boolean'},
description: 'icon only when narrow',
},
}
}

function classNames(disabled, fullWidth, iconOnlyWhenNarrow) {
const classNames = ['SegmentedControl'];

if (disabled) {
classNames.push("SegmentedControl--disabled")
}
if (fullWidth) {
classNames.push("SegmentedControl--fullWidth")
}
if (iconOnlyWhenNarrow) {
classNames.push("SegmentedControl--iconOnly-whenNarrow")
}

return classNames.join(' ')
}

export const BasicTemplate = ({disabled, fullWidth, ariaLabel}) => (
<>
<segmented-control role="group" aria-label={ariaLabel} class={classNames(disabled, fullWidth)}>
<SegmentedControlButtonTemplate label="Outline" ariaPressed />
<SegmentedControlButtonTemplate label="Write" />
<SegmentedControlButtonTemplate label="Preview" />
<SegmentedControlButtonTemplate label="Publish" />
</segmented-control>
</>
)

export const Basic = BasicTemplate.bind({})
Basic.args = {
ariaLabel: "Label",
disabled: false,
fullWidth: false,
iconOnlyWhenNarrow: false,
}

export const IconsAndLabelsTemplate = ({disabled, fullWidth, ariaLabel, iconOnlyWhenNarrow}) => (
<>
<segmented-control role="group" aria-label={ariaLabel} class={classNames(disabled, fullWidth, iconOnlyWhenNarrow)}>
<SegmentedControlButtonTemplate label="Outline" leadingIcon ariaPressed />
<SegmentedControlButtonTemplate label="Write" leadingIcon />
<SegmentedControlButtonTemplate label="Preview" leadingIcon />
<SegmentedControlButtonTemplate label="Publish" leadingIcon />
</segmented-control>
</>
)

export const IconsAndLabels = IconsAndLabelsTemplate.bind({})
IconsAndLabels.args = {
ariaLabel: "Label",
disabled: false,
fullWidth: false,
iconOnlyWhenNarrow: false,
}

export const IconsOnlyTemplate = ({disabled, fullWidth, ariaLabel, iconOnlyWhenNarrow}) => (
<>
<segmented-control role="group" aria-label={ariaLabel} class={classNames(disabled, fullWidth, iconOnlyWhenNarrow)}>
<SegmentedControlButtonTemplate label="Outline" leadingIcon iconOnly ariaPressed />
<SegmentedControlButtonTemplate label="Write" leadingIcon iconOnly />
<SegmentedControlButtonTemplate label="Preview" leadingIcon iconOnly />
<SegmentedControlButtonTemplate label="Publish" leadingIcon iconOnly />
</segmented-control>
</>
)

export const IconsOnly = IconsOnlyTemplate.bind({})
IconsOnly.args = {
ariaLabel: "Label",
disabled: false,
fullWidth: false,
iconOnlyWhenNarrow: false,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react'
import clsx from 'clsx'

export default {
title: 'Components/SegmentedControl/SegmentedControlButton',
excludeStories: ['SegmentedControlButtonTemplate'],
layout: 'padded',

argTypes: {
ariaPressed: {
control: {type: 'boolean'},
description: 'Currently selected item',
},
isLoading: {
control: {type: 'boolean'},
description: 'Pressed item is loading',
},
label: {
defaultValue: 'Item',
type: 'string',
name: 'label',
description: 'Button label',
},
leadingIcon: {
defaultValue: false,
control: {type: 'boolean'},
description: 'Has icon'
},
iconOnly: {
defaultValue: false,
control: {type: 'boolean'},
description: 'Show icon only',
},
}
}

// build every component case here in the template (private api)
export const SegmentedControlButtonTemplate = ({ariaPressed, isLoading, label, leadingIcon, iconOnly }) => (
<>
<button className={clsx(
'SegmentedControl-button',
iconOnly && `SegmentedControl-button--iconOnly`,
isLoading && `SegmentedControl-button--isLoading`,
)}
aria-pressed={ariaPressed}
aria-label={iconOnly && label}
>
{leadingIcon && (
<svg class="SegmentedControl-leadingIcon octicon" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.679 7.932c.412-.621 1.242-1.75 2.366-2.717C5.175 4.242 6.527 3.5 8 3.5c1.473 0 2.824.742 3.955 1.715 1.124.967 1.954 2.096 2.366 2.717a.119.119 0 010 .136c-.412.621-1.242 1.75-2.366 2.717C10.825 11.758 9.473 12.5 8 12.5c-1.473 0-2.824-.742-3.955-1.715C2.92 9.818 2.09 8.69 1.679 8.068a.119.119 0 010-.136zM8 2c-1.981 0-3.67.992-4.933 2.078C1.797 5.169.88 6.423.43 7.1a1.619 1.619 0 000 1.798c.45.678 1.367 1.932 2.637 3.024C4.329 13.008 6.019 14 8 14c1.981 0 3.67-.992 4.933-2.078 1.27-1.091 2.187-2.345 2.637-3.023a1.619 1.619 0 000-1.798c-.45-.678-1.367-1.932-2.637-3.023C11.671 2.992 9.981 2 8 2zm0 8a2 2 0 100-4 2 2 0 000 4z"></path></svg>
)}
{!iconOnly && (
<span class="SegmentedControl-label" data-content={label}>{label}</span>
)}
{isLoading && (
<svg style={{boxSizing: "content-box", color: "var(--color-icon-primary)"}} width="16" height="16" viewBox="0 0 16 16" fill="none" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke"></circle> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke"></path></svg>
)}
</button>
</>
)

// create a "playground" demo page that may set some defaults and allow story to access component controls
export const Playground = SegmentedControlButtonTemplate.bind({})
Playground.args = {
label: 'Preview',
leadingIcon: true,
ariaPressed: true,
isLoading: false,
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"storybook": "cd docs && yarn && yarn storybook"
},
"dependencies": {
"@primer/primitives": "^7.8.3"
"@primer/primitives": "0.0.0-20220531171341"
},
"devDependencies": {
"@changesets/changelog-github": "0.4.4",
Expand Down
1 change: 1 addition & 0 deletions src/core/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
@import '../links/index.scss';
@import '../navigation/index.scss';
@import '../pagination/index.scss';
@import '../segmented-control/index.scss';
@import '../tooltips/index.scss';
@import '../truncate/index.scss';
@import '../overlay/index.scss';
Expand Down
25 changes: 25 additions & 0 deletions src/segmented-control/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
bundle: "segmented-control"
generated: true
---

# Primer CSS: `segmented-control` bundle

## Usage

Primer CSS source files are written in [SCSS]. To include this Primer CSS module in your own build, ensure that your `node_modules` directory is listed in your Sass include paths, then import it with:

```scss
@import "@primer/css/segmented-control/index.scss";
```

## Build

The `@primer/css` npm package includes a standalone CSS build of this module in `dist/segmented-control.css`.

## License

[MIT](https://github.com/primer/css/blob/main/LICENSE) &copy; [GitHub](https://github.com/)


[scss]: https://sass-lang.com/documentation/syntax#scss
3 changes: 3 additions & 0 deletions src/segmented-control/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// support files
@import '../support/index.scss';
@import './segmented-control.scss';
Loading