@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
@@ -1,11 +1,12 @@
1
- import {cleanup, render as HTMLRender} from '@testing-library/react'
1
+ import {cleanup, render as HTMLRender, waitFor, fireEvent} from '@testing-library/react'
2
2
  import 'babel-polyfill'
3
3
  import {axe, toHaveNoViolations} from 'jest-axe'
4
4
  import React from 'react'
5
5
  import theme from '../theme'
6
6
  import {ActionList} from '../ActionList2'
7
- import {behavesAsComponent, checkExports} from '../utils/testing'
7
+ import {behavesAsComponent, checkExports, checkStoriesForAxeViolations} from '../utils/testing'
8
8
  import {BaseStyles, ThemeProvider, SSRProvider} from '..'
9
+ import '@testing-library/jest-dom'
9
10
  expect.extend(toHaveNoViolations)
10
11
 
11
12
  function SimpleActionList(): JSX.Element {
@@ -26,6 +27,31 @@ function SimpleActionList(): JSX.Element {
26
27
  )
27
28
  }
28
29
 
30
+ const projects = [
31
+ {name: 'Primer Backlog', scope: 'GitHub'},
32
+ {name: 'Primer React', scope: 'github/primer'},
33
+ {name: 'Disabled Project', scope: 'github/primer', disabled: true}
34
+ ]
35
+ function SingleSelectListStory(): JSX.Element {
36
+ const [selectedIndex, setSelectedIndex] = React.useState(0)
37
+
38
+ return (
39
+ <ActionList selectionVariant="single" showDividers role="listbox" aria-label="Select a project">
40
+ {projects.map((project, index) => (
41
+ <ActionList.Item
42
+ key={index}
43
+ role="option"
44
+ selected={index === selectedIndex}
45
+ onSelect={() => setSelectedIndex(index)}
46
+ disabled={project.disabled}
47
+ >
48
+ {project.name}
49
+ </ActionList.Item>
50
+ ))}
51
+ </ActionList>
52
+ )
53
+ }
54
+
29
55
  describe('ActionList', () => {
30
56
  behavesAsComponent({
31
57
  Component: ActionList,
@@ -44,4 +70,87 @@ describe('ActionList', () => {
44
70
  expect(results).toHaveNoViolations()
45
71
  cleanup()
46
72
  })
73
+
74
+ it('should fire onSelect on click and keypress', async () => {
75
+ const component = HTMLRender(<SingleSelectListStory />)
76
+ const options = await waitFor(() => component.getAllByRole('option'))
77
+
78
+ expect(options[0]).toHaveAttribute('aria-selected', 'true')
79
+ expect(options[1]).toHaveAttribute('aria-selected', 'false')
80
+
81
+ fireEvent.click(options[1])
82
+
83
+ expect(options[0]).toHaveAttribute('aria-selected', 'false')
84
+ expect(options[1]).toHaveAttribute('aria-selected', 'true')
85
+
86
+ // We pass keycode here to navigate a implementation detail in react-testing-library
87
+ // https://github.com/testing-library/react-testing-library/issues/269#issuecomment-455854112
88
+ fireEvent.keyPress(options[0], {key: 'Enter', charCode: 13})
89
+
90
+ expect(options[0]).toHaveAttribute('aria-selected', 'true')
91
+ expect(options[1]).toHaveAttribute('aria-selected', 'false')
92
+
93
+ fireEvent.keyPress(options[1], {key: ' ', charCode: 32})
94
+
95
+ expect(options[0]).toHaveAttribute('aria-selected', 'false')
96
+ expect(options[1]).toHaveAttribute('aria-selected', 'true')
97
+
98
+ cleanup()
99
+ })
100
+
101
+ it('should skip onSelect on disabled items', async () => {
102
+ const component = HTMLRender(<SingleSelectListStory />)
103
+ const options = await waitFor(() => component.getAllByRole('option'))
104
+
105
+ expect(options[0]).toHaveAttribute('aria-selected', 'true')
106
+ expect(options[2]).toHaveAttribute('aria-selected', 'false')
107
+
108
+ fireEvent.click(options[2])
109
+
110
+ expect(options[0]).toHaveAttribute('aria-selected', 'true')
111
+ expect(options[2]).toHaveAttribute('aria-selected', 'false')
112
+
113
+ fireEvent.keyPress(options[2], {key: 'Enter', charCode: 13})
114
+
115
+ expect(options[0]).toHaveAttribute('aria-selected', 'true')
116
+ expect(options[2]).toHaveAttribute('aria-selected', 'false')
117
+
118
+ cleanup()
119
+ })
120
+
121
+ it('should throw when selected is provided without a selectionVariant on parent', async () => {
122
+ // we expect console.error to be called, so we suppress that in the test
123
+ const mockError = jest.spyOn(console, 'error').mockImplementation(() => jest.fn())
124
+
125
+ expect(() => {
126
+ HTMLRender(
127
+ <ActionList showDividers role="listbox" aria-label="Select a project">
128
+ <ActionList.Item role="option" selected={true}>
129
+ Primer React
130
+ </ActionList.Item>
131
+ </ActionList>
132
+ )
133
+ }).toThrow('For Item to be selected, ActionList or ActionList.Group needs to have a selectionVariant defined')
134
+
135
+ cleanup()
136
+ mockError.mockRestore()
137
+ })
138
+
139
+ it('should not crash when clicking an item without an onSelect', async () => {
140
+ const component = HTMLRender(
141
+ <ActionList role="listbox">
142
+ <ActionList.Item role="option">Primer React</ActionList.Item>
143
+ </ActionList>
144
+ )
145
+ const option = await waitFor(() => component.getByRole('option'))
146
+ expect(option).toBeInTheDocument()
147
+
148
+ fireEvent.click(option)
149
+ fireEvent.keyPress(option, {key: 'Enter', charCode: 13})
150
+ expect(option).toBeInTheDocument()
151
+
152
+ cleanup()
153
+ })
154
+
155
+ checkStoriesForAxeViolations('ActionList2')
47
156
  })
@@ -0,0 +1,155 @@
1
+ import React from 'react'
2
+ import {Checkbox} from '..'
3
+ import {behavesAsComponent, checkExports} from '../utils/testing'
4
+ import {render, cleanup} from '@testing-library/react'
5
+ import {toHaveNoViolations} from 'jest-axe'
6
+ import 'babel-polyfill'
7
+ import '@testing-library/jest-dom'
8
+ import userEvent from '@testing-library/user-event'
9
+
10
+ expect.extend(toHaveNoViolations)
11
+
12
+ describe('Checkbox', () => {
13
+ beforeEach(() => {
14
+ jest.resetAllMocks()
15
+ cleanup()
16
+ })
17
+ behavesAsComponent({Component: Checkbox})
18
+
19
+ checkExports('Checkbox', {
20
+ default: Checkbox
21
+ })
22
+
23
+ it('renders a valid checkbox input', () => {
24
+ const {getByRole} = render(<Checkbox />)
25
+
26
+ const checkbox = getByRole('checkbox')
27
+
28
+ expect(checkbox).toBeDefined()
29
+ })
30
+
31
+ it('renders an unchecked checkbox by default', () => {
32
+ const {getByRole} = render(<Checkbox />)
33
+
34
+ const checkbox = getByRole('checkbox') as HTMLInputElement
35
+
36
+ expect(checkbox.checked).toEqual(false)
37
+ })
38
+
39
+ it('renders an active checkbox when checked attribute is passed', () => {
40
+ const handleChange = jest.fn()
41
+ const {getByRole} = render(<Checkbox checked onChange={handleChange} />)
42
+
43
+ const checkbox = getByRole('checkbox') as HTMLInputElement
44
+
45
+ expect(checkbox.checked).toEqual(true)
46
+ })
47
+
48
+ it('accepts a change handler that can alter the checkbox state', () => {
49
+ const handleChange = jest.fn()
50
+ const {getByRole} = render(<Checkbox onChange={handleChange} />)
51
+
52
+ const checkbox = getByRole('checkbox') as HTMLInputElement
53
+
54
+ expect(checkbox.checked).toEqual(false)
55
+
56
+ userEvent.click(checkbox)
57
+ expect(handleChange).toHaveBeenCalled()
58
+ expect(checkbox.checked).toEqual(true)
59
+
60
+ userEvent.click(checkbox)
61
+ expect(handleChange).toHaveBeenCalled()
62
+ expect(checkbox.checked).toEqual(false)
63
+ })
64
+
65
+ it('renders an indeterminate prop correctly', () => {
66
+ const handleChange = jest.fn()
67
+ const {getByRole} = render(<Checkbox indeterminate checked onChange={handleChange} />)
68
+
69
+ const checkbox = getByRole('checkbox') as HTMLInputElement
70
+
71
+ expect(checkbox.indeterminate).toEqual(true)
72
+ expect(checkbox.checked).toEqual(false)
73
+ })
74
+
75
+ it('renders an inactive checkbox state correctly', () => {
76
+ const handleChange = jest.fn()
77
+ const {getByRole, rerender} = render(<Checkbox disabled onChange={handleChange} />)
78
+
79
+ const checkbox = getByRole('checkbox') as HTMLInputElement
80
+
81
+ expect(checkbox.disabled).toEqual(true)
82
+ expect(checkbox.checked).toEqual(false)
83
+ expect(checkbox).toHaveAttribute('aria-disabled', 'true')
84
+
85
+ userEvent.click(checkbox)
86
+
87
+ expect(checkbox.disabled).toEqual(true)
88
+ expect(checkbox.checked).toEqual(false)
89
+ expect(checkbox).toHaveAttribute('aria-disabled', 'true')
90
+
91
+ // remove disabled attribute and retest
92
+ rerender(<Checkbox onChange={handleChange} />)
93
+
94
+ expect(checkbox).toHaveAttribute('aria-disabled', 'false')
95
+ })
96
+
97
+ it('renders an uncontrolled component correctly', () => {
98
+ const {getByRole} = render(<Checkbox defaultChecked />)
99
+
100
+ const checkbox = getByRole('checkbox') as HTMLInputElement
101
+
102
+ expect(checkbox.checked).toEqual(true)
103
+
104
+ userEvent.click(checkbox)
105
+
106
+ expect(checkbox.checked).toEqual(false)
107
+ })
108
+
109
+ it('renders an aria-checked attribute correctly', () => {
110
+ const handleChange = jest.fn()
111
+ const {getByRole, rerender} = render(<Checkbox checked={false} onChange={handleChange} />)
112
+
113
+ const checkbox = getByRole('checkbox') as HTMLInputElement
114
+
115
+ expect(checkbox).toHaveAttribute('aria-checked', 'false')
116
+
117
+ rerender(<Checkbox checked={true} onChange={handleChange} />)
118
+
119
+ expect(checkbox).toHaveAttribute('aria-checked', 'true')
120
+
121
+ rerender(<Checkbox indeterminate checked onChange={handleChange} />)
122
+
123
+ expect(checkbox).toHaveAttribute('aria-checked', 'mixed')
124
+ })
125
+
126
+ it('renders an invalid aria state when validation prop indicates an error', () => {
127
+ const handleChange = jest.fn()
128
+ const {getByRole, rerender} = render(<Checkbox onChange={handleChange} />)
129
+
130
+ const checkbox = getByRole('checkbox') as HTMLInputElement
131
+
132
+ expect(checkbox).toHaveAttribute('aria-invalid', 'false')
133
+
134
+ rerender(<Checkbox onChange={handleChange} validationStatus="success" />)
135
+
136
+ expect(checkbox).toHaveAttribute('aria-invalid', 'false')
137
+
138
+ rerender(<Checkbox onChange={handleChange} validationStatus="error" />)
139
+
140
+ expect(checkbox).toHaveAttribute('aria-invalid', 'true')
141
+ })
142
+
143
+ it('renders an aria state indicating the field is required', () => {
144
+ const handleChange = jest.fn()
145
+ const {getByRole, rerender} = render(<Checkbox onChange={handleChange} />)
146
+
147
+ const checkbox = getByRole('checkbox') as HTMLInputElement
148
+
149
+ expect(checkbox).toHaveAttribute('aria-required', 'false')
150
+
151
+ rerender(<Checkbox onChange={handleChange} required />)
152
+
153
+ expect(checkbox).toHaveAttribute('aria-required', 'true')
154
+ })
155
+ })
@@ -468,6 +468,9 @@ Array [
468
468
  -webkit-box-align: center;
469
469
  -ms-flex-align: center;
470
470
  align-items: center;
471
+ -webkit-flex-shrink: 0;
472
+ -ms-flex-negative: 0;
473
+ flex-shrink: 0;
471
474
  }
472
475
 
473
476
  .c10 {
@@ -510,6 +513,7 @@ Array [
510
513
  .c6 rect {
511
514
  fill: #ffffff;
512
515
  stroke: #d0d7de;
516
+ shape-rendering: auto;
513
517
  }
514
518
 
515
519
  .c6 path {
@@ -1375,11 +1379,15 @@ Array [
1375
1379
  -webkit-box-align: center;
1376
1380
  -ms-flex-align: center;
1377
1381
  align-items: center;
1382
+ -webkit-flex-shrink: 0;
1383
+ -ms-flex-negative: 0;
1384
+ flex-shrink: 0;
1378
1385
  }
1379
1386
 
1380
1387
  .c6 rect {
1381
1388
  fill: #ffffff;
1382
1389
  stroke: #d0d7de;
1390
+ shape-rendering: auto;
1383
1391
  }
1384
1392
 
1385
1393
  .c6 path {
@@ -2192,11 +2200,15 @@ Array [
2192
2200
  -webkit-box-align: center;
2193
2201
  -ms-flex-align: center;
2194
2202
  align-items: center;
2203
+ -webkit-flex-shrink: 0;
2204
+ -ms-flex-negative: 0;
2205
+ flex-shrink: 0;
2195
2206
  }
2196
2207
 
2197
2208
  .c10 rect {
2198
2209
  fill: #ffffff;
2199
2210
  stroke: #d0d7de;
2211
+ shape-rendering: auto;
2200
2212
  }
2201
2213
 
2202
2214
  .c10 path {
@@ -2207,6 +2219,7 @@ Array [
2207
2219
  .c6 rect {
2208
2220
  fill: #0969da;
2209
2221
  stroke: #0969da;
2222
+ shape-rendering: auto;
2210
2223
  }
2211
2224
 
2212
2225
  .c6 path {
@@ -0,0 +1,16 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Checkbox 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="checkbox"
15
+ />
16
+ `;