Skip to content

Commit

Permalink
feat(ui-table): remove restriction for children types and add documen…
Browse files Browse the repository at this point in the history
…tation
  • Loading branch information
balzss committed Jul 3, 2024
1 parent 09a6a63 commit 00e3026
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 134 deletions.
21 changes: 7 additions & 14 deletions packages/ui-table/src/Table/Body/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,12 @@
/** @jsx jsx */
import { Component, Children } from 'react'

import {
matchComponentTypes,
safeCloneElement,
omitProps
} from '@instructure/ui-react-utils'
import { safeCloneElement, omitProps } from '@instructure/ui-react-utils'
import { View } from '@instructure/ui-view'
import { withStyle, jsx } from '@instructure/emotion'

import generateStyle from './styles'
import generateComponentTheme from './theme'
import { Row } from '../Row'
import type { TableBodyProps } from './props'
import type { RowChild } from '../props'
import { allowedProps, propTypes } from './props'
Expand Down Expand Up @@ -76,14 +71,12 @@ class Body extends Component<TableBodyProps> {
role={isStacked ? 'rowgroup' : undefined}
>
{Children.map(children as RowChild[], (child) =>
matchComponentTypes(child, [Row])
? safeCloneElement(child, {
key: child.props.name,
hover,
isStacked,
headers
})
: null
safeCloneElement(child, {
key: child.props.name,
hover,
isStacked,
headers
})
)}
</View>
)
Expand Down
5 changes: 1 addition & 4 deletions packages/ui-table/src/Table/Body/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
import React from 'react'
import PropTypes from 'prop-types'

import { Children as ChildrenPropTypes } from '@instructure/ui-prop-types'

import { Row } from '../Row'
import type { TableRowProps } from '../Row/props'

