@instructure/ui-table 9.7.0 → 9.8.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 (97) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/es/Table/Body/index.js +24 -11
  3. package/es/Table/Body/props.js +2 -5
  4. package/es/Table/Body/styles.js +0 -2
  5. package/es/Table/Cell/index.js +3 -2
  6. package/es/Table/Cell/props.js +1 -2
  7. package/es/Table/ColHeader/props.js +2 -1
  8. package/es/Table/Head/index.js +40 -30
  9. package/es/Table/Head/props.js +1 -2
  10. package/es/Table/Head/styles.js +0 -2
  11. package/es/Table/Row/index.js +25 -12
  12. package/es/Table/Row/props.js +2 -5
  13. package/es/Table/Row/styles.js +4 -6
  14. package/es/Table/RowHeader/index.js +3 -2
  15. package/es/Table/RowHeader/props.js +1 -2
  16. package/es/Table/TableContext.js +34 -0
  17. package/es/Table/__new-tests__/Table.test.js +74 -1
  18. package/es/Table/index.js +25 -17
  19. package/es/index.js +2 -1
  20. package/lib/Table/Body/index.js +23 -10
  21. package/lib/Table/Body/props.js +2 -5
  22. package/lib/Table/Body/styles.js +0 -2
  23. package/lib/Table/Cell/index.js +3 -2
  24. package/lib/Table/Cell/props.js +1 -2
  25. package/lib/Table/ColHeader/props.js +2 -1
  26. package/lib/Table/Head/index.js +39 -30
  27. package/lib/Table/Head/props.js +1 -2
  28. package/lib/Table/Head/styles.js +0 -2
  29. package/lib/Table/Row/index.js +24 -11
  30. package/lib/Table/Row/props.js +2 -5
  31. package/lib/Table/Row/styles.js +4 -6
  32. package/lib/Table/RowHeader/index.js +3 -2
  33. package/lib/Table/RowHeader/props.js +1 -2
  34. package/lib/Table/TableContext.js +39 -0
  35. package/lib/Table/__new-tests__/Table.test.js +74 -1
  36. package/lib/Table/index.js +24 -16
  37. package/lib/index.js +8 -1
  38. package/package.json +17 -17
  39. package/src/Table/Body/index.tsx +23 -13
  40. package/src/Table/Body/props.ts +6 -18
  41. package/src/Table/Body/styles.ts +0 -2
  42. package/src/Table/Cell/index.tsx +6 -3
  43. package/src/Table/Cell/props.ts +7 -9
  44. package/src/Table/ColHeader/props.ts +9 -3
  45. package/src/Table/Head/index.tsx +40 -40
  46. package/src/Table/Head/props.ts +20 -10
  47. package/src/Table/Head/styles.ts +0 -2
  48. package/src/Table/README.md +1788 -546
  49. package/src/Table/Row/index.tsx +27 -11
  50. package/src/Table/Row/props.ts +7 -19
  51. package/src/Table/Row/styles.ts +5 -6
  52. package/src/Table/RowHeader/index.tsx +6 -4
  53. package/src/Table/RowHeader/props.ts +1 -3
  54. package/src/Table/TableContext.ts +54 -0
  55. package/src/Table/__new-tests__/Table.test.tsx +131 -2
  56. package/src/Table/index.tsx +42 -44
  57. package/src/Table/props.ts +8 -28
  58. package/src/index.ts +1 -0
  59. package/tsconfig.build.tsbuildinfo +1 -1
  60. package/types/Table/Body/index.d.ts +6 -13
  61. package/types/Table/Body/index.d.ts.map +1 -1
  62. package/types/Table/Body/props.d.ts +4 -5
  63. package/types/Table/Body/props.d.ts.map +1 -1
  64. package/types/Table/Body/styles.d.ts +0 -2
  65. package/types/Table/Body/styles.d.ts.map +1 -1
  66. package/types/Table/Cell/index.d.ts +4 -3
  67. package/types/Table/Cell/index.d.ts.map +1 -1
  68. package/types/Table/Cell/props.d.ts +6 -2
  69. package/types/Table/Cell/props.d.ts.map +1 -1
  70. package/types/Table/ColHeader/index.d.ts +2 -0
  71. package/types/Table/ColHeader/index.d.ts.map +1 -1
  72. package/types/Table/ColHeader/props.d.ts +7 -3
  73. package/types/Table/ColHeader/props.d.ts.map +1 -1
  74. package/types/Table/Head/index.d.ts +15 -5
  75. package/types/Table/Head/index.d.ts.map +1 -1
  76. package/types/Table/Head/props.d.ts +19 -4
  77. package/types/Table/Head/props.d.ts.map +1 -1
  78. package/types/Table/Head/styles.d.ts +0 -2
  79. package/types/Table/Head/styles.d.ts.map +1 -1
  80. package/types/Table/Row/index.d.ts +6 -13
  81. package/types/Table/Row/index.d.ts.map +1 -1
  82. package/types/Table/Row/props.d.ts +5 -6
  83. package/types/Table/Row/props.d.ts.map +1 -1
  84. package/types/Table/Row/styles.d.ts +5 -2
  85. package/types/Table/Row/styles.d.ts.map +1 -1
  86. package/types/Table/RowHeader/index.d.ts +4 -3
  87. package/types/Table/RowHeader/index.d.ts.map +1 -1
  88. package/types/Table/RowHeader/props.d.ts +0 -1
  89. package/types/Table/RowHeader/props.d.ts.map +1 -1
  90. package/types/Table/TableContext.d.ts +24 -0
  91. package/types/Table/TableContext.d.ts.map +1 -0
  92. package/types/Table/index.d.ts +1 -1
  93. package/types/Table/index.d.ts.map +1 -1
  94. package/types/Table/props.d.ts +10 -22
  95. package/types/Table/props.d.ts.map +1 -1
  96. package/types/index.d.ts +1 -0
  97. package/types/index.d.ts.map +1 -1
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  /** @jsx jsx */
26
- import { Component, Children } from 'react'
26
+ import { Component, Children, ContextType, isValidElement } from 'react'
27
27
 
