@coreui/react 4.3.0 → 4.4.0

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 (30) hide show
  1. package/README.md +1 -1
  2. package/dist/components/dropdown/CDropdown.d.ts +1 -3
  3. package/dist/components/table/CTable.d.ts +1 -1
  4. package/dist/components/table/CTableDataCell.d.ts +5 -1
  5. package/dist/components/table/CTableResponsiveWrapper.d.ts +9 -0
  6. package/dist/components/table/CTableRow.d.ts +1 -1
  7. package/dist/index.es.js +146 -83
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/index.js +146 -83
  10. package/dist/index.js.map +1 -1
  11. package/package.json +10 -10
  12. package/src/components/alert/__tests__/__snapshots__/CAlert.spec.tsx.snap +1 -0
  13. package/src/components/button/__tests__/__snapshots__/CButtonClose.spec.tsx.snap +2 -0
  14. package/src/components/carousel/CCarousel.tsx +1 -1
  15. package/src/components/close-button/__tests__/__snapshots__/CCloseButton.spec.tsx.snap +2 -0
  16. package/src/components/dropdown/CDropdown.tsx +7 -5
  17. package/src/components/dropdown/CDropdownMenu.tsx +8 -0
  18. package/src/components/dropdown/CDropdownToggle.tsx +1 -1
  19. package/src/components/form/__tests__/__snapshots__/CFormTextarea.spec.tsx.snap +1 -0
  20. package/src/components/modal/CModal.tsx +18 -1
  21. package/src/components/modal/__tests__/__snapshots__/CModalHeader.spec.tsx.snap +2 -0
  22. package/src/components/nav/CNavGroup.tsx +4 -1
  23. package/src/components/sidebar/CSidebarNav.tsx +4 -1
  24. package/src/components/table/CTable.tsx +56 -65
  25. package/src/components/table/CTableDataCell.tsx +5 -1
  26. package/src/components/table/CTableResponsiveWrapper.tsx +39 -0
  27. package/src/components/table/CTableRow.tsx +1 -1
  28. package/src/components/table/__tests__/CTable.spec.tsx +45 -0
  29. package/src/components/table/__tests__/__snapshots__/CTable.spec.tsx.snap +86 -2
  30. package/src/components/toast/CToast.tsx +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreui/react",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "description": "UI Components Library for React.js",
5
5
  "keywords": [
6
6
  "react",
@@ -36,24 +36,24 @@
36
36
  },
