Skip to content

Commit

Permalink
Merge pull request #1443 from dhis2/segmented-control-design
Browse files Browse the repository at this point in the history
fix(segmented-control): adjust design and accessibility
  • Loading branch information
cooper-joe authored Jan 11, 2024
2 parents 21cd2b2 + e20c405 commit 53b9f83
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 52 deletions.
94 changes: 42 additions & 52 deletions components/segmented-control/src/segmented-control.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { colors, spacers, theme } from '@dhis2/ui-constants'
import { colors, elevations, spacers, theme } from '@dhis2/ui-constants'
import cx from 'classnames'
import { PropTypes } from 'prop-types'
import React from 'react'
Expand All @@ -18,7 +18,12 @@ import { SegmentedControl } from '@dhis2/ui'
```
*/

export const SegmentedControl = ({ options, selected, onChange }) => {
export const SegmentedControl = ({
options,
selected,
onChange,
ariaLabel,
}) => {
if (!options.map(({ value }) => value).includes(selected)) {
const message =
`There is no option with the value: "${selected}". ` +
Expand All @@ -28,44 +33,47 @@ export const SegmentedControl = ({ options, selected, onChange }) => {
}

return (
<div className="segmented-control">
<ul className="segmented-control" aria-label={ariaLabel}>
{options.map(({ label, value, disabled }) => (
<button
key={label}
type="button"
className={cx('segment', {
selected: value === selected,
disabled,
})}
onClick={(e) => onChange({ value }, e)}
disabled={disabled}
>
{label}
</button>
<li key="label">
<button
type="button"
className={cx('segment', {
selected: value === selected,
disabled,
})}
onClick={(e) => onChange({ value }, e)}
disabled={disabled}
>
{label}
</button>
</li>
))}

<style jsx>{`
.segmented-control {
/* create a stacking context for the children */
position: relative;
z-index: 0;
all: unset;
list-style: none;
display: inline-flex;
align-items: stretch;
background: ${colors.grey300};
border-radius: 5px;
padding: 2px;
}
.segment {
all: unset;
box-sizing: border-box;
display: inline-block;
position: relative;
cursor: pointer;
font-size: 14px;
text-align: center;
border: 1px solid ${colors.grey400};
border-right-width: 0;
background: ${colors.grey050};
color: ${colors.grey600};
border-radius: 5px;
background: transparent;
color: ${colors.grey700};
min-width: 72px;
max-width: 320px;
padding: ${spacers.dp8} ${spacers.dp16};
height: 100%;
padding: 6px ${spacers.dp12};
}
.segment:focus {
Expand All @@ -77,44 +85,24 @@ export const SegmentedControl = ({ options, selected, onChange }) => {
outline: none;
}
.segment:not(.selected):hover,
.segment:not(.selected):focus {
background: ${colors.grey100};
color: ${colors.grey700};
}
.segment:first-of-type {
border-radius: 3px 0 0 3px;
}
.segment:last-of-type {
border-right-width: 1px;
border-radius: 0 3px 3px 0;
.segment:not(.selected):not(.disabled):hover {
background: ${colors.grey400};
color: ${colors.grey900};
}
.segment.selected {
cursor: default;
font-weight: 600;
border: 1px solid ${colors.teal800};
background: ${colors.teal600};
color: white;
}
.segment.selected:not(:last-of-type) {
z-index: 1;
margin-right: -1px;
}
.segment.selected:focus {
background: ${colors.teal700};
box-shadow: ${elevations.e100};
background: ${colors.white};
color: ${colors.grey900};
}
.segment.disabled {
cursor: not-allowed;
opacity: 0.5;
}
`}</style>
</div>
</ul>
)
}

Expand All @@ -131,4 +119,6 @@ SegmentedControl.propTypes = {
selected: PropTypes.string.isRequired,
/** Called with the signature `({ value: string }, event)` */
onChange: PropTypes.func.isRequired,
/** Used to provide an accessible label to a segmented control without a visible label */
ariaLabel: PropTypes.string,
}
14 changes: 14 additions & 0 deletions components/segmented-control/src/segmented-control.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export default {
],
selected: 'DOG',
onChange: logger,
ariaLabel: 'Segmented control label',
},
}

Expand All @@ -33,3 +34,16 @@ DisabledOption.args = {
],
selected: 'THREE',
}

export const LongLabels = Template.bind({})
LongLabels.args = {
options: [
{
label: 'Program configuration, security, and distribution',
value: 'PROGRAM',
},
{ label: 'Two', value: 'TWO' },
{ label: 'Three', value: 'THREE' },
],
selected: 'PROGRAM',
}

0 comments on commit 53b9f83

Please sign in to comment.