28
28
  import { omitProps, safeCloneElement } from '@instructure/ui-react-utils'
29
29
  import { View } from '@instructure/ui-view'
@@ -35,6 +35,7 @@ import generateComponentTheme from './theme'
35
35
 
36
36
  import type { TableRowProps } from './props'
37
37
  import { allowedProps, propTypes } from './props'
38
+ import TableContext from '../TableContext'
38
39
 
39
40
  /**
40
41
  ---
@@ -45,7 +46,8 @@ id: Table.Row
45
46
  @withStyle(generateStyle, generateComponentTheme)
46
47
  class Row extends Component<TableRowProps> {
47
48
  static readonly componentId = 'Table.Row'
48
-
49
+ static contextType = TableContext
50
+ declare context: ContextType<typeof TableContext>
49
51
  static allowedProps = allowedProps
50
52
  static propTypes = propTypes
51
53
 
@@ -54,15 +56,23 @@ class Row extends Component<TableRowProps> {
54
56
  }
55
57
 
56
58
  componentDidMount() {
57
- this.props.makeStyles?.()
59
+ this.props.makeStyles?.({
60
+ isStacked: this.context.isStacked,
61
+ hover: this.context.hover
62
+ })
58
63
  }
59
64
 
60
65
  componentDidUpdate() {
61
- this.props.makeStyles?.()
66
+ this.props.makeStyles?.({
67
+ isStacked: this.context.isStacked,
68
+ hover: this.context.hover
69
+ })
62
70
  }
63
71
 
64
72
  render() {
65
- const { children, styles, isStacked, headers } = this.props
73
+ const { children, styles } = this.props
74
+ const isStacked = this.context.isStacked
75
+ const headers = this.context.headers
66
76
 
67
77
  return (
68
78
  <View
@@ -73,12 +83,18 @@ class Row extends Component<TableRowProps> {
73
83
  >
74
84
  {Children.toArray(children)
75
85
  .filter(Boolean)
76
- .map((child: any, index) => {
77
- return safeCloneElement(child, {
78
- key: child.props.name,
79
- isStacked,
80
- header: headers && headers[index]
81
- })
86
+ .map((child, index) => {
87
+ if (isValidElement(child)) {
88
+ return safeCloneElement(child, {
89
+ key: child.props.name,
90
+ // Sent down for compatibility with custom components
91
+ // TODO DEPRECATED, remove in v11
92
+ isStacked,
93
+ // used by `Cell` to render its column title in `stacked` layout
94
+ header: headers && headers[index]
95
+ })
96
+ }
97
+ return child
82
98
  })}
83
99
  </View>
84
100
  )
@@ -25,8 +25,6 @@
25
25
  import React from 'react'
26
26
  import PropTypes from 'prop-types'
27
27
 
28
- import type { TableCellProps } from '../Cell/props'
29
-
30
28
  import type {
31
29
  OtherHTMLAttributes,
32
30
  PropValidators,
@@ -35,13 +33,13 @@ import type {
35
33
  import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
36
34
 
37
35
  type TableRowOwnProps = {
38
- hover?: boolean
39
- isStacked?: boolean
40
- headers?: TableCellProps['header'][]
41
36
  /**
42
- * `Table.ColHeader`, `Table.RowHeader` or `Table.Cell`
37
+ * A row's children should be table cells. Its children should have the
38
+ * `header` prop to render the column header in `stacked` layout
39
+ *
40
+ * By default `Table.ColHeader` or `Table.RowHeader` or `Table.Cell`
43
41
  */
