@primer/components 32.0.2-rc.859381a1 → 32.1.1-rc.b4502a34

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.
Files changed (155) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/dist/browser.esm.js +9 -2
  3. package/dist/browser.esm.js.map +1 -1
  4. package/dist/browser.umd.js +9 -2
  5. package/dist/browser.umd.js.map +1 -1
  6. package/docs/content/ActionList2.mdx +23 -3
  7. package/docs/content/Avatar.mdx +21 -1
  8. package/docs/content/AvatarStack.mdx +23 -3
  9. package/docs/content/BranchName.md +24 -4
  10. package/docs/content/Breadcrumbs.md +22 -1
  11. package/docs/content/Buttons.md +2 -1
  12. package/docs/content/Checkbox.md +118 -0
  13. package/docs/content/CircleBadge.md +1 -0
  14. package/docs/content/CircleOcticon.md +2 -1
  15. package/docs/content/CounterLabel.md +1 -1
  16. package/docs/content/Details.md +2 -1
  17. package/docs/content/Dialog.md +1 -0
  18. package/docs/content/Dialog2.mdx +1 -0
  19. package/docs/content/Dropdown.md +1 -0
  20. package/docs/content/DropdownMenu.mdx +1 -0
  21. package/docs/content/FilterList.md +1 -0
  22. package/docs/content/FilteredSearch.md +1 -0
  23. package/docs/content/Flash.md +1 -0
  24. package/docs/content/FormGroup.md +1 -0
  25. package/docs/content/Header.md +1 -0
  26. package/docs/content/Heading.md +8 -4
  27. package/docs/content/Label.md +1 -0
  28. package/docs/content/LabelGroup.md +1 -0
  29. package/docs/content/Link.md +1 -0
  30. package/docs/content/Overlay.mdx +1 -0
  31. package/docs/content/Pagehead.md +1 -0
  32. package/docs/content/Pagination.md +1 -0
  33. package/docs/content/PointerBox.md +1 -0
  34. package/docs/content/Popover.md +1 -0
  35. package/docs/content/Portal.mdx +1 -0
  36. package/docs/content/Position.md +2 -9
  37. package/docs/content/ProgressBar.mdx +1 -0
  38. package/docs/content/SelectMenu.md +1 -0
  39. package/docs/content/SideNav.md +1 -0
  40. package/docs/content/StateLabel.md +1 -0
  41. package/docs/content/StyledOcticon.md +1 -1
  42. package/docs/content/SubNav.md +1 -0
  43. package/docs/content/TabNav.md +1 -0
  44. package/docs/content/Text.md +10 -3
  45. package/docs/content/TextInput.md +9 -1
  46. package/docs/content/Timeline.md +1 -0
  47. package/docs/content/Tooltip.md +1 -0
  48. package/docs/content/Truncate.md +1 -0
  49. package/docs/content/UnderlineNav.md +1 -0
  50. package/docs/content/status.mdx +10 -0
  51. package/docs/src/@primer/gatsby-theme-doctocat/mdx-components.js +9 -0
  52. package/docs/src/@primer/gatsby-theme-doctocat/nav.yml +4 -0
  53. package/docs/src/component-statuses.js +74 -0
  54. package/lib/ActionList/Item.js +3 -3
  55. package/lib/ActionList2/Item.js +3 -1
  56. package/lib/ActionList2/List.js +1 -2
  57. package/lib/ActionList2/Selection.js +3 -1
  58. package/lib/Autocomplete/Autocomplete.d.ts +1 -0
  59. package/lib/Autocomplete/AutocompleteInput.d.ts +1 -0
  60. package/lib/Button/Button.d.ts +1 -0
  61. package/lib/Button/ButtonClose.d.ts +2 -1
  62. package/lib/Button/ButtonDanger.d.ts +1 -0
  63. package/lib/Button/ButtonInvisible.d.ts +1 -0
  64. package/lib/Button/ButtonOutline.d.ts +1 -0
  65. package/lib/Button/ButtonPrimary.d.ts +1 -0
  66. package/lib/Checkbox.d.ts +29 -0
  67. package/lib/Checkbox.js +64 -0
  68. package/lib/CircleOcticon.d.ts +1 -0
  69. package/lib/Dialog.d.ts +3 -2
  70. package/lib/Dropdown.d.ts +4 -0
  71. package/lib/DropdownMenu/DropdownButton.d.ts +2 -1
  72. package/lib/FilterList.d.ts +1 -0
  73. package/lib/Position.d.ts +4 -4
  74. package/lib/SelectMenu/SelectMenu.d.ts +10 -4
  75. package/lib/SelectMenu/SelectMenuItem.d.ts +1 -1
  76. package/lib/SelectMenu/SelectMenuModal.d.ts +1 -1
  77. package/lib/TextInputWithTokens.d.ts +1 -0
  78. package/lib/Token/AvatarToken.d.ts +1 -1
  79. package/lib/Token/IssueLabelToken.d.ts +1 -1
  80. package/lib/Token/Token.d.ts +1 -1
  81. package/lib/__tests__/ActionList2.test.d.ts +1 -0
  82. package/lib/__tests__/ActionList2.test.js +117 -0
  83. package/lib/__tests__/Checkbox.test.d.ts +2 -0
  84. package/lib/__tests__/Checkbox.test.js +189 -0
  85. package/lib/__tests__/themePreval.test.d.ts +1 -0
  86. package/lib/__tests__/themePreval.test.js +14 -0
  87. package/lib/index.d.ts +2 -0
  88. package/lib/index.js +8 -0
  89. package/lib/stories/ActionList2.stories.js +20 -6
  90. package/lib/stories/Checkbox.stories.js +227 -0
  91. package/lib/utils/testing.d.ts +1 -0
  92. package/lib/utils/testing.js +29 -0
  93. package/lib-esm/ActionList/Item.js +3 -3
  94. package/lib-esm/ActionList2/Item.js +3 -1
  95. package/lib-esm/ActionList2/List.js +1 -2
  96. package/lib-esm/ActionList2/Selection.js +3 -1
  97. package/lib-esm/Autocomplete/Autocomplete.d.ts +1 -0
  98. package/lib-esm/Autocomplete/AutocompleteInput.d.ts +1 -0
  99. package/lib-esm/Button/Button.d.ts +1 -0
  100. package/lib-esm/Button/ButtonClose.d.ts +2 -1
  101. package/lib-esm/Button/ButtonDanger.d.ts +1 -0
  102. package/lib-esm/Button/ButtonInvisible.d.ts +1 -0
  103. package/lib-esm/Button/ButtonOutline.d.ts +1 -0
  104. package/lib-esm/Button/ButtonPrimary.d.ts +1 -0
  105. package/lib-esm/Checkbox.d.ts +29 -0
  106. package/lib-esm/Checkbox.js +44 -0
  107. package/lib-esm/CircleOcticon.d.ts +1 -0
  108. package/lib-esm/Dialog.d.ts +3 -2
  109. package/lib-esm/Dropdown.d.ts +4 -0
  110. package/lib-esm/DropdownMenu/DropdownButton.d.ts +2 -1
  111. package/lib-esm/FilterList.d.ts +1 -0
  112. package/lib-esm/Position.d.ts +4 -4
  113. package/lib-esm/SelectMenu/SelectMenu.d.ts +10 -4
  114. package/lib-esm/SelectMenu/SelectMenuItem.d.ts +1 -1
  115. package/lib-esm/SelectMenu/SelectMenuModal.d.ts +1 -1
  116. package/lib-esm/TextInputWithTokens.d.ts +1 -0
  117. package/lib-esm/Token/AvatarToken.d.ts +1 -1
  118. package/lib-esm/Token/IssueLabelToken.d.ts +1 -1
  119. package/lib-esm/Token/Token.d.ts +1 -1
  120. package/lib-esm/__tests__/ActionList2.test.d.ts +1 -0
  121. package/lib-esm/__tests__/ActionList2.test.js +105 -2
  122. package/lib-esm/__tests__/Checkbox.test.d.ts +2 -0
  123. package/lib-esm/__tests__/Checkbox.test.js +169 -0
  124. package/lib-esm/__tests__/themePreval.test.d.ts +1 -0
  125. package/lib-esm/__tests__/themePreval.test.js +7 -0
  126. package/lib-esm/index.d.ts +2 -0
  127. package/lib-esm/index.js +1 -0
  128. package/lib-esm/stories/ActionList2.stories.js +20 -6
  129. package/lib-esm/stories/Checkbox.stories.js +197 -0
  130. package/lib-esm/utils/testing.d.ts +1 -0
  131. package/lib-esm/utils/testing.js +24 -0
  132. package/package-lock.json +179 -20
  133. package/package.json +2 -2
  134. package/src/ActionList/Item.tsx +2 -1
  135. package/src/ActionList2/Item.tsx +3 -2
  136. package/src/ActionList2/List.tsx +1 -6
  137. package/src/ActionList2/Selection.tsx +2 -1
  138. package/src/Checkbox.tsx +75 -0
  139. package/src/__tests__/ActionList2.test.tsx +111 -2
  140. package/src/__tests__/Checkbox.test.tsx +155 -0
  141. package/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +13 -0
  142. package/src/__tests__/__snapshots__/Checkbox.test.tsx.snap +16 -0
  143. package/src/__tests__/__snapshots__/themePreval.test.ts.snap +3176 -0
  144. package/src/__tests__/themePreval.test.ts +8 -0
  145. package/src/index.ts +3 -0
  146. package/src/stories/ActionList2.stories.tsx +22 -8
  147. package/src/stories/Checkbox.stories.tsx +164 -0
  148. package/src/utils/testing.tsx +22 -0
  149. package/stats.html +1 -1
  150. package/docs/content/TextInputTokens.mdx +0 -89
  151. package/lib/ActionList2/Header.d.ts +0 -26
  152. package/lib/ActionList2/Header.js +0 -55
  153. package/lib-esm/ActionList2/Header.d.ts +0 -26
  154. package/lib-esm/ActionList2/Header.js +0 -44
  155. package/src/ActionList2/Header.tsx +0 -58
