-
Notifications
You must be signed in to change notification settings - Fork 645
Add ToggleSwitch component #1933
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
Merged
Merged
Changes from 31 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
81d5b63
adds Switch component and stories
mperrotti f02595e
adds tests and more ARIA markup
mperrotti 872bdb4
adds component docs and fixes transition
mperrotti 0316ed3
adds changeset
mperrotti 27dccc7
Merge branch 'main' into mp/switch-component
mperrotti ca8950c
update snapshots
mperrotti 108b40f
Merge branch 'mp/switch-component' of github.com:primer/react into mp…
mperrotti 40ff806
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti cebfa1b
addresses component design feedback
mperrotti 176b5b8
improves docs and storybook examples
mperrotti d653469
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti 30612f9
updates snaps
mperrotti b475d8a
Merge branch 'main' into mp/switch-component
mperrotti 1d52067
Update src/Switch.tsx
mperrotti 37ed9ae
Update docs/content/Switch.mdx
mperrotti 1971e6f
Update src/Switch.tsx
mperrotti 3b8d444
Update src/Switch.tsx
mperrotti 55817f2
addresses PR feedback
mperrotti 22c19ae
Merge branch 'mp/switch-component' of github.com:primer/react into mp…
mperrotti f43c423
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti 3ce5352
increases contrast of control to meet WCAG guidelines
mperrotti 301e05a
CSS cleanup and revert to light off button
mperrotti 8c32664
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti 650a89f
updates snapshots
mperrotti 1bd2e3f
addresses PR feedback
mperrotti 5516bee
rename switch docs
mperrotti 16a3c9c
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti f79f4a3
use component primitives for toggle switch colors
mperrotti b9558bb
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti bbadab8
fixes documentation mistakes
mperrotti ce275cd
updates snapshots
mperrotti d3022e4
Update docs/content/ToggleSwitch.mdx
mperrotti 97cea00
Update docs/content/ToggleSwitch.mdx
mperrotti 09b735e
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti 7afe8e3
updates themePreval snapshot
mperrotti 2871849
Merge branch 'main' of github.com:primer/react into mp/switch-component
mperrotti 5aee49d
upgrades primitives, updates snapshots
mperrotti fa9ff75
Update snapshot
simurai bb78093
Merge branch 'main' into mp/switch-component
mperrotti 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,5 @@ | ||
| --- | ||
| '@primer/react': minor | ||
| --- | ||
|
|
||
| Adds a toggle switch component |
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,220 @@ | ||
| --- | ||
| componentId: toggle_switch | ||
| title: ToggleSwitch | ||
| description: Toggles a setting on or off, and immediately saves the change | ||
| status: Alpha | ||
| source: https://github.com/primer/react/blob/main/src/ToggleSwitch.tsx | ||
| storybook: '/react/storybook?path=/story/toggleswitch-examples--default' | ||
| --- | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Basic | ||
|
|
||
| ```jsx live | ||
| <Box display="flex" maxWidth="300px"> | ||
| <Box flexGrow={1} fontSize={2} fontWeight="bold" id="switchLabel"> | ||
| Notifications | ||
| </Box> | ||
| <ToggleSwitch aria-labelledby="switchLabel" /> | ||
| </Box> | ||
| ``` | ||
|
|
||
| ### Uncontrolled with default value | ||
|
|
||
| ```jsx live | ||
| <Box display="flex" maxWidth="300px"> | ||
| <Box flexGrow={1} fontSize={2} fontWeight="bold" id="switchLabel"> | ||
| Notifications | ||
| </Box> | ||
| <ToggleSwitch defaultChecked aria-labelledby="switchLabel" /> | ||
| </Box> | ||
| ``` | ||
|
|
||
| ### Controlled | ||
|
|
||
| ```javascript noinline live | ||
| const Controlled = () => { | ||
| const [isOn, setIsOn] = React.useState(false) | ||
|
|
||
| const onClick = () => { | ||
| setIsOn(!isOn) | ||
| } | ||
|
|
||
| const handleSwitchChange = on => { | ||
| console.log(`new switch "on" state: ${on}`) | ||
| } | ||
|
|
||
| return ( | ||
| <> | ||
| <Box display="flex" maxWidth="300px"> | ||
| <Box flexGrow={1} fontSize={2} fontWeight="bold" id="switchLabel"> | ||
| Notifications | ||
| </Box> | ||
| <ToggleSwitch onClick={onClick} onChange={handleSwitchChange} checked={isOn} aria-labelledby="switchLabel" /> | ||
| </Box> | ||
| <p>The switch is {isOn ? 'on' : 'off'}</p> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| render(Controlled) | ||
| ``` | ||
|
|
||
| ### Small | ||
|
|
||
| ```jsx live | ||
| <Box display="flex" maxWidth="300px"> | ||
| <Box flexGrow={1} fontSize={1} fontWeight="bold" id="switchLabel"> | ||
| Notifications | ||
| </Box> | ||
| <ToggleSwitch aria-labelledby="switchLabel" size="small" /> | ||
| </Box> | ||
| ``` | ||
|
|
||
| ### Delayed toggle with loading state | ||
|
|
||
| ```javascript noinline live | ||
| const LoadingToggle = () => { | ||
| const [loading, setLoading] = React.useState(false) | ||
| const [isOn, setIsOn] = React.useState(false) | ||
|
|
||
| async function switchSlowly(currentOn) { | ||
| await new Promise(resolve => setTimeout(resolve, 1500)) | ||
| return await !currentOn | ||
| } | ||
|
|
||
| async function onClick() { | ||
| setLoading(!loading) | ||
| const newSwitchState = await switchSlowly(isOn) | ||
| setIsOn(newSwitchState) | ||
| } | ||
|
|
||
| const handleSwitchChange = React.useCallback( | ||
| on => { | ||
| setLoading(false) | ||
| }, | ||
| [setLoading] | ||
| ) | ||
|
|
||
| return ( | ||
| <> | ||
| <Box display="flex" maxWidth="300px"> | ||
| <Box flexGrow={1} fontSize={2} fontWeight="bold" id="switchLabel"> | ||
| Notifications | ||
| </Box> | ||
| <ToggleSwitch | ||
| aria-labelledby="switchLabel" | ||
| loading={loading} | ||
| checked={isOn} | ||
| onClick={onClick} | ||
| onChange={handleSwitchChange} | ||
| /> | ||
| </Box> | ||
| <p>The switch is {isOn ? 'on' : 'off'}</p> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| render(LoadingToggle) | ||
| ``` | ||
|
|
||
| ### Disabled | ||
|
|
||
| ```jsx live | ||
| <Box display="flex" maxWidth="300px"> | ||
| <Box flexGrow={1} fontSize={2} fontWeight="bold" id="switchLabel"> | ||
| Notifications | ||
| </Box> | ||
| <ToggleSwitch aria-labelledby="switchLabel" disabled /> | ||
| </Box> | ||
| ``` | ||
|
|
||
| ### With associated caption text | ||
|
|
||
| ```jsx live | ||
| <Box display="flex"> | ||
| <Box flexGrow={1}> | ||
| <Text fontSize={2} fontWeight="bold" id="switchLabel" display="block"> | ||
| Notifications | ||
| </Text> | ||
| <Text color="fg.subtle" fontSize={1} id="switchCaption" display="block"> | ||
| Notifications will be delivered via email and the GitHub notification center | ||
| </Text> | ||
| </Box> | ||
| <ToggleSwitch aria-labelledby="switchLabel" aria-describedby="switchCaption" /> | ||
| </Box> | ||
| ``` | ||
|
|
||
| ### Left-aligned with label | ||
|
|
||
| ```jsx live | ||
| <> | ||
| <Text fontSize={2} fontWeight="bold" id="switchLabel" display="block" mb={1}> | ||
| Notifications | ||
| </Text> | ||
| <ToggleSwitch statusLabelPosition="end" aria-labelledby="switchLabel" /> | ||
| </> | ||
| ``` | ||
|
|
||
| ## Props | ||
|
|
||
| <PropsTable> | ||
| <PropsTableRow name="aria-describedby" type="string" description="The id of the DOM node that describes the switch" /> | ||
| <PropsTableRow | ||
| name="aria-labelledby" | ||
| type="string" | ||
| required | ||
| description="The id of the DOM node that labels the switch" | ||
| /> | ||
| <PropsTableRow name="defaultChecked" type="boolean" description="Uncontrolled - whether the switch is turned on" /> | ||
| <PropsTableRow name="disabled" type="boolean" description="Whether the switch is ready for user input" /> | ||
| <PropsTableRow name="loading" type="boolean" description="Whether the switch's value is being calculated" /> | ||
| <PropsTableRow name="checked" type="boolean" description="Whether the switch is turned on" /> | ||
| <PropsTableRow | ||
| name="onChange" | ||
| type="(on: boolean) => void" | ||
| description="The callback that is called when the switch is toggled on or off" | ||
| /> | ||
| <PropsTableRow | ||
| name="onClick" | ||
| type="(e: MouseEvent) => void" | ||
| description="The callback that is called when the switch is clicked" | ||
| /> | ||
| <PropsTableRow name="size" type="'small' | 'medium'" defaultValue="medium" description="Size of the switch" /> | ||
| <PropsTableRow | ||
| name="statusLabelPosition" | ||
| type="'start' | 'end'" | ||
| defaultValue="start" | ||
mperrotti marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| description={ | ||
| <> | ||
| <div>Whether the "on" and "off" labels should appear before or after the switch.</div> | ||
| <div> | ||
| <Text fontWeight="bold">This should only be changed when the switch's alignment needs to be adjusted.</Text>{' '} | ||
| For example: It needs to be left-aligned because the label appears above it and the caption appears below it. | ||
| </div> | ||
| </> | ||
| } | ||
| /> | ||
| </PropsTable> | ||
|
|
||
| ## Status | ||
|
|
||
| <ComponentChecklist | ||
| items={{ | ||
| propsDocumented: true, | ||
| noUnnecessaryDeps: true, | ||
| adaptsToThemes: true, | ||
| adaptsToScreenSizes: true, | ||
| fullTestCoverage: true, | ||
| usedInProduction: false, | ||
| usageExamplesDocumented: true, | ||
| hasStorybookStories: true, | ||
| designReviewed: false, | ||
| a11yReviewed: false, | ||
| stableApi: false, | ||
| addressedApiFeedback: false, | ||
| hasDesignGuidelines: false, | ||
| hasFigmaComponent: 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
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.
Uh oh!
There was an error while loading. Please reload this page.