44
- children?: React.ReactNode
42
+ children?: React.ReactElement | React.ReactElement[]
45
43
  }
46
44
 
47
45
  type PropKeys = keyof TableRowOwnProps
@@ -55,20 +53,10 @@ type TableRowProps = TableRowOwnProps &
55
53
  type TableRowStyle = ComponentStyle<'row'>
56
54
 
57
55
  const propTypes: PropValidators<PropKeys> = {
58
- children: PropTypes.node,
59
- hover: PropTypes.bool,
60
- isStacked: PropTypes.bool,
61
- headers: PropTypes.arrayOf(
62
- PropTypes.oneOfType([PropTypes.node, PropTypes.func])
63
- )
56
+ children: PropTypes.node
64
57
  }
65
58
 
66
- const allowedProps: AllowedPropKeys = [
67
- 'children',
68
- 'hover',
69
- 'isStacked',
70
- 'headers'
71
- ]
59
+ const allowedProps: AllowedPropKeys = ['children']
72
60
 
73
61
  export type { TableRowProps, TableRowStyle }
74
62
  export { propTypes, allowedProps }
@@ -32,15 +32,14 @@ import type { TableRowProps, TableRowStyle } from './props'
32
32
  * Generates the style object from the theme and provided additional information
33
33
  * @param {Object} componentTheme The theme variable object.
34
34
  * @param {Object} props the props of the component, the style is applied to
35
- * @param {Object} state the state of the component, the style is applied to
35
+ * @param {Object} extraArgs the state of the component, the style is applied to
36
36
  * @return {Object} The final style object, which will be used in the component
37
37
  */