@@ -0,0 +1,8 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ test('snapshot theme-preval.js', () => {
5
+ // Snapshot test the build output of theme-preval.js to catch any unexpected changes
6
+ const themePrevalFile = fs.readFileSync(path.resolve(__dirname, '../../lib/theme-preval.js'), 'utf8')
7
+ expect(themePrevalFile).toMatchSnapshot()
8
+ })
package/src/index.ts CHANGED
@@ -169,4 +169,7 @@ export type {TruncateProps} from './Truncate'
169
169
  export {default as UnderlineNav} from './UnderlineNav'
170
170
  export type {UnderlineNavProps, UnderlineNavLinkProps} from './UnderlineNav'
171
171
 
172
+ export {default as Checkbox} from './Checkbox'
173
+ export type {CheckboxProps} from './Checkbox'
174
+
172
175
  export {SSRProvider, useSSRSafeId} from './utils/ssr'
@@ -801,7 +801,7 @@ export function AllCombinations(): JSX.Element {
801
801
  L + I + B<ActionList.Description variant="inline">inline description</ActionList.Description>
802
802
  <ActionList.Description variant="block">Block description</ActionList.Description>
803
803
  </ActionList.Item>
804
- <ActionList.Item>
804
+ <ActionList.Item disabled>
805
805
  <ActionList.LeadingVisual>
806
806
  <StarIcon />
807
807
  </ActionList.LeadingVisual>
@@ -810,7 +810,7 @@ export function AllCombinations(): JSX.Element {
810
810
  <StarIcon />
811
811
  </ActionList.TrailingVisual>
812
812
  </ActionList.Item>
813
- <ActionList.Item>
813
+ <ActionList.Item disabled>
814
814
  <ActionList.LeadingVisual>
815
815
  <StarIcon />
816
816
  </ActionList.LeadingVisual>
@@ -819,7 +819,7 @@ export function AllCombinations(): JSX.Element {
819
819
  <StarIcon />
820
820
  </ActionList.TrailingVisual>
821
821
  </ActionList.Item>
822
- <ActionList.Item>
822
+ <ActionList.Item disabled>
823
823
  I + B + T<ActionList.Description variant="inline">inline description</ActionList.Description>
824
824
  <ActionList.Description variant="block">Block description</ActionList.Description>
825
825
  <ActionList.TrailingVisual>
@@ -1051,9 +1051,14 @@ export function MemexGroupBy(): JSX.Element {
1051
1051
  <h1>Memex GroupBy List</h1>
1052
1052
  <ErsatzOverlay>
1053
1053
  <ActionList>
1054
- <ActionList.Group title="Group by" selectionVariant="single">
1054
+ <ActionList.Group title="Group by" selectionVariant="single" role="listbox">
1055
1055
  {options.map((option, index) => (
1056
- <ActionList.Item key={index} selected={index === selectedIndex} onSelect={() => setSelectedIndex(index)}>
1056
+ <ActionList.Item
1057
+ key={index}
1058
+ selected={index === selectedIndex}
1059
+ onSelect={() => setSelectedIndex(index)}
1060
+ role="option"
1061
+ >
1057
1062
  <ActionList.LeadingVisual>{option.icon}</ActionList.LeadingVisual>
1058
1063
  {option.text}
1059
1064
  </ActionList.Item>
@@ -1119,10 +1124,11 @@ export function MemexSortable(): JSX.Element {
1119
1124
  <ErsatzOverlay>
1120
1125
  <DndProvider backend={HTML5Backend}>
1121
1126
  <ActionList selectionVariant="multiple">
1122
- <ActionList.Group title="Visible fields (can be reordered)">
1127
+ <ActionList.Group title="Visible fields (can be reordered)" role="listbox">
1123
1128
  {visibleOptions.map(option => (
1124
1129
  <SortableItem
1125
1130
  key={option.text}
1131
+ role="option"
1126
1132
  option={option}
1127
1133
  onSelect={() => toggle(option.text)}
1128
1134
  reorder={reorder}
@@ -1130,6 +1136,7 @@ export function MemexSortable(): JSX.Element {
1130
1136
  ))}
1131
1137
  </ActionList.Group>
1132
1138
  <ActionList.Group
1139
+ role="listbox"
1133
1140
  title="Hidden fields"
1134
1141
  selectionVariant={
1135
1142
  /** selectionVariant override on Group: disable selection if there are no options */
@@ -1137,7 +1144,12 @@ export function MemexSortable(): JSX.Element {
1137
1144
  }
1138
1145
  >
1139
1146
  {hiddenOptions.map((option, index) => (
1140
- <ActionList.Item key={index} selected={option.selected} onSelect={() => toggle(option.text)}>
1147
+ <ActionList.Item
1148
+ key={index}
1149
+ role="option"
1150
+ selected={option.selected}
1151
+ onSelect={() => toggle(option.text)}
1152
+ >
1141
1153
  <ActionList.LeadingVisual>{option.icon}</ActionList.LeadingVisual>
1142
1154
  {option.text}
1143
1155
  </ActionList.Item>
@@ -1154,10 +1166,11 @@ MemexSortable.storyName = 'Memex Sortable List'
1154
1166
 
1155
1167
  type SortableItemProps = {
1156
1168
  option: Option
1169
+ role: ItemProps['role']
1157
1170
  onSelect: ItemProps['onSelect']
1158
1171
  reorder: ({optionToMove, moveAfterOption}: {optionToMove: Option; moveAfterOption: Option}) => void
1159
1172
  }
1160
- const SortableItem: React.FC<SortableItemProps> = ({option, onSelect, reorder}) => {
1173
+ const SortableItem: React.FC<SortableItemProps> = ({option, role, onSelect, reorder}) => {
1161
1174
  const [{isDragging}, dragRef] = useDrag(() => ({
1162
1175
  type: 'ITEM',
1163
1176
  item: option,
@@ -1178,6 +1191,7 @@ const SortableItem: React.FC<SortableItemProps> = ({option, onSelect, reorder})
1178
1191
 
1179
1192
  return (
1180
1193
  <ActionList.Item
1194
+ role={role}
1181
1195
  ref={element => dragRef(element) && dropRef(element)} // merge refs
1182
1196
  selected={option.selected}
1183
1197
  onSelect={onSelect}
@@ -0,0 +1,164 @@
1
+ import React, {useLayoutEffect, useRef, useState} from 'react'
2
+ import {Meta} from '@storybook/react'
3
+ import styled from 'styled-components'
4
+
5
+ import {BaseStyles, Box, Checkbox, CheckboxProps, Text, ThemeProvider} from '..'
6
+ import {action} from '@storybook/addon-actions'
7
+ import {COMMON, get} from '../constants'
8
+
9
+ export default {
10
+ title: 'Forms/Checkbox',
11
+ component: Checkbox,
12
+ decorators: [
13
+ Story => {
14
+ return (
15
+ <ThemeProvider>
16
+ <BaseStyles>
17
+ <Box paddingTop={5}>{Story()}</Box>
18
+ </BaseStyles>
19
+ </ThemeProvider>
20
+ )
21
+ }
22
+ ],
23
+ argTypes: {
24
+ sx: {
25
+ table: {
26
+ disable: true
27
+ }
28
+ },
29
+ disabled: {
30
+ name: 'Disabled',
31
+ defaultValue: false,
32
+ control: {
33
+ type: 'boolean'
34
+ }
35
+ }
36
+ }
37
+ } as Meta
38
+
39
+ const StyledLabel = styled.label`
40
+ user-select: none;
41
+ font-weight: 600;
42
+ font-size: 14px;
43
+ line-height: 18px;
44
+ margin-left: 16px;
45
+ ${COMMON}
46
+ `
47
+
48
+ const StyledSubLabel = styled(Text)`
49
+ color: ${get('colors.fg.muted')};
50
+ font-size: 13px;
51
+ ${COMMON}
52
+ `
53
+
54
+ export const Default = (args: CheckboxProps) => {
55
+ const [isChecked, setChecked] = useState<boolean>(false)
56
+
57
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
58
+ setChecked(event.target.checked)
59
+ action('Change event triggered')
60
+ }
61
+
62
+ return (
63
+ <>
64
+ <Box as="form" sx={{p: 3, display: 'flex', alignItems: 'flex-start'}}>
65
+ <Checkbox id="controlled-checkbox" onChange={handleChange} checked={isChecked} {...args} />
66
+ <StyledLabel htmlFor="controlled-checkbox">
67
+ <Text sx={{display: 'block'}}>Default checkbox</Text>
68
+ <StyledSubLabel>controlled</StyledSubLabel>
69
+ </StyledLabel>
70
+ </Box>
71
+ <Box as="form" sx={{p: 3, display: 'flex', alignItems: 'flex-start'}}>
72
+ <Checkbox id="always-checked-checkbox" checked {...args} />
73
+ <StyledLabel htmlFor="always-checked-checkbox">
74
+ <Text sx={{display: 'block'}}>Always checked</Text>
75
+ <StyledSubLabel>checked=&quot;true&quot;</StyledSubLabel>
76
+ </StyledLabel>
77
+ </Box>
78
+ <Box as="form" sx={{p: 3, display: 'flex', alignItems: 'flex-start'}}>
79
+ <Checkbox id="always-unchecked-checkbox" checked={false} {...args} />
80
+ <StyledLabel htmlFor="always-unchecked-checkbox">
81
+ <Text sx={{display: 'block'}}>Always unchecked</Text>
82
+ <StyledSubLabel>checked=&quot;false&quot;</StyledSubLabel>
83
+ </StyledLabel>
84
+ </Box>
85
+ <Box as="form" sx={{p: 3, display: 'flex', alignItems: 'flex-start'}}>
86
+ <Checkbox id="disabled-checkbox" disabled checked={false} />
87
+ <StyledLabel htmlFor="disabled-checkbox">
88
+ <Text sx={{display: 'block'}}>Inactive</Text>
89
+ <StyledSubLabel>disabled=&quot;true&quot;</StyledSubLabel>
90
+ </StyledLabel>
91
+ </Box>
92
+ </>
93
+ )
94
+ }
95
+
96
+ export const Uncontrolled = (args: CheckboxProps) => {
97
+ const checkboxRef = useRef<HTMLInputElement | null>(null)
98
+
99
+ useLayoutEffect(() => {
100
+ if (checkboxRef.current) {
101
+ checkboxRef.current.checked = true
102
+ }
103
+ }, [])
104
+
105
+ return (
106
+ <Box as="form" sx={{p: 3, display: 'flex', alignItems: 'flex-start'}}>
107
+ <Checkbox id="uncontrolled-checkbox" ref={checkboxRef} {...args} />
108
+ <StyledLabel htmlFor="uncontrolled-checkbox">
109
+ <Text sx={{display: 'block'}}>Uncontrolled checkbox</Text>
110
+ <StyledSubLabel>Checked by default</StyledSubLabel>
111
+ </StyledLabel>
112
+ </Box>
113
+ )
114
+ }
115
+
116
+ export const Indeterminate = (args: CheckboxProps) => {
117
+ const [checkboxes, setCheckboxes] = useState<boolean[]>([false, false, false, false])
118
+
119
+ const handleChange = (_: React.ChangeEvent<HTMLInputElement>, index: number) => {
120
+ const newCheckboxes = [...checkboxes]
121
+ newCheckboxes[index] = !checkboxes[index]
122
+ setCheckboxes(newCheckboxes)
123
+ }
124
+
125
+ const handleIndeterminateChange = () => {
126
+ if (checkboxes.every(checkbox => checkbox)) {
127
+ return setCheckboxes(checkboxes.map(() => false))
128
+ }
129
+
130
+ const newCheckboxes = checkboxes.map(() => true)
131
+ setCheckboxes(newCheckboxes)
132
+ }
133
+
134
+ return (
135
+ <>
136
+ <Box as="form" sx={{p: 3, display: 'flex', alignItems: 'flex-start'}}>
137
+ <Checkbox
138
+ id="indeterminate-checkbox"
139
+ checked={checkboxes.every(Boolean)}
140
+ onChange={handleIndeterminateChange}
141
+ indeterminate={!checkboxes.every(Boolean)}
142
+ />
143
+ <StyledLabel htmlFor="controlled-checkbox">
144
+ <Text sx={{display: 'block'}}>Default checkbox</Text>
145
+ <StyledSubLabel>controlled</StyledSubLabel>
146
+ </StyledLabel>
147
+ </Box>
148
+
149
+ {checkboxes.map((field, index) => (
150
+ <Box key={`sub-checkbox-${index}`} as="form" sx={{p: 1, pl: 7, display: 'flex', alignItems: 'flex-start'}}>
151
+ <Checkbox
152
+ id={`sub-checkbox-${index}`}
153
+ checked={checkboxes[index]}
154
+ onChange={event => handleChange(event, index)}
155
+ {...args}
156
+ />
157
+ <StyledLabel htmlFor={`sub-checkbox-${index}`}>
158
+ <Text sx={{display: 'block'}}>Checkbox {index + 1}</Text>
159
+ </StyledLabel>
160
+ </Box>
161
+ ))}
162
+ </>
163
+ )
164
+ }
@@ -3,6 +3,9 @@ import {promisify} from 'util'
3
3
  import renderer from 'react-test-renderer'
4
4
  import enzyme from 'enzyme'
5
5
  import Adapter from '@wojtekmaj/enzyme-adapter-react-17'
6
+ import {cleanup, render as HTMLRender} from '@testing-library/react'
7
+ import {axe, toHaveNoViolations} from 'jest-axe'
8
+ import type {Story as StoryType} from '@storybook/react'
6
9
  import {ThemeProvider} from '..'
7
10
  import {default as defaultTheme} from '../theme'
8
11
 
@@ -240,3 +243,22 @@ export function checkExports(path: string, exports: Record<any, any>): void {
240
243
  expect(mod).toSetExports(exports)
241
244
  })
242
245
  }
246
+
247
+ expect.extend(toHaveNoViolations)
248
+ export function checkStoriesForAxeViolations(name: string) {
249
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
250
+ const stories = require(`../stories/${name}.stories`)
251
+
252
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- _meta
253
+ const {default: _meta, ...Stories} = stories
254
+ Object.values(Stories).map(Story => {
255
+ if (typeof Story !== 'function') return
256
+
257
+ it(`story ${(Story as StoryType).storyName} should have no axe violations`, async () => {
258
+ const {container} = HTMLRender(<Story />)
259
+ const results = await axe(container)
260
+ expect(results).toHaveNoViolations()
261
+ cleanup()
262
+ })
263
+ })
264
+ }