37
37
  "devDependencies": {
38
38
  "@popperjs/core": "^2.11.5",
39
- "@rollup/plugin-commonjs": "^22.0.1",
39
+ "@rollup/plugin-commonjs": "^22.0.2",
40
40
  "@rollup/plugin-node-resolve": "^13.3.0",
41
- "@rollup/plugin-typescript": "^8.3.3",
42
- "@testing-library/jest-dom": "^5.16.4",
43
- "@testing-library/react": "^13.3.0",
44
- "@types/react": "18.0.15",
41
+ "@rollup/plugin-typescript": "^8.5.0",
42
+ "@testing-library/jest-dom": "^5.16.5",
43
+ "@testing-library/react": "^13.4.0",
44
+ "@types/react": "18.0.19",
45
45
  "@types/react-dom": "^18.0.6",
46
46
  "@types/react-transition-group": "^4.4.5",
47
- "classnames": "^2.3.1",
47
+ "classnames": "^2.3.2",
48
48
  "prop-types": "^15.8.1",
49
49
  "react": "^18.2.0",
50
50
  "react-dom": "^18.2.0",
51
51
  "react-popper": "^2.2.5",
52
- "react-transition-group": "^4.4.2",
53
- "rollup": "^2.75.7",
52
+ "react-transition-group": "^4.4.5",
53
+ "rollup": "^2.79.0",
54
54
  "rollup-plugin-peer-deps-external": "^2.2.4",
55
55
  "tslib": "^2.4.0",
56
- "typescript": "^4.7.4"
56
+ "typescript": "^4.8.3"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "react": ">=17",
@@ -10,6 +10,7 @@ exports[`CAlert customize 1`] = `
10
10
  <button
11
11
  aria-label="Close"
12
12
  class="btn btn-close"
13
+ type="button"
13
14
  />
14
15
  </div>
15
16
  </div>
@@ -6,6 +6,7 @@ exports[`CCloseButton customize 1`] = `
6
6
  aria-label="Close"
7
7
  class="btn btn-close btn-close-white bazinga"
8
8
  disabled=""
9
+ type="button"
9
10
  >
10
11
  Test
11
12
  </button>
@@ -17,6 +18,7 @@ exports[`loads and displays CCloseButton component 1`] = `
17
18
  <button
18
19
  aria-label="Close"
19
20
  class="btn btn-close"
21
+ type="button"
20
22
  >
21
23
  Test
22
24
  </button>
@@ -235,7 +235,7 @@ export const CCarousel = forwardRef<HTMLDivElement, CCarouselProps>(
235
235
  <div className="carousel-inner">
236
236
  {Children.map(children, (child, index) => {
237
237
  if (React.isValidElement(child)) {
238
- return React.cloneElement(child, {
238
+ return React.cloneElement(child as React.ReactElement<any>, {
239
239
  active: active === index ? true : false,
240
240
  direction: direction,
241
241
  key: index,
@@ -6,6 +6,7 @@ exports[`CCloseButton customize 1`] = `
6
6
  aria-label="Close"
7
7
  class="btn btn-close btn-close-white bazinga"
8
8
  disabled=""
9
+ type="button"
9
10
  />
10
11
  </div>
11
12
  `;
@@ -15,6 +16,7 @@ exports[`loads and displays CCloseButton component 1`] = `
15
16
  <button
16
17
  aria-label="Close"
17
18
  class="btn btn-close"
19
+ type="button"
18
20
  />
19
21
  </div>
20
22
  `;
@@ -56,10 +56,8 @@ export interface CDropdownProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
56
56
  dark?: boolean
57
57
  /**
58
58
  * Sets a specified direction and location of the dropdown menu.
59
- *
60
- * @type 'dropup' | 'dropend' | 'dropstart'
61
59
  */
62
- direction?: 'dropup' | 'dropend' | 'dropstart'
60
+ direction?: 'center' | 'dropup' | 'dropup-center' | 'dropend' | 'dropstart'
63
61
  /**
64
62
  * Callback fired when the component requests to be hidden.
65
63
  */
@@ -146,7 +144,11 @@ export const CDropdown = forwardRef<HTMLDivElement | HTMLLIElement, CDropdownPro
146
144
  {
147
145
  show: _visible,
148
146
  },
149
- direction,
147
+ direction === 'center'
148
+ ? 'dropdown-center'
149
+ : direction === 'dropup-center'
150
+ ? 'dropup dropup-center'
151
+ : direction,
150
152
  className,
151
153
  )
152
154
 
@@ -202,7 +204,7 @@ CDropdown.propTypes = {
202
204
  className: PropTypes.string,
203
205
  component: PropTypes.elementType,
204
206
  dark: PropTypes.bool,
205
- direction: PropTypes.oneOf(['dropup', 'dropend', 'dropstart']),
207
+ direction: PropTypes.oneOf(['center', 'dropup', 'dropup-center', 'dropend', 'dropstart']),
206
208
  onHide: PropTypes.func,
207
209
  onShow: PropTypes.func,
208
210
  placement: placementPropType,
@@ -86,10 +86,18 @@ export const CDropdownMenu: FC<CDropdownMenuProps> = ({
86
86
 
87
87
  let _placement: Placements = placement
88
88
 
89
+ if (direction === 'center') {
90
+ _placement = 'bottom'
91
+ }
92
+
89
93
  if (direction === 'dropup') {
90
94
  _placement = 'top-start'
91
95
  }
92
96
 
97
+ if (direction === 'dropup-center') {
98
+ _placement = 'top'
99
+ }
100
+
93
101
  if (direction === 'dropend') {
94
102
  _placement = 'right-start'
95
103
  }
@@ -75,7 +75,7 @@ export const CDropdownToggle: FC<CDropdownToggleProps> = ({
75
75
  const Toggler = (ref?: React.Ref<any>) => {
76
76
  return custom && React.isValidElement(children) ? (
77
77
  <>
78
- {React.cloneElement(children, {
78
+ {React.cloneElement(children as React.ReactElement<any>, {
79
79
  'aria-expanded': visible,
80
80
  ...(!rest.disabled && { ...triggers }),
81
81
  ref: useForkedRef(ref, dropdownToggleRef),
@@ -6,6 +6,7 @@ exports[`CFormTextarea customize 1`] = `
6
6
  class="form-control-plaintext is-invalid is-valid bazinga"
7
7
  disabled=""
8
8
  readonly=""
9
+ rows="2"
9
10
  >
10
11
  Some value
11
12
  </textarea>
@@ -171,6 +171,12 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
171
171
  useLayoutEffect(() => {
172
172
  if (_visible) {
173
173
  document.body.classList.add('modal-open')
174
+
175
+ if (backdrop) {
176
+ document.body.style.overflow = 'hidden'
177
+ document.body.style.paddingRight = '0px'
178
+ }
179
+
174
180
  setTimeout(
175
181
  () => {
176
182
  modalRef.current?.focus()
@@ -179,8 +185,19 @@ export const CModal = forwardRef<HTMLDivElement, CModalProps>(
179
185
  )
180
186
  } else {
181
187
  document.body.classList.remove('modal-open')
188
+
189
+ if (backdrop) {
190
+ document.body.style.removeProperty('overflow')
191
+ document.body.style.removeProperty('padding-right')
192
+ }
193
+ }
194
+ return () => {
195
+ document.body.classList.remove('modal-open')
196
+ if (backdrop) {
197
+ document.body.style.removeProperty('overflow')
198
+ document.body.style.removeProperty('padding-right')
199
+ }
182
200
  }
183
- return () => document.body.classList.remove('modal-open')
184
201
  }, [_visible])
185
202
 
186
203
  const handleClickOutside = (event: Event) => {
@@ -9,6 +9,7 @@ exports[`CModalHeader customize 1`] = `
9
9
  <button
10
10
  aria-label="Close"
11
11
  class="btn btn-close"
12
+ type="button"
12
13
  />
13
14
  </div>
14
15
  </div>
@@ -23,6 +24,7 @@ exports[`loads and displays CModalHeader component 1`] = `
23
24
  <button
24
25
  aria-label="Close"
25
26
  class="btn btn-close"
27
+ type="button"
26
28
  />
27
29
  </div>
28
30
  </div>
@@ -124,7 +124,10 @@ export const CNavGroup = forwardRef<HTMLLIElement, CNavGroupProps>(
124
124
  >
125
125
  {React.Children.map(children, (child, index) => {
126
126
  if (React.isValidElement(child)) {
127
- return React.cloneElement(child, { key: index, idx: `${idx}.${index}` })
127
+ return React.cloneElement(child as React.ReactElement<any>, {
128
+ key: index,
129
+ idx: `${idx}.${index}`,
130
+ })
128
131
  }
129
132
  return
130
133
  })}
@@ -29,7 +29,10 @@ export const CSidebarNav = forwardRef<HTMLUListElement, CSidebarNavProps>(
29
29
  <CNavContext.Provider value={CNavContextValues}>
30
30
  {React.Children.map(children, (child, index) => {
31
31
  if (React.isValidElement(child)) {
32
- return React.cloneElement(child, { key: index, idx: `${index}` })
32
+ return React.cloneElement(child as React.ReactElement<any>, {
33
+ key: index,
34
+ idx: `${index}`,
35
+ })
33
36
  }
34
37
  return
35
38
  })}
@@ -10,12 +10,13 @@ import { CTableDataCell, CTableDataCellProps } from './CTableDataCell'
10
10
  import { CTableRow, CTableRowProps } from './CTableRow'
11
11
  import { CTableFoot, CTableFootProps } from './CTableFoot'
12
12
  import { CTableCaption } from './CTableCaption'
13
+ import { CTableResponsiveWrapper } from './CTableResponsiveWrapper'
13
14
 
14
15
  export interface CTableProps extends Omit<TableHTMLAttributes<HTMLTableElement>, 'align'> {
15
16
  /**
16
17
  * Set the vertical aligment.
17
18
  */
18
- align?: 'bottom' | 'middle' | 'top'
19
+ align?: 'bottom' | 'middle' | 'top' | string
19
20
  /**
20
21
  * Sets the border color of the component to one of CoreUI’s themed colors.
21
22
  *
@@ -206,72 +207,62 @@ export const CTable = forwardRef<HTMLTableElement, CTableProps>(
206
207
  : pretifyName(column.key)
207
208
  : pretifyName(column)
208
209
 
209
- const Table = () => (
210
- <table className={_className} {...rest} ref={ref}>
211
- {((caption && caption !== 'top') || captionTop) && (
212
- <CTableCaption>{caption || captionTop}</CTableCaption>
213
- )}
214
- {columns && (
215
- <CTableHead {...tableHeadProps}>
216
- <CTableRow>
217
- {columns.map((column: Column, index: number) => (
218
- <CTableHeaderCell
219
- {...(column._props && { ...column._props })}
220
- {...(column._style && { style: { ...column._style } })}
221
- key={index}
222
- >
223
- {label(column)}
224
- </CTableHeaderCell>
225
- ))}
226
- </CTableRow>
227
- </CTableHead>
228
- )}
229
- {items && (
230
- <CTableBody>
231
- {items.map((item: Item, index: number) => (
232
- <CTableRow {...(item._props && { ...item._props })} key={index}>
233
- {rawColumnNames.map((colName: string, index: number) => {
234
- return item[colName] ? (
235
- <CTableDataCell
236
- {...(item._cellProps && {
237
- ...(item._cellProps['all'] && { ...item._cellProps['all'] }),
238
- ...(item._cellProps[colName] && { ...item._cellProps[colName] }),
239
- })}
240
- key={index}
241
- >
242
- {item[colName]}
243
- </CTableDataCell>
244
- ) : null
245
- })}
210
+ return (
211
+ <CTableResponsiveWrapper responsive={responsive}>
212
+ <table className={_className} {...rest} ref={ref}>
213
+ {((caption && caption !== 'top') || captionTop) && (
214
+ <CTableCaption>{caption || captionTop}</CTableCaption>
215
+ )}
216
+ {columns && (
217
+ <CTableHead {...tableHeadProps}>
218
+ <CTableRow>
219
+ {columns.map((column: Column, index: number) => (
220
+ <CTableHeaderCell
221
+ {...(column._props && { ...column._props })}
222
+ {...(column._style && { style: { ...column._style } })}
223
+ key={index}
224
+ >
225
+ {label(column)}
226
+ </CTableHeaderCell>
227
+ ))}
246
228
  </CTableRow>
247
- ))}
248
- </CTableBody>
249
- )}
250
- {children}
251
- {footer && (
252
- <CTableFoot {...tableFootProps}>
253
- <CTableRow>
254
- {footer.map((item: FooterItem, index: number) => (
255
- <CTableDataCell {...(item._props && { ...item._props })} key={index}>
256
- {typeof item === 'object' ? item.label : item}
257
- </CTableDataCell>
229
+ </CTableHead>
230
+ )}
231
+ {items && (
232
+ <CTableBody>
233
+ {items.map((item: Item, index: number) => (
234
+ <CTableRow {...(item._props && { ...item._props })} key={index}>
235
+ {rawColumnNames.map((colName: string, index: number) => {
236
+ return item[colName] ? (
237
+ <CTableDataCell
238
+ {...(item._cellProps && {
239
+ ...(item._cellProps['all'] && { ...item._cellProps['all'] }),
240
+ ...(item._cellProps[colName] && { ...item._cellProps[colName] }),
241
+ })}
242
+ key={index}
243
+ >
244
+ {item[colName]}
245
+ </CTableDataCell>
246
+ ) : null
247
+ })}
248
+ </CTableRow>
258
249
  ))}
259
- </CTableRow>
260
- </CTableFoot>
261
- )}
262
- </table>
263
- )
264
-
265
- return responsive ? (
266
- <div
267
- className={
268
- typeof responsive === 'boolean' ? 'table-responsive' : `table-responsive-${responsive}`
269
- }
270
- >
271
- <Table />
272
- </div>
273
- ) : (
274
- <Table />
250
+ </CTableBody>
251
+ )}
252
+ {children}
253
+ {footer && (
254
+ <CTableFoot {...tableFootProps}>
255
+ <CTableRow>
256
+ {footer.map((item: FooterItem, index: number) => (
257
+ <CTableDataCell {...(item._props && { ...item._props })} key={index}>
258
+ {typeof item === 'object' ? item.label : item}
259
+ </CTableDataCell>
260
+ ))}
261
+ </CTableRow>
262
+ </CTableFoot>
263
+ )}
264
+ </table>
265
+ </CTableResponsiveWrapper>
275
266
  )
276
267
  },
277
268
  )
@@ -14,7 +14,7 @@ export interface CTableDataCellProps
14
14
  /**
15
15
  * Set the vertical aligment.
16
16
  */
17
- align?: 'bottom' | 'middle' | 'top'
17
+ align?: 'bottom' | 'middle' | 'top' | string
18
18
  /**
19
19
  * A string of all className you want applied to the component.
20
20
  */
@@ -25,6 +25,10 @@ export interface CTableDataCellProps
25
25
  * @type 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'dark' | 'light' | string
26
26
  */
27
27
  color?: Colors
28
+ /**
29
+ * @ignore
30
+ */
31
+ colSpan?: number
28
32
  }
29
33
 
30
34
  export const CTableDataCell = forwardRef<HTMLTableCellElement, CTableDataCellProps>(
@@ -0,0 +1,39 @@
1
+ import React, { FC, HTMLAttributes } from 'react'
2
+ import PropTypes from 'prop-types'
3
+
4
+ export interface CTableResponsiveWrapperProps extends HTMLAttributes<HTMLDivElement> {
5
+ children: any
6
+ /**
7
+ * Make any table responsive across all viewports or pick a maximum breakpoint with which to have a responsive table up to.
8
+ */
9
+ responsive?: boolean | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'
10
+ }
11
+
12
+ export const CTableResponsiveWrapper: FC<CTableResponsiveWrapperProps> = ({
13
+ children,
14
+ responsive,
15
+ ...rest
16
+ }) => {
17
+ return responsive ? (
18
+ <div
19
+ className={
20
+ typeof responsive === 'boolean' ? 'table-responsive' : `table-responsive-${responsive}`
21
+ }
22
+ {...rest}
23
+ >
24
+ {children}
25
+ </div>
26
+ ) : (
27
+ children
28
+ )
29
+ }
30
+
31
+ CTableResponsiveWrapper.propTypes = {
32
+ children: PropTypes.any,
33
+ responsive: PropTypes.oneOfType([
34
+ PropTypes.bool,
35
+ PropTypes.oneOf<'sm' | 'md' | 'lg' | 'xl' | 'xxl'>(['sm', 'md', 'lg', 'xl', 'xxl']),
36
+ ]),
37
+ }
38
+
39
+ CTableResponsiveWrapper.displayName = 'CTableResponsiveWrapper'
@@ -12,7 +12,7 @@ export interface CTableRowProps extends HTMLAttributes<HTMLTableRowElement> {
12
12
  /**
13
13
  * Set the vertical aligment.
14
14
  */
15
- align?: 'bottom' | 'middle' | 'top'
15
+ align?: 'bottom' | 'middle' | 'top' | string
16
16
  /**
17
17
  * A string of all className you want applied to the component.
18
18
  */
@@ -17,6 +17,51 @@ test('loads and displays CTable component', async () => {
17
17
  expect(container).toMatchSnapshot()
18
18
  })
19
19
 
20
+ test('loads and displays CTable component - new way', async () => {
21
+ const columns = [
22
+ {
23
+ key: 'id',
24
+ label: '#',
25
+ _props: { scope: 'col' },
26
+ },
27
+ 'class',
28
+ {
29
+ key: 'heading_1',
30
+ label: 'Heading',
31
+ _props: { scope: 'col' },
32
+ },
33
+ {
34
+ key: 'heading_2',
35
+ label: 'Heading',
36
+ _props: { scope: 'col' },
37
+ },
38
+ ]
39
+ const items = [
40
+ {
41
+ id: 1,
42
+ class: 'Mark',
43
+ heading_1: 'Otto',
44
+ heading_2: '@mdo',
45
+ _cellProps: { id: { scope: 'row' } },
46
+ },
47
+ {
48
+ id: 2,
49
+ class: 'Jacob',
50
+ heading_1: 'Thornton',
51
+ heading_2: '@fat',
52
+ _cellProps: { id: { scope: 'row' } },
53
+ },
54
+ {
55
+ id: 3,
56
+ class: 'Larry the Bird',
57
+ heading_2: '@twitter',
58
+ _cellProps: { id: { scope: 'row' }, class: { colSpan: 2 } },
59
+ },
60
+ ]
61
+ const { container } = render(<CTable columns={columns} items={items} />)
62
+ expect(container).toMatchSnapshot()
63
+ })
64
+
20
65
  test('CTable customize', async () => {
21
66
  const { container } = render(
22
67
  <CTable
@@ -6,8 +6,9 @@ exports[`CTable customize 1`] = `
6
6
  class="table-responsive-xl"
7
7
  >
8
8
  <table
9
- class="table align-middle caption-top border-primary table-bordered table-borderless table-info table-hover table-sm table-striped bazinga"
9
+ class="table align-middle border-primary caption-top table-bordered table-borderless table-info table-hover table-sm table-striped bazinga"
10
10
  >
11
+ <tbody />
11
12
  <tbody>
12
13
  <tr>
13
14
  <td>
@@ -25,6 +26,7 @@ exports[`CTable full example test 1`] = `
25
26
  <table
26
27
  class="table caption-top"
27
28
  >
29
+ <tbody />
28
30
  <caption>
29
31
  List of users
30
32
  </caption>
@@ -108,10 +110,92 @@ exports[`CTable full example test 1`] = `
108
110
  </div>
109
111
  `;
110
112
 
113
+ exports[`loads and displays CTable component - new way 1`] = `
114
+ <div>
115
+ <table
116
+ class="table"
117
+ >
118
+ <thead>
119
+ <tr>
120
+ <th
121
+ scope="col"
122
+ >
123
+ #
124
+ </th>
125
+ <th>
126
+ Class
127
+ </th>
128
+ <th
129
+ scope="col"
130
+ >
131
+ Heading
132
+ </th>
133
+ <th
134
+ scope="col"
135
+ >
136
+ Heading
137
+ </th>
138
+ </tr>
139
+ </thead>
140
+ <tbody>
141
+ <tr>
142
+ <th
143
+ scope="row"
144
+ >
145
+ 1
146
+ </th>
147
+ <td>
148
+ Mark
149
+ </td>
150
+ <td>
151
+ Otto
152
+ </td>
153
+ <td>
154
+ @mdo
155
+ </td>
156
+ </tr>
157
+ <tr>
158
+ <th
159
+ scope="row"
160
+ >
161
+ 2
162
+ </th>
163
+ <td>
164
+ Jacob
165
+ </td>
166
+ <td>
167
+ Thornton
168
+ </td>
169
+ <td>
170
+ @fat
171
+ </td>
172
+ </tr>
173
+ <tr>
174
+ <th
175
+ scope="row"
176
+ >
177
+ 3
178
+ </th>
179
+ <td
180
+ colspan="2"
181
+ >
182
+ Larry the Bird
183
+ </td>
184
+ <td>
185
+ @twitter
186
+ </td>
187
+ </tr>
188
+ </tbody>
189
+ </table>
190
+ </div>
191
+ `;
192
+
111
193
  exports[`loads and displays CTable component 1`] = `
112
194
  <div>
113
195
  <table
114
196
  class="table"
115
- />
197
+ >
198
+ <tbody />
199
+ </table>
116
200
  </div>
117
201
  `;
@@ -153,7 +153,7 @@ export const CToast = forwardRef<HTMLDivElement, CToastProps>(
153
153
  aria-atomic="true"
154
154
  role="alert"
155
155
  onMouseEnter={() => clearTimeout(timeout.current)}
156
- onMouseLeave={() => _autohide}
156
+ onMouseLeave={() => _autohide()}
157
157
  {...rest}
158
158
  key={key}
159
159
  ref={forkedRef}