38
38
  const generateStyle = (
39
39
  componentTheme: TableRowTheme,
40
- props: TableRowProps
40
+ _props: TableRowProps,
41
+ extraArgs: { isStacked: boolean; hover: boolean }
41
42
  ): TableRowStyle => {
42
- const { hover, isStacked } = props
43
-
44
43
  return {
45
44
  row: {
46
45
  label: 'row',
@@ -54,7 +53,7 @@ const generateStyle = (
54
53
  borderBottomWidth: '0.0625rem',
55
54
  borderBottomColor: componentTheme.borderColor,
56
55
 
57
- ...(hover && {
56
+ ...(extraArgs.hover && {
58
57
  borderLeft: '0.1875rem solid transparent',
59
58
  borderRight: '0.1875rem solid transparent',
60
59
 
@@ -64,7 +63,7 @@ const generateStyle = (
64
63
  }
65
64
  }),
66
65
 
67
- ...(isStacked && { padding: componentTheme.padding })
66
+ ...(extraArgs.isStacked && { padding: componentTheme.padding })
68
67
  }
69
68
  }
70
69
  }
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  /** @jsx jsx */
26
- import { Component } from 'react'
26
+ import { Component, ContextType } from 'react'
27
27
 
28
28
  import { omitProps, callRenderProp } from '@instructure/ui-react-utils'
29
29
  import { View } from '@instructure/ui-view'
@@ -34,6 +34,7 @@ import generateStyle from './styles'
34
34
  import generateComponentTheme from './theme'
35
35
  import type { TableRowHeaderProps } from './props'
36
36
  import { allowedProps, propTypes } from './props'
37
+ import TableContext from '../TableContext'
37
38
 
38
39
  /**
39
40
  ---
@@ -44,7 +45,8 @@ id: Table.RowHeader
44
45
  @withStyle(generateStyle, generateComponentTheme)
45
46
  class RowHeader extends Component<TableRowHeaderProps> {
46
47
  static readonly componentId = 'Table.RowHeader'
47
-
48
+ static contextType = TableContext
49
+ declare context: ContextType<typeof TableContext>
48
50
  static allowedProps = allowedProps
49
51
  static propTypes = propTypes
50
52
 
@@ -62,8 +64,8 @@ class RowHeader extends Component<TableRowHeaderProps> {
62
64
  }
63
65
 
64
66
  render() {
65
- const { children, isStacked, styles } = this.props
66
-
67
+ const { children, styles } = this.props
68
+ const isStacked = this.context.isStacked
67
69
  return (
68
70
  <View
69
71
  {...View.omitViewProps(
@@ -33,7 +33,6 @@ import type {
33
33
  import type { WithStyleProps, ComponentStyle } from '@instructure/emotion'
34
34
 
35
35
  type TableRowHeaderOwnProps = {
36
- isStacked?: boolean
37
36
  /**
38
37
  * Control the text alignment in row header
39
38
  */
@@ -53,11 +52,10 @@ type TableRowHeaderStyle = ComponentStyle<'rowHeader'>
53
52
 
54
53
  const propTypes: PropValidators<PropKeys> = {
55
54
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
56
- isStacked: PropTypes.bool,
57
55
  textAlign: PropTypes.oneOf(['start', 'center', 'end'])
58
56
  }
59
57
 
60
- const allowedProps: AllowedPropKeys = ['children', 'isStacked', 'textAlign']
58
+ const allowedProps: AllowedPropKeys = ['children', 'textAlign']
61
59
 
62
60
  export type { TableRowHeaderProps, TableRowHeaderStyle }
63
61
  export { propTypes, allowedProps }
@@ -0,0 +1,54 @@
1
+ /*
2
+ * The MIT License (MIT)
3
+ *
4
+ * Copyright (c) 2015 - present Instructure, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ import { createContext } from 'react'
26
+ import { Renderable } from '@instructure/shared-types'
27
+
28
+ type TableContextType = {
29
+ /**
30
+ * If `true` the table gets rendered in one column to be more readable on
31
+ * narrow screens.
32
+ */
33
+ isStacked: boolean
34
+ /**
35
+ * Highlight each row on hover.
36
+ */
37
+ hover: boolean
38
+ /**
39
+ * Contents of the first row of cells. Has value if `isStacked` is `true`.
40
+ */
41
+ headers?: Renderable[]
42
+ }
43
+
44
+ /**
45
+ * React context created by the `Table` component to hold its data
46
+ */
47
+ const TableContext = createContext<TableContextType>({
48
+ isStacked: false,
49
+ hover: false
50
+ })
51
+
52
+ export default TableContext
53
+ export { TableContext }
54
+ export type { TableContextType }
@@ -24,7 +24,7 @@
24
24
 
25
25
  import React from 'react'
26
26
  import { render, screen, waitFor } from '@testing-library/react'
27
- import { vi } from 'vitest'
27
+ import { MockInstance, vi } from 'vitest'
28
28
  import { userEvent } from '@testing-library/user-event'
29
29
  import '@testing-library/jest-dom'
30
30
 
@@ -34,7 +34,7 @@ import type { TableColHeaderProps } from '../ColHeader/props'
34
34
  import { runAxeCheck } from '@instructure/ui-axe-check'
35
35
 
36
36
  describe('<Table />', async () => {
37
- let consoleErrorMock: any
37
+ let consoleErrorMock: MockInstance<typeof console.error>
38
38
 
39
39
  beforeEach(() => {
40
40
  // Mocking console to prevent test output pollution
@@ -167,6 +167,45 @@ describe('<Table />', async () => {
167
167
  expect(stackedTable).not.toHaveTextContent('Foo')
168
168
  })
169
169
 
170
+ it('does not crash for invalid children', async () => {
171
+ render(
172
+ <Table caption="Test table" layout="stacked">
173
+ test1
174
+ <span>test</span>
175
+ {/* @ts-ignore error is normal here */}
176
+ <Table.Head>
177
+ <span>test</span>
178
+ test2
179
+ {/* @ts-ignore error is normal here */}
180
+ <Table.Row>
181
+ test3
182
+ <span>test</span>
183
+ <Table.Cell>Foo</Table.Cell>
184
+ </Table.Row>
185
+ test4
186
+ <span>test</span>
187
+ </Table.Head>
188
+ test5
189
+ <Table.Body>
190
+ test
191
+ <span>test</span>
192
+ {/* @ts-ignore error is normal here */}
193
+ <Table.Row>
194
+ test
195
+ <span>test</span>
196
+ <Table.Cell>Foo</Table.Cell>
197
+ test
198
+ <span>test</span>
199
+ </Table.Row>
200
+ </Table.Body>
201
+ </Table>
202
+ )
203
+ const table = screen.getByRole('table')
204
+
205
+ expect(table).toBeInTheDocument()
206
+ expect(table).toHaveTextContent('Foo')
207
+ })
208
+
170
209
  describe('when table is sortable', async () => {
171
210
  const renderSortableTable = (
172
211
  props: TableColHeaderProps | null,
@@ -290,4 +329,94 @@ describe('<Table />', async () => {
290
329
  expect(header).toHaveAttribute('aria-sort', 'descending')
291
330
  })
292
331
  })
332
+
333
+ describe('when using custom components', () => {
334
+ it('should render wrapper HOCs', () => {
335
+ class CustomTableCell extends React.Component<any> {
336
+ render() {
337
+ return <Table.Cell {...this.props}>{this.props.children}</Table.Cell>
338
+ }
339
+ }
340
+ class CustomTableRow extends React.Component {
341
+ render() {
342
+ return (
343
+ <Table.Row {...this.props}>
344
+ <Table.RowHeader>1</Table.RowHeader>
345
+ <Table.Cell>The Shawshank Redemption</Table.Cell>
346
+ <CustomTableCell>9.3</CustomTableCell>
347
+ </Table.Row>
348
+ )
349
+ }
350
+ }
351
+ const table = render(
352
+ <Table caption="Test custom table">
353
+ <Table.Head>
354
+ <Table.Row>
355
+ <Table.ColHeader id="foo">ColHeader</Table.ColHeader>
356
+ <Table.ColHeader id="bar">Bar-header</Table.ColHeader>
357
+ <Table.ColHeader id="baz">Bar-header</Table.ColHeader>
358
+ </Table.Row>
359
+ </Table.Head>
360
+ <Table.Body>
361
+ <CustomTableRow />
362
+ <Table.Row>
363
+ <Table.RowHeader>RowHeader</Table.RowHeader>
364
+ <Table.Cell>Cell</Table.Cell>
365
+ <Table.Cell>Cell2</Table.Cell>
366
+ </Table.Row>
367
+ </Table.Body>
368
+ </Table>
369
+ )
370
+ const stackedTable = screen.getByRole('table')
371
+
372
+ expect(stackedTable).toBeInTheDocument()
373
+ const { container } = table
374
+ expect(container).toBeInTheDocument()
375
+ expect(container).toHaveTextContent('The Shawshank Redemption')
376
+ expect(container).toHaveTextContent('9.3')
377
+ })
378
+
379
+ it('should render fully custom components', () => {
380
+ class CustomTableCell extends React.Component<any> {
381
+ render() {
382
+ return <td>{this.props.children}</td>
383
+ }
384
+ }
385
+
386
+ class CustomTableRow extends React.Component<any> {
387
+ render() {
388
+ return <tr>{this.props.children}</tr>
389
+ }
390
+ }
391
+
392
+ const table = render(
393
+ <Table caption="Test custom table">
394
+ <Table.Head>
395
+ <CustomTableRow>
396
+ <CustomTableCell id="foo">ColHeader</CustomTableCell>
397
+ <CustomTableCell id="bar">Bar-header</CustomTableCell>
398
+ <Table.ColHeader id="baz">Bar-header</Table.ColHeader>
399
+ </CustomTableRow>
400
+ </Table.Head>
401
+ <Table.Body>
402
+ <CustomTableRow>
403
+ <Table.RowHeader>RowHeader2</Table.RowHeader>
404
+ <CustomTableCell>Cell</CustomTableCell>
405
+ <Table.Cell>Cell2</Table.Cell>
406
+ </CustomTableRow>
407
+ </Table.Body>
408
+ </Table>
409
+ )
410
+ const stackedTable = screen.getByRole('table')
411
+
412
+ expect(stackedTable).toBeInTheDocument()
413
+ const { container } = table
414
+ expect(container).toBeInTheDocument()
415
+ expect(container).toHaveTextContent('ColHeader')
416
+ expect(container).toHaveTextContent('Bar-header')
417
+ expect(container).toHaveTextContent('RowHeader2')
418
+ expect(container).toHaveTextContent('Cell')
419
+ expect(container).toHaveTextContent('Cell2')
420
+ })
421
+ })
293
422
  })
@@ -23,7 +23,7 @@
23
23
  */
24
24
 
25
25
  /** @jsx jsx */
26
- import { Component, Children } from 'react'
26
+ import { Component, Children, isValidElement } from 'react'
27
27
 
28
28
  import { safeCloneElement, omitProps } from '@instructure/ui-react-utils'
29
29
  import { View } from '@instructure/ui-view'
@@ -41,15 +41,10 @@ import { ColHeader } from './ColHeader'
41
41
  import { RowHeader } from './RowHeader'
42
42
  import { Cell } from './Cell'
43
43
 
44
- import type {
45
- TableProps,
46
- HeadChild,
47
- ColHeaderChild,
48
- RowHeaderChild,
49
- CellChild
50
- } from './props'
44
+ import type { TableProps } from './props'
51
45
 
52
46
  import { allowedProps, propTypes } from './props'
47
+ import TableContext from './TableContext'
53
48
 
54
49
  /**
55
50
  ---
@@ -97,17 +92,14 @@ class Table extends Component<TableProps> {
97
92
  }
98
93
 
99
94
  getHeaders() {
100
- const { children } = this.props
101
- const [head] = Children.toArray(children) as HeadChild[]
102
- const [row]: any = Children.toArray(head.props.children)
103
- if (!row) return undefined
104
-
105
- return Children.map(
106
- row.props.children as (ColHeaderChild | RowHeaderChild | CellChild)[],
107
- (colHeader) => {
108
- return colHeader.props.children
109
- }
110
- )
95
+ const [headChild] = Children.toArray(this.props.children)
96
+ if (!headChild || !isValidElement(headChild)) return undefined
97
+ const [firstRow] = Children.toArray(headChild.props.children)
98
+ if (!firstRow || !isValidElement(firstRow)) return undefined
99
+ return Children.map(firstRow.props.children, (colHeader) => {
100
+ if (!isValidElement<{ children?: any }>(colHeader)) return undefined
101
+ return colHeader.props.children
102
+ })
111
103
  }
112
104
 
113
105
  render() {
@@ -116,32 +108,38 @@ class Table extends Component<TableProps> {
116
108
  const headers = isStacked ? this.getHeaders() : undefined
117
109
 
118
110
  return (
119
- <View
120
- {...View.omitViewProps(
121
- omitProps(this.props, Table.allowedProps),
122
- Table
123
- )}
124
- as={isStacked ? 'div' : 'table'}
125
- margin={margin}
126
- elementRef={this.handleRef}
127
- css={styles?.table}
128
- role={isStacked ? 'table' : undefined}
129
- aria-label={isStacked ? (caption as string) : undefined}
111
+ <TableContext.Provider
112
+ value={{
113
+ isStacked: isStacked,
114
+ hover: hover!,
115
+ headers: headers
116
+ }}
130
117
  >
131
- {!isStacked && (
132
- <caption>
133
- <ScreenReaderContent>{caption}</ScreenReaderContent>
134
- </caption>
135
- )}
136
- {Children.map(children, (child: any) => {
137
- return safeCloneElement(child, {
138
- key: child.props.name,
139
- isStacked,
140
- hover,
141
- headers
142
- })
143
- })}
144
- </View>
118
+ <View
119
+ {...View.omitViewProps(
120
+ omitProps(this.props, Table.allowedProps),
121
+ Table
122
+ )}
123
+ as={isStacked ? 'div' : 'table'}
124
+ margin={margin}
125
+ elementRef={this.handleRef}
126
+ css={styles?.table}
127
+ role={isStacked ? 'table' : undefined}
128
+ aria-label={isStacked ? (caption as string) : undefined}
129
+ >
130
+ {!isStacked && (
131
+ <caption>
132
+ <ScreenReaderContent>{caption}</ScreenReaderContent>
133
+ </caption>
134
+ )}
135
+ {Children.map(children, (child) => {
136
+ if (isValidElement(child)) {
137
+ return safeCloneElement(child, { key: child.props.name })
138
+ }
139
+ return child
140
+ })}
141
+ </View>
142
+ </TableContext.Provider>
145
143
  )
146
144
  }
147
145
  }
@@ -37,25 +37,7 @@ import type {
37
37
  TableTheme
38
38
  } from '@instructure/shared-types'
39
39
 
40
- import { Head } from './Head'
41
- import type { TableHeadProps } from './Head/props'
42
- import { Body } from './Body'
43
- import type { TableBodyProps } from './Body/props'
44
- import { Row } from './Row'
45
- import type { TableRowProps } from './Row/props'
46
- import { ColHeader } from './ColHeader'
47
- import type { TableColHeaderProps } from './ColHeader/props'
48
- import { RowHeader } from './RowHeader'
49
- import type { TableRowHeaderProps } from './RowHeader/props'
50
- import { Cell } from './Cell'
51
- import type { TableCellProps } from './Cell/props'
52
-
53
- type HeadChild = React.ComponentElement<TableHeadProps, Head>
54
- type BodyChild = React.ComponentElement<TableBodyProps, Body>
55
- type RowChild = React.ComponentElement<TableRowProps, Row>
56
- type ColHeaderChild = React.ComponentElement<TableColHeaderProps, ColHeader>
57
- type RowHeaderChild = React.ComponentElement<TableRowHeaderProps, RowHeader>
58
- type CellChild = React.ComponentElement<TableCellProps, Cell>
40
+ type RowChild = React.ReactElement<{ children: React.ReactElement }>
59
41
 
60
42
  type TableOwnProps = {
61
43
  /**
@@ -79,12 +61,15 @@ type TableOwnProps = {
79
61
  hover?: boolean
80
62
  /**
81
63
  * `auto` lets the browser determine table column widths based on cell content,
82
- * while `fixed` forces columns of equal width. `stacked` renders table in one
83
- * column to be more readable on narrow screens
64
+ * while `fixed` forces columns of equal width (sets the
65
+ * [tableLayout](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout)
66
+ * CSS prop to `fixed`).
67
+ *
68
+ * `stacked` renders table in one column to be more readable on narrow screens
84
69
  */
85
70
  layout?: 'auto' | 'fixed' | 'stacked'
86
71
  /**
87
- * Build table via `Table.Head` and `Table.Body`
72
+ * `Table.Head` or `Table.Body`
88
73
  */
89
74
  children?: React.ReactNode
90
75
  }
@@ -121,11 +106,6 @@ export type {
121
106
  TableProps,
122
107
  TableStyle,
123
108
  // children
124
- HeadChild,
125
- BodyChild,
126
- RowChild,
127
- ColHeaderChild,
128
- RowHeaderChild,
129
- CellChild
109
+ RowChild
130
110
  }
131
111
  export { propTypes, allowedProps }
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
  export { Table } from './Table'
25
+ export { TableContext } from './Table/TableContext'
25
26
 
26
27
  export type { TableProps } from './Table/props'
27
28
  export type { TableBodyProps } from './Table/Body/props'