@primer/components 33.0.0-rc.b495ba4a → 33.1.0-rc.6856bcf5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.devcontainer/devcontainer.json +1 -1
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/release.yml +6 -27
- package/.github/workflows/release_canary.yml +4 -60
- package/.github/workflows/release_candidate.yml +5 -51
- package/.github/workflows/statuses.yml +32 -0
- package/.gitignore +1 -0
- package/.nvmrc +1 -1
- package/CHANGELOG.md +20 -0
- package/contributor-docs/CONTRIBUTING.md +14 -61
- package/dist/browser.esm.js +2 -2209
- package/dist/browser.esm.js.map +1 -1
- package/dist/browser.umd.js +2 -2209
- package/dist/browser.umd.js.map +1 -1
- package/docs/content/AnchoredOverlay.mdx +121 -1
- package/docs/content/Avatar.mdx +29 -14
- package/docs/content/AvatarPair.mdx +47 -0
- package/docs/content/AvatarStack.mdx +14 -6
- package/docs/content/Box.mdx +13 -11
- package/docs/content/BranchName.mdx +52 -0
- package/docs/content/{Breadcrumbs.md → Breadcrumbs.mdx} +21 -13
- package/docs/content/Link.mdx +75 -0
- package/docs/content/Radio.md +90 -0
- package/docs/content/TextInput.mdx +125 -0
- package/docs/content/drafts/ActionList2.mdx +484 -0
- package/docs/content/drafts/ActionMenu2.mdx +302 -0
- package/docs/src/@primer/gatsby-theme-doctocat/live-code-scope.js +9 -1
- package/docs/src/@primer/gatsby-theme-doctocat/mdx-components.js +15 -2
- package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +4 -0
- package/docs/src/component-checklist.js +10 -2
- package/docs/src/props-table.js +165 -0
- package/docs/src/props.js +14 -28
- package/lib/ActionList/Header.js +1 -1
- package/lib/ActionList/Item.js +10 -10
- package/lib/ActionList/List.js +1 -1
- package/lib/ActionList2/ActionListContainerContext.d.ts +10 -0
- package/lib/ActionList2/ActionListContainerContext.js +15 -0
- package/lib/ActionList2/Divider.d.ts +3 -2
- package/lib/ActionList2/Divider.js +10 -5
- package/lib/ActionList2/Item.js +22 -8
- package/lib/ActionList2/List.js +12 -2
- package/lib/ActionList2/Selection.js +11 -0
- package/lib/ActionList2/index.d.ts +1 -2
- package/lib/ActionMenu2.d.ts +317 -0
- package/lib/ActionMenu2.js +125 -0
- package/lib/Autocomplete/Autocomplete.d.ts +2 -1
- package/lib/Autocomplete/AutocompleteInput.d.ts +2 -1
- package/lib/BaseStyles.js +2 -20
- package/lib/BorderBox.js +1 -1
- package/lib/Box.js +1 -1
- package/lib/BranchName.js +1 -1
- package/lib/Breadcrumbs.js +3 -3
- package/lib/Button/Button.d.ts +2 -2
- package/lib/Button/Button.js +1 -1
- package/lib/Button/ButtonClose.d.ts +2 -2
- package/lib/Button/ButtonDanger.d.ts +2 -2
- package/lib/Button/ButtonGroup.js +1 -1
- package/lib/Button/ButtonInvisible.d.ts +2 -2
- package/lib/Button/ButtonOutline.d.ts +2 -2
- package/lib/Button/ButtonPrimary.d.ts +2 -2
- package/lib/Checkbox.d.ts +1 -1
- package/lib/Checkbox.js +1 -1
- package/lib/CircleOcticon.d.ts +35 -35
- package/lib/Details.js +1 -1
- package/lib/Dialog.d.ts +37 -37
- package/lib/Dropdown.d.ts +6 -6
- package/lib/DropdownMenu/DropdownButton.d.ts +6 -3
- package/lib/FilterList.d.ts +1 -1
- package/lib/FilteredActionList/FilteredActionList.js +1 -1
- package/lib/Flex.js +1 -1
- package/lib/LabelGroup.js +1 -1
- package/lib/Overlay.js +1 -1
- package/lib/Pagination/Pagination.js +2 -2
- package/lib/Position.d.ts +4 -4
- package/lib/Position.js +1 -1
- package/lib/Radio.d.ts +38 -0
- package/lib/Radio.js +55 -0
- package/lib/SelectMenu/SelectMenu.d.ts +11 -10
- package/lib/SelectMenu/SelectMenu.js +1 -1
- package/lib/SelectMenu/SelectMenuFilter.js +1 -1
- package/lib/SelectMenu/SelectMenuFooter.js +1 -1
- package/lib/SelectMenu/SelectMenuItem.d.ts +1 -1
- package/lib/SelectMenu/SelectMenuItem.js +1 -1
- package/lib/SelectMenu/SelectMenuModal.d.ts +1 -1
- package/lib/SelectMenu/SelectMenuTab.js +1 -1
- package/lib/SelectMenu/SelectMenuTabPanel.js +1 -1
- package/lib/SelectMenu/SelectMenuTabs.js +1 -1
- package/lib/StateLabel.js +1 -1
- package/lib/StyledOcticon.js +1 -1
- package/lib/SubNav.js +3 -3
- package/lib/TextInputWithTokens.d.ts +2 -1
- package/lib/ThemeProvider.d.ts +1 -0
- package/lib/ThemeProvider.js +17 -4
- package/lib/Timeline.js +4 -4
- package/lib/Token/AvatarToken.d.ts +1 -1
- package/lib/Token/AvatarToken.js +1 -1
- package/lib/Token/IssueLabelToken.d.ts +1 -1
- package/lib/Token/Token.d.ts +1 -1
- package/lib/Token/TokenBase.js +1 -1
- package/lib/Tooltip.js +1 -1
- package/lib/UnderlineNav.js +2 -2
- package/lib/__tests__/Radio.test.d.ts +2 -0
- package/lib/__tests__/Radio.test.js +202 -0
- package/lib/__tests__/ThemeProvider.test.js +114 -0
- package/lib/drafts.d.ts +1 -0
- package/lib/drafts.js +13 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +9 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +8 -0
- package/lib/stories/ActionList.stories.js +3 -3
- package/lib/stories/ActionList2.stories.js +1 -1
- package/lib/stories/ActionMenu2.stories.js +455 -0
- package/lib/stories/Checkbox.stories.js +4 -4
- package/lib/stories/Radio.stories.js +146 -0
- package/lib/stories/ThemeProvider.stories.js +1 -5
- package/lib/stories/useFocusTrap.stories.js +1 -11
- package/lib/stories/useFocusZone.stories.js +2 -6
- package/lib-esm/ActionList/Header.js +1 -1
- package/lib-esm/ActionList/Item.js +10 -10
- package/lib-esm/ActionList/List.js +1 -1
- package/lib-esm/ActionList2/ActionListContainerContext.d.ts +10 -0
- package/lib-esm/ActionList2/ActionListContainerContext.js +3 -0
- package/lib-esm/ActionList2/Divider.d.ts +3 -2
- package/lib-esm/ActionList2/Divider.js +8 -5
- package/lib-esm/ActionList2/Item.js +20 -8
- package/lib-esm/ActionList2/List.js +10 -2
- package/lib-esm/ActionList2/Selection.js +9 -0
- package/lib-esm/ActionList2/index.d.ts +1 -2
- package/lib-esm/ActionMenu2.d.ts +317 -0
- package/lib-esm/ActionMenu2.js +100 -0
- package/lib-esm/Autocomplete/Autocomplete.d.ts +2 -1
- package/lib-esm/Autocomplete/AutocompleteInput.d.ts +2 -1
- package/lib-esm/BaseStyles.js +2 -20
- package/lib-esm/BorderBox.js +1 -1
- package/lib-esm/Box.js +1 -1
- package/lib-esm/BranchName.js +1 -1
- package/lib-esm/Breadcrumbs.js +3 -3
- package/lib-esm/Button/Button.d.ts +2 -2
- package/lib-esm/Button/Button.js +1 -1
- package/lib-esm/Button/ButtonClose.d.ts +2 -2
- package/lib-esm/Button/ButtonDanger.d.ts +2 -2
- package/lib-esm/Button/ButtonGroup.js +1 -1
- package/lib-esm/Button/ButtonInvisible.d.ts +2 -2
- package/lib-esm/Button/ButtonOutline.d.ts +2 -2
- package/lib-esm/Button/ButtonPrimary.d.ts +2 -2
- package/lib-esm/Checkbox.d.ts +1 -1
- package/lib-esm/Checkbox.js +1 -1
- package/lib-esm/CircleOcticon.d.ts +35 -35
- package/lib-esm/Details.js +1 -1
- package/lib-esm/Dialog.d.ts +37 -37
- package/lib-esm/Dropdown.d.ts +6 -6
- package/lib-esm/DropdownMenu/DropdownButton.d.ts +6 -3
- package/lib-esm/FilterList.d.ts +1 -1
- package/lib-esm/FilteredActionList/FilteredActionList.js +1 -1
- package/lib-esm/Flex.js +1 -1
- package/lib-esm/LabelGroup.js +1 -1
- package/lib-esm/Overlay.js +1 -1
- package/lib-esm/Pagination/Pagination.js +2 -2
- package/lib-esm/Position.d.ts +4 -4
- package/lib-esm/Position.js +1 -1
- package/lib-esm/Radio.d.ts +38 -0
- package/lib-esm/Radio.js +40 -0
- package/lib-esm/SelectMenu/SelectMenu.d.ts +11 -10
- package/lib-esm/SelectMenu/SelectMenu.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuFilter.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuFooter.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuItem.d.ts +1 -1
- package/lib-esm/SelectMenu/SelectMenuItem.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuModal.d.ts +1 -1
- package/lib-esm/SelectMenu/SelectMenuTab.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuTabPanel.js +1 -1
- package/lib-esm/SelectMenu/SelectMenuTabs.js +1 -1
- package/lib-esm/StateLabel.js +1 -1
- package/lib-esm/StyledOcticon.js +1 -1
- package/lib-esm/SubNav.js +3 -3
- package/lib-esm/TextInputWithTokens.d.ts +2 -1
- package/lib-esm/ThemeProvider.d.ts +1 -0
- package/lib-esm/ThemeProvider.js +17 -4
- package/lib-esm/Timeline.js +4 -4
- package/lib-esm/Token/AvatarToken.d.ts +1 -1
- package/lib-esm/Token/AvatarToken.js +1 -1
- package/lib-esm/Token/IssueLabelToken.d.ts +1 -1
- package/lib-esm/Token/Token.d.ts +1 -1
- package/lib-esm/Token/TokenBase.js +1 -1
- package/lib-esm/Tooltip.js +1 -1
- package/lib-esm/UnderlineNav.js +2 -2
- package/lib-esm/__tests__/Radio.test.d.ts +2 -0
- package/lib-esm/__tests__/Radio.test.js +183 -0
- package/lib-esm/__tests__/ThemeProvider.test.js +114 -0
- package/lib-esm/drafts.d.ts +1 -0
- package/lib-esm/drafts.js +2 -1
- package/lib-esm/hooks/index.d.ts +1 -0
- package/lib-esm/hooks/index.js +2 -1
- package/lib-esm/index.d.ts +2 -0
- package/lib-esm/index.js +1 -0
- package/lib-esm/stories/ActionList.stories.js +3 -3
- package/lib-esm/stories/ActionList2.stories.js +1 -1
- package/lib-esm/stories/ActionMenu2.stories.js +393 -0
- package/lib-esm/stories/Checkbox.stories.js +5 -5
- package/lib-esm/stories/Radio.stories.js +121 -0
- package/lib-esm/stories/ThemeProvider.stories.js +1 -5
- package/lib-esm/stories/useFocusTrap.stories.js +1 -11
- package/lib-esm/stories/useFocusZone.stories.js +2 -6
- package/package-lock.json +1366 -3544
- package/package.json +14 -8
- package/script/component-status-project/build.ts +100 -0
- package/script/component-status-project/deploy.rb +142 -0
- package/src/ActionList2/ActionListContainerContext.tsx +14 -0
- package/src/ActionList2/Divider.tsx +13 -8
- package/src/ActionList2/Item.tsx +14 -6
- package/src/ActionList2/List.tsx +6 -2
- package/src/ActionList2/Selection.tsx +9 -0
- package/src/ActionMenu2.tsx +116 -0
- package/src/BranchName.tsx +2 -1
- package/src/Radio.tsx +76 -0
- package/src/ThemeProvider.tsx +22 -5
- package/src/__tests__/Radio.test.tsx +174 -0
- package/src/__tests__/ThemeProvider.test.tsx +116 -0
- package/src/__tests__/__snapshots__/BranchName.test.tsx.snap +3 -1
- package/src/__tests__/__snapshots__/Radio.test.tsx.snap +16 -0
- package/src/drafts.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/index.ts +2 -0
- package/src/stories/ActionMenu2.stories.tsx +605 -0
- package/src/stories/Checkbox.stories.tsx +1 -3
- package/src/stories/Radio.stories.tsx +126 -0
- package/stats.html +1 -1
- package/tsconfig.build.json +1 -1
- package/tsconfig.json +1 -1
- package/docs/content/ActionList2.mdx +0 -379
- package/docs/content/BranchName.md +0 -39
- package/docs/content/Link.md +0 -29
- package/docs/content/TextInput.md +0 -42
package/src/Radio.tsx
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
import styled from 'styled-components'
|
2
|
+
import React, {InputHTMLAttributes, ReactElement} from 'react'
|
3
|
+
import sx, {SxProp} from './sx'
|
4
|
+
|
5
|
+
export type RadioProps = {
|
6
|
+
/**
|
7
|
+
* A unique value that is never shown to the user.
|
8
|
+
* Used during form submission and to identify which radio button in a group is selected
|
9
|
+
*/
|
10
|
+
value: string
|
11
|
+
/**
|
12
|
+
* Name attribute of the input element. Required for grouping radio inputs
|
13
|
+
*/
|
14
|
+
name: string
|
15
|
+
/**
|
16
|
+
* Apply inactive visual appearance to the radio button
|
17
|
+
*/
|
18
|
+
disabled?: boolean
|
19
|
+
/**
|
20
|
+
* Indicates whether the radio button is selected
|
21
|
+
*/
|
22
|
+
checked?: boolean
|
23
|
+
/**
|
24
|
+
* Forward a ref to the underlying input element
|
25
|
+
*/
|
26
|
+
ref?: React.RefObject<HTMLInputElement>
|
27
|
+
/**
|
28
|
+
* Indicates whether the radio button must be checked before the form can be submitted
|
29
|
+
*/
|
30
|
+
required?: boolean
|
31
|
+
/**
|
32
|
+
* Indicates whether the radio button validation state is non-standard
|
33
|
+
*/
|
34
|
+
validationStatus?: 'error' | 'success' // TODO: hoist to Validation typings
|
35
|
+
} & InputHTMLAttributes<HTMLInputElement> &
|
36
|
+
SxProp
|
37
|
+
|
38
|
+
const StyledRadio = styled.input`
|
39
|
+
cursor: pointer;
|
40
|
+
|
41
|
+
${props => props.disabled && `cursor: not-allowed;`}
|
42
|
+
|
43
|
+
${sx}
|
44
|
+
`
|
45
|
+
|
46
|
+
/**
|
47
|
+
* An accessible, native radio component for selecting one option from a list.
|
48
|
+
*/
|
49
|
+
const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
|
50
|
+
(
|
51
|
+
{checked, disabled, sx: sxProp, required, validationStatus, value, name, ...rest}: RadioProps,
|
52
|
+
ref
|
53
|
+
): ReactElement => {
|
54
|
+
return (
|
55
|
+
<StyledRadio
|
56
|
+
type="radio"
|
57
|
+
value={value}
|
58
|
+
name={name}
|
59
|
+
ref={ref}
|
60
|
+
disabled={disabled}
|
61
|
+
aria-disabled={disabled ? 'true' : 'false'}
|
62
|
+
checked={checked}
|
63
|
+
aria-checked={checked ? 'true' : 'false'}
|
64
|
+
required={required}
|
65
|
+
aria-required={required ? 'true' : 'false'}
|
66
|
+
aria-invalid={validationStatus === 'error' ? 'true' : 'false'}
|
67
|
+
sx={sxProp}
|
68
|
+
{...rest}
|
69
|
+
/>
|
70
|
+
)
|
71
|
+
}
|
72
|
+
)
|
73
|
+
|
74
|
+
Radio.displayName = 'Radio'
|
75
|
+
|
76
|
+
export default Radio
|
package/src/ThemeProvider.tsx
CHANGED
@@ -24,6 +24,7 @@ const ThemeContext = React.createContext<{
|
|
24
24
|
colorScheme?: string
|
25
25
|
colorMode?: ColorModeWithAuto
|
26
26
|
resolvedColorMode?: ColorMode
|
27
|
+
resolvedColorScheme?: string
|
27
28
|
dayScheme?: string
|
28
29
|
nightScheme?: string
|
29
30
|
setColorMode: React.Dispatch<React.SetStateAction<ColorModeWithAuto>>
|
@@ -52,7 +53,10 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({children, ...props}
|
|
52
53
|
const systemColorMode = useSystemColorMode()
|
53
54
|
const resolvedColorMode = resolveColorMode(colorMode, systemColorMode)
|
54
55
|
const colorScheme = chooseColorScheme(resolvedColorMode, dayScheme, nightScheme)
|
55
|
-
const resolvedTheme = React.useMemo(
|
56
|
+
const {resolvedTheme, resolvedColorScheme} = React.useMemo(
|
57
|
+
() => applyColorScheme(theme, colorScheme),
|
58
|
+
[theme, colorScheme]
|
59
|
+
)
|
56
60
|
|
57
61
|
// Update state if props change
|
58
62
|
React.useEffect(() => {
|
@@ -74,6 +78,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({children, ...props}
|
|
74
78
|
colorScheme,
|
75
79
|
colorMode,
|
76
80
|
resolvedColorMode,
|
81
|
+
resolvedColorScheme,
|
77
82
|
dayScheme,
|
78
83
|
nightScheme,
|
79
84
|
setColorMode,
|
@@ -156,9 +161,15 @@ function chooseColorScheme(colorMode: ColorMode, dayScheme: string, nightScheme:
|
|
156
161
|
}
|
157
162
|
}
|
158
163
|
|
159
|
-
function applyColorScheme(
|
164
|
+
function applyColorScheme(
|
165
|
+
theme: Theme,
|
166
|
+
colorScheme: string
|
167
|
+
): {resolvedTheme: Theme; resolvedColorScheme: string | undefined} {
|
160
168
|
if (!theme.colorSchemes) {
|
161
|
-
return
|
169
|
+
return {
|
170
|
+
resolvedTheme: theme,
|
171
|
+
resolvedColorScheme: undefined
|
172
|
+
}
|
162
173
|
}
|
163
174
|
|
164
175
|
if (!theme.colorSchemes[colorScheme]) {
|
@@ -167,10 +178,16 @@ function applyColorScheme(theme: Theme, colorScheme: string) {
|
|
167
178
|
|
168
179
|
// Apply the first defined color scheme
|
169
180
|
const defaultColorScheme = Object.keys(theme.colorSchemes)[0]
|
170
|
-
return
|
181
|
+
return {
|
182
|
+
resolvedTheme: deepmerge(theme, theme.colorSchemes[defaultColorScheme]),
|
183
|
+
resolvedColorScheme: defaultColorScheme
|
184
|
+
}
|
171
185
|
}
|
172
186
|
|
173
|
-
return
|
187
|
+
return {
|
188
|
+
resolvedTheme: deepmerge(theme, theme.colorSchemes[colorScheme]),
|
189
|
+
resolvedColorScheme: colorScheme
|
190
|
+
}
|
174
191
|
}
|
175
192
|
|
176
193
|
export default ThemeProvider
|
@@ -0,0 +1,174 @@
|
|
1
|
+
import React from 'react'
|
2
|
+
import {Radio} from '..'
|
3
|
+
import {behavesAsComponent, checkExports} from '../utils/testing'
|
4
|
+
import {render, cleanup, fireEvent} from '@testing-library/react'
|
5
|
+
import {toHaveNoViolations} from 'jest-axe'
|
6
|
+
import 'babel-polyfill'
|
7
|
+
import '@testing-library/jest-dom'
|
8
|
+
|
9
|
+
expect.extend(toHaveNoViolations)
|
10
|
+
|
11
|
+
describe('Radio', () => {
|
12
|
+
const defaultProps = {
|
13
|
+
name: 'mock',
|
14
|
+
value: 'mock value'
|
15
|
+
}
|
16
|
+
|
17
|
+
beforeEach(() => {
|
18
|
+
jest.resetAllMocks()
|
19
|
+
cleanup()
|
20
|
+
})
|
21
|
+
|
22
|
+
behavesAsComponent({Component: Radio})
|
23
|
+
|
24
|
+
checkExports('Radio', {
|
25
|
+
default: Radio
|
26
|
+
})
|
27
|
+
|
28
|
+
it('renders a valid radio input', () => {
|
29
|
+
const {getByRole} = render(<Radio {...defaultProps} />)
|
30
|
+
|
31
|
+
const radio = getByRole('radio')
|
32
|
+
|
33
|
+
expect(radio).toBeDefined()
|
34
|
+
})
|
35
|
+
|
36
|
+
it('renders an unchecked radio by default', () => {
|
37
|
+
const {getByRole} = render(<Radio {...defaultProps} />)
|
38
|
+
|
39
|
+
const radio = getByRole('radio') as HTMLInputElement
|
40
|
+
|
41
|
+
expect(radio.checked).toEqual(false)
|
42
|
+
})
|
43
|
+
|
44
|
+
it('accepts and applies value and name attributes', () => {
|
45
|
+
const {getByRole} = render(<Radio {...defaultProps} />)
|
46
|
+
|
47
|
+
const radio = getByRole('radio') as HTMLInputElement
|
48
|
+
|
49
|
+
expect(radio).toHaveAttribute('name', defaultProps.name)
|
50
|
+
expect(radio).toHaveAttribute('value', defaultProps.value)
|
51
|
+
})
|
52
|
+
|
53
|
+
it('renders an active radio when checked attribute is passed', () => {
|
54
|
+
const handleChange = jest.fn()
|
55
|
+
const {getByRole} = render(<Radio {...defaultProps} checked onChange={handleChange} />)
|
56
|
+
|
57
|
+
const radio = getByRole('radio') as HTMLInputElement
|
58
|
+
|
59
|
+
expect(radio.checked).toEqual(true)
|
60
|
+
})
|
61
|
+
|
62
|
+
it('accepts a change handler that can alter a single radio state', () => {
|
63
|
+
const handleChange = jest.fn()
|
64
|
+
const {getByRole} = render(<Radio {...defaultProps} onChange={handleChange} />)
|
65
|
+
|
66
|
+
const radio = getByRole('radio') as HTMLInputElement
|
67
|
+
|
68
|
+
expect(radio.checked).toEqual(false)
|
69
|
+
|
70
|
+
fireEvent.click(radio)
|
71
|
+
expect(handleChange).toHaveBeenCalled()
|
72
|
+
expect(radio.checked).toEqual(true)
|
73
|
+
})
|
74
|
+
|
75
|
+
it('renders correct behavior for multiple radio buttons in a group', () => {
|
76
|
+
const handleChange = jest.fn()
|
77
|
+
const RadioGroup = () => (
|
78
|
+
<form>
|
79
|
+
<Radio {...defaultProps} value="radio-one" onChange={handleChange} />
|
80
|
+
<Radio {...defaultProps} value="radio-two" onChange={handleChange} />
|
81
|
+
</form>
|
82
|
+
)
|
83
|
+
const {getByDisplayValue} = render(<RadioGroup />)
|
84
|
+
|
85
|
+
const radioOne = getByDisplayValue('radio-one') as HTMLInputElement
|
86
|
+
const radioTwo = getByDisplayValue('radio-two') as HTMLInputElement
|
87
|
+
|
88
|
+
expect(radioOne).not.toBeChecked()
|
89
|
+
expect(radioTwo).not.toBeChecked()
|
90
|
+
|
91
|
+
fireEvent.click(radioOne)
|
92
|
+
|
93
|
+
expect(radioOne).toBeChecked()
|
94
|
+
expect(radioTwo).not.toBeChecked()
|
95
|
+
|
96
|
+
fireEvent.click(radioTwo)
|
97
|
+
|
98
|
+
expect(radioOne).not.toBeChecked()
|
99
|
+
expect(radioTwo).toBeChecked()
|
100
|
+
})
|
101
|
+
|
102
|
+
it('renders an inactive radio state correctly', () => {
|
103
|
+
const handleChange = jest.fn()
|
104
|
+
const {getByRole, rerender} = render(<Radio {...defaultProps} disabled onChange={handleChange} />)
|
105
|
+
|
106
|
+
const radio = getByRole('radio') as HTMLInputElement
|
107
|
+
|
108
|
+
expect(radio.disabled).toEqual(true)
|
109
|
+
expect(radio).not.toBeChecked()
|
110
|
+
expect(radio).toHaveAttribute('aria-disabled', 'true')
|
111
|
+
|
112
|
+
fireEvent.change(radio)
|
113
|
+
|
114
|
+
expect(radio.disabled).toEqual(true)
|
115
|
+
expect(radio).not.toBeChecked()
|
116
|
+
expect(radio).toHaveAttribute('aria-disabled', 'true')
|
117
|
+
|
118
|
+
// remove disabled attribute and retest
|
119
|
+
rerender(<Radio {...defaultProps} onChange={handleChange} />)
|
120
|
+
|
121
|
+
expect(radio).toHaveAttribute('aria-disabled', 'false')
|
122
|
+
})
|
123
|
+
|
124
|
+
it('renders an uncontrolled component correctly', () => {
|
125
|
+
const {getByRole} = render(<Radio {...defaultProps} defaultChecked />)
|
126
|
+
|
127
|
+
const radio = getByRole('radio') as HTMLInputElement
|
128
|
+
|
129
|
+
expect(radio.checked).toEqual(true)
|
130
|
+
})
|
131
|
+
|
132
|
+
it('renders an aria-checked attribute correctly', () => {
|
133
|
+
const handleChange = jest.fn()
|
134
|
+
const {getByRole, rerender} = render(<Radio {...defaultProps} checked={false} onChange={handleChange} />)
|
135
|
+
|
136
|
+
const radio = getByRole('radio') as HTMLInputElement
|
137
|
+
|
138
|
+
expect(radio).toHaveAttribute('aria-checked', 'false')
|
139
|
+
|
140
|
+
rerender(<Radio {...defaultProps} checked={true} onChange={handleChange} />)
|
141
|
+
|
142
|
+
expect(radio).toHaveAttribute('aria-checked', 'true')
|
143
|
+
})
|
144
|
+
|
145
|
+
it('renders an invalid aria state when validation prop indicates an error', () => {
|
146
|
+
const handleChange = jest.fn()
|
147
|
+
const {getByRole, rerender} = render(<Radio {...defaultProps} onChange={handleChange} />)
|
148
|
+
|
149
|
+
const radio = getByRole('radio') as HTMLInputElement
|
150
|
+
|
151
|
+
expect(radio).toHaveAttribute('aria-invalid', 'false')
|
152
|
+
|
153
|
+
rerender(<Radio {...defaultProps} onChange={handleChange} validationStatus="success" />)
|
154
|
+
|
155
|
+
expect(radio).toHaveAttribute('aria-invalid', 'false')
|
156
|
+
|
157
|
+
rerender(<Radio {...defaultProps} onChange={handleChange} validationStatus="error" />)
|
158
|
+
|
159
|
+
expect(radio).toHaveAttribute('aria-invalid', 'true')
|
160
|
+
})
|
161
|
+
|
162
|
+
it('renders an aria state indicating the field is required', () => {
|
163
|
+
const handleChange = jest.fn()
|
164
|
+
const {getByRole, rerender} = render(<Radio {...defaultProps} onChange={handleChange} />)
|
165
|
+
|
166
|
+
const radio = getByRole('radio') as HTMLInputElement
|
167
|
+
|
168
|
+
expect(radio).toHaveAttribute('aria-required', 'false')
|
169
|
+
|
170
|
+
rerender(<Radio {...defaultProps} onChange={handleChange} required />)
|
171
|
+
|
172
|
+
expect(radio).toHaveAttribute('aria-required', 'true')
|
173
|
+
})
|
174
|
+
})
|
@@ -439,3 +439,119 @@ describe('useColorSchemeVar', () => {
|
|
439
439
|
expect(screen.getByText('Hello')).toHaveStyleRule('background-color', 'blue')
|
440
440
|
})
|
441
441
|
})
|
442
|
+
|
443
|
+
describe('useTheme().resolvedColorScheme', () => {
|
444
|
+
it('is undefined when not in a theme', () => {
|
445
|
+
const Component = () => {
|
446
|
+
const {resolvedColorScheme} = useTheme()
|
447
|
+
|
448
|
+
return <Text data-testid="text">{resolvedColorScheme}</Text>
|
449
|
+
}
|
450
|
+
|
451
|
+
render(<Component />)
|
452
|
+
|
453
|
+
expect(screen.getByTestId('text').textContent).toEqual('')
|
454
|
+
})
|
455
|
+
|
456
|
+
it('is undefined when the theme has no colorScheme object', () => {
|
457
|
+
const Component = () => {
|
458
|
+
const {resolvedColorScheme} = useTheme()
|
459
|
+
|
460
|
+
return <Text data-testid="text">{resolvedColorScheme}</Text>
|
461
|
+
}
|
462
|
+
|
463
|
+
render(
|
464
|
+
<ThemeProvider theme={{color: 'red'}}>
|
465
|
+
<Component />
|
466
|
+
</ThemeProvider>
|
467
|
+
)
|
468
|
+
|
469
|
+
expect(screen.getByTestId('text').textContent).toEqual('')
|
470
|
+
})
|
471
|
+
|
472
|
+
it('is the same as the applied colorScheme, when that colorScheme is in the theme', () => {
|
473
|
+
const Component = () => {
|
474
|
+
const {resolvedColorScheme} = useTheme()
|
475
|
+
|
476
|
+
return <Text data-testid="text">{resolvedColorScheme}</Text>
|
477
|
+
}
|
478
|
+
|
479
|
+
const schemeToApply = 'dark'
|
480
|
+
|
481
|
+
render(
|
482
|
+
<ThemeProvider theme={exampleTheme} colorMode="day" dayScheme={schemeToApply}>
|
483
|
+
<Component />
|
484
|
+
</ThemeProvider>
|
485
|
+
)
|
486
|
+
|
487
|
+
expect(exampleTheme.colorSchemes).toHaveProperty(schemeToApply)
|
488
|
+
expect(screen.getByTestId('text').textContent).toEqual(schemeToApply)
|
489
|
+
})
|
490
|
+
|
491
|
+
it('is the value of the fallback colorScheme applied when attempting to apply an invalid colorScheme', () => {
|
492
|
+
const Component = () => {
|
493
|
+
const {resolvedColorScheme} = useTheme()
|
494
|
+
|
495
|
+
return <Text data-testid="text">{resolvedColorScheme}</Text>
|
496
|
+
}
|
497
|
+
|
498
|
+
const schemeToApply = 'totally-invalid-colorscheme'
|
499
|
+
render(
|
500
|
+
<ThemeProvider theme={exampleTheme} colorMode="day" dayScheme={schemeToApply}>
|
501
|
+
<Component />
|
502
|
+
</ThemeProvider>
|
503
|
+
)
|
504
|
+
|
505
|
+
const defaultThemeColorScheme = Object.keys(exampleTheme.colorSchemes)[0]
|
506
|
+
|
507
|
+
expect(defaultThemeColorScheme).not.toEqual(schemeToApply)
|
508
|
+
expect(exampleTheme.colorSchemes).not.toHaveProperty(schemeToApply)
|
509
|
+
expect(screen.getByTestId('text').textContent).toEqual('light')
|
510
|
+
})
|
511
|
+
|
512
|
+
describe('nested theme', () => {
|
513
|
+
it('is the same as the applied colorScheme, when that colorScheme is in the theme', () => {
|
514
|
+
const Component = () => {
|
515
|
+
const {resolvedColorScheme} = useTheme()
|
516
|
+
|
517
|
+
return <Text data-testid="text">{resolvedColorScheme}</Text>
|
518
|
+
}
|
519
|
+
|
520
|
+
const schemeToApply = 'dark'
|
521
|
+
|
522
|
+
render(
|
523
|
+
<ThemeProvider theme={exampleTheme} colorMode="day" dayScheme={schemeToApply}>
|
524
|
+
<ThemeProvider>
|
525
|
+
<Component />
|
526
|
+
</ThemeProvider>
|
527
|
+
</ThemeProvider>
|
528
|
+
)
|
529
|
+
|
530
|
+
expect(exampleTheme.colorSchemes).toHaveProperty(schemeToApply)
|
531
|
+
expect(screen.getByTestId('text').textContent).toEqual(schemeToApply)
|
532
|
+
})
|
533
|
+
|
534
|
+
it('is the value of the fallback colorScheme applied when attempting to apply an invalid colorScheme', () => {
|
535
|
+
const Component = () => {
|
536
|
+
const {resolvedColorScheme} = useTheme()
|
537
|
+
|
538
|
+
return <Text data-testid="text">{resolvedColorScheme}</Text>
|
539
|
+
}
|
540
|
+
|
541
|
+
const schemeToApply = 'totally-invalid-colorscheme'
|
542
|
+
render(
|
543
|
+
<ThemeProvider theme={exampleTheme} colorMode="day" dayScheme={schemeToApply}>
|
544
|
+
<ThemeProvider>
|
545
|
+
<Component />
|
546
|
+
</ThemeProvider>
|
547
|
+
</ThemeProvider>
|
548
|
+
)
|
549
|
+
|
550
|
+
const defaultThemeColorScheme = Object.keys(exampleTheme.colorSchemes)[0]
|
551
|
+
|
552
|
+
expect(defaultThemeColorScheme).not.toEqual(schemeToApply)
|
553
|
+
expect(exampleTheme.colorSchemes).not.toHaveProperty(schemeToApply)
|
554
|
+
expect(screen.getByTestId('text').textContent).toEqual('light')
|
555
|
+
})
|
556
|
+
})
|
557
|
+
})
|
@@ -6,9 +6,11 @@ exports[`BranchName renders consistently 1`] = `
|
|
6
6
|
padding: 2px 6px;
|
7
7
|
font-size: 12px;
|
8
8
|
font-family: SFMono-Regular,Consolas,"Liberation Mono",Menlo,Courier,monospace;
|
9
|
-
color: #
|
9
|
+
color: #0969da;
|
10
10
|
background-color: #ddf4ff;
|
11
11
|
border-radius: 6px;
|
12
|
+
-webkit-text-decoration: none;
|
13
|
+
text-decoration: none;
|
12
14
|
}
|
13
15
|
|
14
16
|
<a
|
@@ -0,0 +1,16 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`Radio renders consistently 1`] = `
|
4
|
+
.c0 {
|
5
|
+
cursor: pointer;
|
6
|
+
}
|
7
|
+
|
8
|
+
<input
|
9
|
+
aria-checked="false"
|
10
|
+
aria-disabled="false"
|
11
|
+
aria-invalid="false"
|
12
|
+
aria-required="false"
|
13
|
+
className="c0"
|
14
|
+
type="radio"
|
15
|
+
/>
|
16
|
+
`;
|
package/src/drafts.ts
CHANGED
package/src/hooks/index.ts
CHANGED
@@ -9,3 +9,4 @@ export {useAnchoredPosition} from './useAnchoredPosition'
|
|
9
9
|
export {useOverlay} from './useOverlay'
|
10
10
|
export type {UseOverlaySettings} from './useOverlay'
|
11
11
|
export {useRenderForcingRef} from './useRenderForcingRef'
|
12
|
+
export {useProvidedStateOrCreate} from './useProvidedStateOrCreate'
|
package/src/index.ts
CHANGED
@@ -27,6 +27,8 @@ export {useOverlay} from './hooks/useOverlay'
|
|
27
27
|
export {useConfirm} from './Dialog/ConfirmationDialog'
|
28
28
|
|
29
29
|
// Components
|
30
|
+
export {default as Radio} from './Radio'
|
31
|
+
export type {RadioProps} from './Radio'
|
30
32
|
export {ActionList} from './ActionList'
|
31
33
|
export {ActionMenu} from './ActionMenu'
|
32
34
|
export type {ActionMenuProps} from './ActionMenu'
|