From 1f0803e8fd7d788cbce89760fdee677c3935eb1f Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Sat, 23 Jul 2022 16:29:58 -0700 Subject: [PATCH 1/9] adds first draft of segmented control guidelines --- content/components/segmented-control.mdx | 284 ++++++++++++++++++++++ src/@primer/gatsby-theme-doctocat/nav.yml | 6 +- 2 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 content/components/segmented-control.mdx diff --git a/content/components/segmented-control.mdx b/content/components/segmented-control.mdx new file mode 100644 index 000000000..9689977c4 --- /dev/null +++ b/content/components/segmented-control.mdx @@ -0,0 +1,284 @@ +--- +title: Segmented control +--- + +import {Box, Text} from '@primer/components' + + + A segmented control is used to pick one choice from a linear set of closely related choices, and immediately apply + that selection. + + +## Anatomy + +![A diagram of a segmented control with three buttons. The labeled parts of the segmented control are: the selected third button, the icon in the second button, and the text label in the second button.](https://user-images.githubusercontent.com/2313998/180623801-08eb59b2-7609-4017-a391-4f6b5c4c68ac.png) + +## Content + +A segmented control should have 2–5 choices with text labels, or up to 6 icon-only buttons. Too many choices can be difficult to parse and take up too much horizontal space. + + + + + Use a segmented control for picking from 5 (6 for icon-only buttons) or fewer options. + + + + Don't use a segmented control for more than 5 options. + + + +Each choice should be a static value. None of the choices may be a dropdown button. + + + + + + Use a segmented control for selecting from a list of static values. You may use an auxiliary dropdown adjacent to + the segmented control. + + + + + Don't use a segmented control with a choice that is a dropdown. + + + +If there are more than 5 choices, use another choice selection pattern such as a group of radio inputs or a dropdown menu. + +### Button icons + + + +Icons may be used to make choices easier to understand. + +Use icons without a visible text label sparingly, and only with icons that are easily understood by an average GitHub user. When a segment has an icon without a visible text label, the text label should be shown in a tooltip. + + + + + Use icons without a visible label when the icon's meaning is obvious. + + + + Don't use obscure icons without a visible label. + + + +Icons should not be used to communicate state + + + + + Use icons to as a visual cue to communicate what the choice does. + + + + Change or add icons to indicate whether the choice is selected. + + + +Be consistent with the way visual cues are used in each button of the segmented control. Use either all icons, all text labels, or all text labels with icons. + + + + + Keep the visual cues in each button consistent. + + + + Don't mix visual cues between buttons. + + + +### Button label text + +Segmented control button labels should be nouns or noun phrases that succinctly describe the choice. Button labels may not wrap to multiple lines. + + + + + Phrase choice labels as nouns or noun phrases with as few characters as possible. + + + + Phrase choice labels as an action or with unnecessarily long strings of text. + + + +### Contextual information + + + +See the [layout](#layout) section for ways to compose a segmented control with a label. + +### Label + +Segmented controls must have a text label, even if the label is only accessible to screen readers. However, a visible text label is preferred. + +### Caption + +An optional caption may be used to provide additional context to help users make a selection or explain how what effect the selection will have. Caption text should be as short as possible. + +## Interaction + +Selections are mutually exclusive. Once a selection has been made, it can only be deselected by making a new selection. + +A segmented control does not require a "Save" button to apply the selection. When a choice is selected, the selection immediately affects an object, state, or view. + +## Layout + +### Composed with label and caption + +#### Single-column + + + +A single-column layout is the same way form controls (for example, text inputs) are layed out. The single-column layout is useful for preserving horizontal space. + +#### Two-column + + + + +A two-column layout can be used to: + +- Align the control with adjacent elements +- Conserve vertical space +- Group related controls in a way that is easy to scan + +### Adapting to narrow areas + +There are cases where a segmented control needs to be placed in a spot that is too narrow to accommodate all of its options. In these cases, the control can be adapted to fit in the narrow area without sacrificing usability. + + + + + + Replace the segmented control with an action menu or use icons that are easily understood without text labels. + + + + + Wrap the buttons to multiple lines, use an overflow button, or remove buttons + + + +#### Convert to an action menu + + +This works well because option text may still be viewed when the dropdown menu is opened + +#### Only show icons + + +This isn’t as strong of a solution because option text will be hidden in a hover tooltip, and not all options have an icon +that works without text + +### Fill available width + + +A segmented control can be stretched to fill the available width. + +## Additional accessibility considerations + +### Keyboard navigation + +!πŸŽ₯[Keyboard navigation video]() + +A segmented control is treated like a [toolbar](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/toolbar_role), not a [radio group](https://developer.mozilla.org/en-US/docs/web/accessibility/aria/roles/radiogroup_role). + +#### `Tab` + +The `Tab` key while focused on the previous focusable element moves focus into the segmented control. + +When focus is moved into the segmented control, focus should go to the button for whichever choice is selected. + +Pressing `Tab` while one of the segmented control buttons is focused will move focus to the next focusable element outside of the segmented control. + +#### `Enter` or `Space` + +Pressing `Enter` or `Space` while focused on a deselected button selects that button. This is the default behavior for buttons. + +If the focused button is already selected, pressing `Enter` or `Space` should not deselect the button. + +#### `Left Arrow` or `Right Arrow` + +The `Left Arrow` key moves focus to the previous button. If the first button is focused, pressing `Left Arrow` will not move the focus. + +The `Right Arrow` key moves focus to the next button. If the last button is focused, pressing `Right Arrow` will not move the focus. + +### Touch targets + + + +Ensure segmented control buttons have a large enough touch target size. The buttons should respond to hovers, clicks, and taps anywhere in the touch target area, even if it isn't directly on the control. diff --git a/src/@primer/gatsby-theme-doctocat/nav.yml b/src/@primer/gatsby-theme-doctocat/nav.yml index 014521368..630c0d39a 100644 --- a/src/@primer/gatsby-theme-doctocat/nav.yml +++ b/src/@primer/gatsby-theme-doctocat/nav.yml @@ -25,7 +25,7 @@ - title: Focus management url: /accessibility/focus-management - title: Headings - url: /accessibility/headings + url: /accessibility/headings - title: Links url: /accessibility/links - title: Semantic HTML @@ -46,7 +46,7 @@ - title: Messaging url: /ui-patterns/messaging - title: Progressive disclosure - url: /ui-patterns/progressive-disclosure + url: /ui-patterns/progressive-disclosure - title: Saving url: /ui-patterns/saving - title: Components @@ -56,6 +56,8 @@ url: /components/action-list - title: Autocomplete url: /components/autocomplete + - title: Segmented control + url: /components/segmented-control - title: Toggle switch url: /components/toggle-switch - title: Tokens From f5871da5574029b3ef82d02f538f85ef4706eb25 Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Sat, 23 Jul 2022 16:31:02 -0700 Subject: [PATCH 2/9] adds custom video player --- .../gatsby-theme-doctocat/mdx-components.js | 3 + src/CustomVideoPlayer.tsx | 55 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/@primer/gatsby-theme-doctocat/mdx-components.js create mode 100644 src/CustomVideoPlayer.tsx diff --git a/src/@primer/gatsby-theme-doctocat/mdx-components.js b/src/@primer/gatsby-theme-doctocat/mdx-components.js new file mode 100644 index 000000000..f62d5f739 --- /dev/null +++ b/src/@primer/gatsby-theme-doctocat/mdx-components.js @@ -0,0 +1,3 @@ +import CustomVideoPlayer from '../../CustomVideoPlayer' + +export default {CustomVideoPlayer} diff --git a/src/CustomVideoPlayer.tsx b/src/CustomVideoPlayer.tsx new file mode 100644 index 000000000..52e53b33f --- /dev/null +++ b/src/CustomVideoPlayer.tsx @@ -0,0 +1,55 @@ +import React from 'react' +import {Box} from '@primer/components' +import {ColumnsIcon, PlayIcon} from '@primer/octicons-react' + +const CustomVideoPlayer = (props: React.HTMLProps) => { + const videoElement = React.useRef(null) + const [isPlaying, setIsPlaying] = React.useState(props.autoPlay) + + const playVideo = () => { + videoElement.current.play() + setIsPlaying(true) + } + + const pauseVideo = () => { + videoElement.current.pause() + setIsPlaying(false) + } + + return ( + + {/* component users would be able to pass their own children */} + {/* eslint-disable-next-line jsx-a11y/media-has-caption */} + + ) +} + +export default CustomVideoPlayer From 7405643a02d6d1d900106329734d311db1416e7e Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Sat, 23 Jul 2022 18:35:48 -0700 Subject: [PATCH 3/9] formats segmented control guidelines --- content/components/segmented-control.mdx | 302 +++++++++++++++++------ package.json | 2 +- src/CustomVideoPlayer.tsx | 17 +- yarn.lock | 10 +- 4 files changed, 241 insertions(+), 90 deletions(-) diff --git a/content/components/segmented-control.mdx b/content/components/segmented-control.mdx index 9689977c4..74f975736 100644 --- a/content/components/segmented-control.mdx +++ b/content/components/segmented-control.mdx @@ -9,13 +9,36 @@ import {Box, Text} from '@primer/components' that selection. + + ## Anatomy ![A diagram of a segmented control with three buttons. The labeled parts of the segmented control are: the selected third button, the icon in the second button, and the text label in the second button.](https://user-images.githubusercontent.com/2313998/180623801-08eb59b2-7609-4017-a391-4f6b5c4c68ac.png) ## Content -A segmented control should have 2–5 choices with text labels, or up to 6 icon-only buttons. Too many choices can be difficult to parse and take up too much horizontal space. +### Buttons + +A segmented control should have 2–5 choices with text labels, or up to 6 icon-only buttons. Too many choices can be difficult to parse and take up too much horizontal space. If there are more than 5 choices, use another choice selection pattern such as a group of radio inputs or a dropdown menu. @@ -34,8 +57,6 @@ A segmented control should have 2–5 choices with text labels, or up to 6 icon- -Each choice should be a static value. None of the choices may be a dropdown button. - -If there are more than 5 choices, use another choice selection pattern such as a group of radio inputs or a dropdown menu. - ### Button icons - + + + An icon can be rendered in a segmented control button as a visual cue to help users understand the choice that + button represents. + + + -Icons may be used to make choices easier to understand. +#### Effective visual cues -Use icons without a visible text label sparingly, and only with icons that are easily understood by an average GitHub user. When a segment has an icon without a visible text label, the text label should be shown in a tooltip. +Be consistent with the way visual cues are used in each button of the segmented control. Use either all icons, all text labels, or all text labels with icons. + +Do not change icons to communicate state. - Use icons without a visible label when the icon's meaning is obvious. + Use icons to as a visual cue to communicate what the choice does. - Don't use obscure icons without a visible label. + Change or add icons to indicate whether the choice is selected. -Icons should not be used to communicate state - - Use icons to as a visual cue to communicate what the choice does. + Keep the visual cues in each button consistent. - Change or add icons to indicate whether the choice is selected. + Don't mix visual cues between buttons. -Be consistent with the way visual cues are used in each button of the segmented control. Use either all icons, all text labels, or all text labels with icons. +#### Icon-only buttons + +Use icons without a visible text label sparingly, and only with icons that are easily understood by an average GitHub user. When a segment has an icon without a visible text label, the text label should be shown in a tooltip. - Keep the visual cues in each button consistent. + Use icons without a visible label when the icon's meaning is obvious. - Don't mix visual cues between buttons. + Don't use obscure icons without a visible label. @@ -147,21 +180,40 @@ Segmented control button labels should be nouns or noun phrases that succinctly ### Contextual information - + + + + Label + + + Segmented controls must have a text label, even if the label is only accessible to screen readers. However, a + visible text label is preferred. + + + Caption + + + An optional caption may be used to provide additional context to help users make a selection or explain how what + effect the selection will have. Caption text should be as short as possible. + + + + See the [layout](#layout) section for ways to compose a segmented control with a label. -### Label - -Segmented controls must have a text label, even if the label is only accessible to screen readers. However, a visible text label is preferred. - -### Caption - -An optional caption may be used to provide additional context to help users make a selection or explain how what effect the selection will have. Caption text should be as short as possible. - ## Interaction Selections are mutually exclusive. Once a selection has been made, it can only be deselected by making a new selection. @@ -170,7 +222,7 @@ A segmented control does not require a "Save" button to apply the selection. Whe ## Layout -### Composed with label and caption +### Composing the control with a label and caption #### Single-column @@ -183,14 +235,18 @@ A single-column layout is the same way form controls (for example, text inputs) #### Two-column - - + + + + A two-column layout can be used to: @@ -198,10 +254,85 @@ A two-column layout can be used to: - Conserve vertical space - Group related controls in a way that is easy to scan +### Fill available width + + + + A segmented control's width can stretch each button evenly to fill the width of the control's parent. This option is + intended to make the segmented control easier to adapt into different layouts. + + + + ### Adapting to narrow areas There are cases where a segmented control needs to be placed in a spot that is too narrow to accommodate all of its options. In these cases, the control can be adapted to fit in the narrow area without sacrificing usability. + +
+ + Convert to an action menu + + + Swapping out the segmented control for an action menu is especially helpful when: + +
  • The icons are cannot be understood without visible text labels
  • +
  • The control is stil too wide when text labels are hidden
  • +
    +
    +
    + +
    + + +
    + + Only show icons + + + If your segmented control uses icons that can be understood without a visible text label, then you can hide the + text labels and rely only on icons. The text from the hidden label will still be visible in a tooltip. + +
    + +
    + -#### Convert to an action menu - - -This works well because option text may still be viewed when the dropdown menu is opened - -#### Only show icons - - -This isn’t as strong of a solution because option text will be hidden in a hover tooltip, and not all options have an icon -that works without text - -### Fill available width - - -A segmented control can be stretched to fill the available width. - -## Additional accessibility considerations +## Accessibility ### Keyboard navigation -!πŸŽ₯[Keyboard navigation video]() + +
    A segmented control is treated like a [toolbar](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/toolbar_role), not a [radio group](https://developer.mozilla.org/en-US/docs/web/accessibility/aria/roles/radiogroup_role). +
    + #### `Tab` The `Tab` key while focused on the previous focusable element moves focus into the segmented control. @@ -274,11 +391,36 @@ The `Left Arrow` key moves focus to the previous button. If the first button is The `Right Arrow` key moves focus to the next button. If the last button is focused, pressing `Right Arrow` will not move the focus. -### Touch targets +
    - +
    -Ensure segmented control buttons have a large enough touch target size. The buttons should respond to hovers, clicks, and taps anywhere in the touch target area, even if it isn't directly on the control. + + + +
    + +### Touch targets + + + +Ensure segmented control buttons have a large enough touch target size. The buttons should respond to hovers, clicks, and taps anywhere in the touch target area, even if it isn't directly on the control. + + diff --git a/package.json b/package.json index 07fd6ffd4..0703184c4 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@primer/gatsby-theme-doctocat": "^3.1.1", - "@primer/octicons-react": "^11.0.0", + "@primer/octicons-react": "^17.3.0", "eslint": "5.8.0", "eslint-plugin-github": "1.6.0", "gatsby": "^2.32.13", diff --git a/src/CustomVideoPlayer.tsx b/src/CustomVideoPlayer.tsx index 52e53b33f..9e664d159 100644 --- a/src/CustomVideoPlayer.tsx +++ b/src/CustomVideoPlayer.tsx @@ -2,9 +2,9 @@ import React from 'react' import {Box} from '@primer/components' import {ColumnsIcon, PlayIcon} from '@primer/octicons-react' -const CustomVideoPlayer = (props: React.HTMLProps) => { +const CustomVideoPlayer = ({autoPlay, controls, ...rest}: React.HTMLProps) => { const videoElement = React.useRef(null) - const [isPlaying, setIsPlaying] = React.useState(props.autoPlay) + const [isPlaying, setIsPlaying] = React.useState(autoPlay) const playVideo = () => { videoElement.current.play() @@ -18,17 +18,26 @@ const CustomVideoPlayer = (props: React.HTMLProps) => { return ( video': { + maxWidth: '100%' + } }} > {/* component users would be able to pass their own children */} {/* eslint-disable-next-line jsx-a11y/media-has-caption */} -