import type {
Expand Down Expand Up @@ -57,7 +54,7 @@ type TableBodyProps = TableBodyOwnProps &
type TableBodyStyle = ComponentStyle<'body'>

const propTypes: PropValidators<PropKeys> = {
children: ChildrenPropTypes.oneOf([Row]),
children: PropTypes.node,
hover: PropTypes.bool,
isStacked: PropTypes.bool,
headers: PropTypes.arrayOf(
Expand Down
6 changes: 1 addition & 5 deletions packages/ui-table/src/Table/Head/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@
import React from 'react'
import PropTypes from 'prop-types'

import { Children as ChildrenPropTypes } from '@instructure/ui-prop-types'

import { Row } from '../Row'

import type {
OtherHTMLAttributes,
PropValidators,
Expand Down Expand Up @@ -56,7 +52,7 @@ type TableHeadProps = TableHeadOwnProps &
type TableHeadStyle = ComponentStyle<'head'>

const propTypes: PropValidators<PropKeys> = {
children: ChildrenPropTypes.oneOf([Row]),
children: PropTypes.node,
isStacked: PropTypes.bool,
renderSortLabel: PropTypes.oneOfType([PropTypes.node, PropTypes.func])
}
Expand Down
112 changes: 112 additions & 0 deletions packages/ui-table/src/Table/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,118 @@ render(
)
```

### Using Custom Components as Children

In some cases you might want to use custom components in a `Table`, e.g. a HOC for `Table.Row` or `Table.Cell`. This is generally not recommended but sometimes it could be beneficial for codesplitting or writing cleaner code for larger and more complex Tables. In those cases you have to pay attention to always pass down the appropriate props manually.

```javascript
---
type: example
---
class CustomTableCell extends React.Component {
render () {
return (
<Table.Cell {...this.props}>{this.props.children}</Table.Cell>
)
}
}

class CustomTableRow extends React.Component {
render () {
return (
<Table.Row {...this.props}>
<Table.RowHeader>1</Table.RowHeader>
<Table.Cell>The Shawshank Redemption</Table.Cell>
<Table.Cell>1994</Table.Cell>
<CustomTableCell>9.3</CustomTableCell>
</Table.Row>
)
}
}

class Example extends React.Component {
state = {
layout: 'auto',
hover: false,
}

handleChange = (field, value) => {
this.setState({
[field]: value,
})
}

renderOptions () {
const { layout, hover } = this.state

return (
<Flex alignItems="start">
<Flex.Item margin="small">
<RadioInputGroup
name="layout2"
description="layout2"
value={layout}
onChange={(e, value) => this.handleChange('layout', value)}
>
<RadioInput label="auto" value="auto" />
<RadioInput label="fixed" value="fixed" />
<RadioInput label="stacked" value="stacked" />
</RadioInputGroup>
</Flex.Item>
<Flex.Item margin="small">
<Checkbox
label="hover"
checked={hover}
onChange={(e, value) => this.handleChange('hover', !hover)}
/>
</Flex.Item>
</Flex>
)
}

render() {
const { layout, hover } = this.state

return (
<div>
{this.renderOptions()}
<Table
caption='Top rated movies'
layout={layout}
hover={hover}
>
<Table.Head>
<Table.Row>
<Table.ColHeader id="Rank">Rank</Table.ColHeader>
<Table.ColHeader id="Title">Title</Table.ColHeader>
<Table.ColHeader id="Year">Year</Table.ColHeader>
<Table.ColHeader id="Rating">Rating</Table.ColHeader>
</Table.Row>
</Table.Head>
<Table.Body>
<CustomTableRow/>
<Table.Row>
<Table.RowHeader>2</Table.RowHeader>
<Table.Cell>The Godfather</Table.Cell>
<Table.Cell>1972</Table.Cell>
<Table.Cell>9.2</Table.Cell>
</Table.Row>
<Table.Row>
<Table.RowHeader>3</Table.RowHeader>
<Table.Cell>The Godfather: Part II</Table.Cell>
<Table.Cell>1974</Table.Cell>
<Table.Cell>9.0</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
</div>
)
}
}

render(<Example />)
```

### Guidelines

```js
Expand Down
42 changes: 8 additions & 34 deletions packages/ui-table/src/Table/Row/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,15 @@
/** @jsx jsx */
import { Component, Children } from 'react'

import {
omitProps,
matchComponentTypes,
safeCloneElement
} from '@instructure/ui-react-utils'
import { omitProps, safeCloneElement } from '@instructure/ui-react-utils'
import { View } from '@instructure/ui-view'

import { withStyle, jsx } from '@instructure/emotion'

import generateStyle from './styles'
import generateComponentTheme from './theme'

import { ColHeader } from '../ColHeader'
import { RowHeader } from '../RowHeader'
import { Cell } from '../Cell'
import type { TableRowProps } from './props'
import type { ColHeaderChild, RowHeaderChild, CellChild } from '../props'
import { allowedProps, propTypes } from './props'

/**
Expand Down Expand Up @@ -79,32 +71,14 @@ class Row extends Component<TableRowProps> {
css={styles?.row}
role={isStacked ? 'row' : undefined}
>
{(
Children.toArray(children) as (
| ColHeaderChild
| RowHeaderChild
| CellChild
)[]
)
{Children.toArray(children)
.filter(Boolean)
.map((child, index) => {
if (matchComponentTypes<ColHeaderChild>(child, [ColHeader])) {
return child
}
if (matchComponentTypes<RowHeaderChild>(child, [RowHeader])) {
return safeCloneElement(child, {
key: child.props.name,
isStacked
})
}
if (matchComponentTypes<CellChild>(child, [Cell])) {
return safeCloneElement(child, {
key: child.props.name,
isStacked,
header: headers && headers[index]
})
}
return null
.map((child: any, index) => {
return safeCloneElement(child, {
key: child.props.name,
isStacked,
header: headers && headers[index]
})
})}
</View>
)
Expand Down
7 changes: 1 addition & 6 deletions packages/ui-table/src/Table/Row/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@
import React from 'react'
import PropTypes from 'prop-types'

import { Children as ChildrenPropTypes } from '@instructure/ui-prop-types'

import { ColHeader } from '../ColHeader'
import { RowHeader } from '../RowHeader'
import { Cell } from '../Cell'
import type { TableCellProps } from '../Cell/props'

import type {
Expand Down Expand Up @@ -60,7 +55,7 @@ type TableRowProps = TableRowOwnProps &
type TableRowStyle = ComponentStyle<'row'>

const propTypes: PropValidators<PropKeys> = {
children: ChildrenPropTypes.oneOf([ColHeader, RowHeader, Cell]),
children: PropTypes.node,
hover: PropTypes.bool,
isStacked: PropTypes.bool,
headers: PropTypes.arrayOf(
Expand Down
33 changes: 1 addition & 32 deletions packages/ui-table/src/Table/__tests__/Table.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,7 @@
*/

import React from 'react'
import {
expect,
mount,
stub,
find,
findAll,
within
} from '@instructure/ui-test-utils'
import { expect, mount, stub, find, within } from '@instructure/ui-test-utils'
//TODO
/* eslint-disable no-restricted-imports */
// @ts-ignore: Cannot find module
Expand Down Expand Up @@ -115,30 +108,6 @@ describe('<Table />', async () => {
expect(stackedTable).to.exist()
})

it('can ignore invalid children', async () => {
await mount(
<Table caption="Test table">
<Table.Head>
{null}
<Table.Row>
<Table.ColHeader id="foo">Foo</Table.ColHeader>
{null}
</Table.Row>
</Table.Head>
{null}
<Table.Body>
{null}
<Table.Row></Table.Row>
</Table.Body>
</Table>
)
const th = await findAll('th')
const tr = await findAll('tr')

expect(th).to.have.length(1)
expect(tr).to.have.length(2)
})

it('can handle non-existent head in stacked layout', async () => {
const stackedTable = await mount(
<Table caption="Test table" layout="stacked">
Expand Down
Loading

0 comments on commit 00e3026

Please sign in to comment.