mirror of
https://github.com/gosticks/react-table.git
synced 2026-08-12 04:50:20 +00:00
Add fixed width column support to useFlexLayout (#1810)
* Add fixed width column support to useFlexLayout * Allow useFlexLayout to honor canResize by calculating flex width separately from total width. * Update example to show the selection checkbox since that's a common fixed width use case. * Add example for right aligning columns. * Tweaked the styles for the table to better align the resize handles (since it made verifying the rest easier when they weren't misaligned by the scroll bar width) Note that the resize behavior is still rather strange, but that's a separate problem that this change didn't really effect. * swich to react-table@latest
This commit is contained in:
committed by
Tanner Linsley
parent
ed2fe54371
commit
1d8ffb18f7
@@ -10,7 +10,7 @@
|
||||
"namor": "^1.1.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-scripts": "3.0.1",
|
||||
"react-scripts": "3.3.0",
|
||||
"react-table": "latest",
|
||||
"styled-components": "^4.3.2"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { useTable, useResizeColumns, useFlexLayout } from 'react-table'
|
||||
import {
|
||||
useTable,
|
||||
useResizeColumns,
|
||||
useFlexLayout,
|
||||
useRowSelect,
|
||||
} from 'react-table'
|
||||
|
||||
import makeData from './makeData'
|
||||
|
||||
@@ -35,13 +40,13 @@ const Styles = styled.div`
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
.th,
|
||||
.td {
|
||||
margin: 0;
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid black;
|
||||
border-right: 1px solid black;
|
||||
|
||||
${'' /* In this example we use an absolutely position resizer,
|
||||
@@ -53,12 +58,11 @@ const Styles = styled.div`
|
||||
}
|
||||
|
||||
.resizer {
|
||||
display: inline-block;
|
||||
right: -5px;
|
||||
background: blue;
|
||||
width: 10px;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
${'' /* prevents from scrolling while dragging on touch devices */}
|
||||
@@ -69,9 +73,51 @@ const Styles = styled.div`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.th {
|
||||
&:last-of-type {
|
||||
.resizer {
|
||||
${'' /* note that the 15 is the scroll width and if also referenced in the getHeaderGroupProps for the header row below */}
|
||||
${'' /* todo: resolve this value dynamicaly from element.scrollWidth to account for OS/Browser differences */}
|
||||
right: -15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const headerProps = (props, { column }) => getStyles(props, column.align)
|
||||
|
||||
const cellProps = (props, { cell }) => getStyles(props, cell.column.align)
|
||||
|
||||
const getStyles = (props, align = 'left') => [
|
||||
props,
|
||||
{
|
||||
style: {
|
||||
justifyContent: align === 'right' ? 'flex-end' : 'flex-start',
|
||||
alignItems: 'flex-start',
|
||||
display: 'flex',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const IndeterminateCheckbox = React.forwardRef(
|
||||
({ indeterminate, ...rest }, ref) => {
|
||||
const defaultRef = React.useRef()
|
||||
const resolvedRef = ref || defaultRef
|
||||
|
||||
React.useEffect(() => {
|
||||
resolvedRef.current.indeterminate = indeterminate
|
||||
}, [resolvedRef, indeterminate])
|
||||
|
||||
return (
|
||||
<>
|
||||
<input type="checkbox" ref={resolvedRef} {...rest} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
function Table({ columns, data }) {
|
||||
const defaultColumn = React.useMemo(
|
||||
() => ({
|
||||
@@ -96,28 +142,69 @@ function Table({ columns, data }) {
|
||||
defaultColumn,
|
||||
},
|
||||
useResizeColumns,
|
||||
useFlexLayout
|
||||
useFlexLayout,
|
||||
useRowSelect,
|
||||
hooks => {
|
||||
hooks.flatColumns.push(columns => [
|
||||
// Let's make a column for selection
|
||||
{
|
||||
id: 'selection',
|
||||
disableResizing: true,
|
||||
minWidth: 35,
|
||||
width: 35,
|
||||
maxWidth: 35,
|
||||
// The header can use the table's getToggleAllRowsSelectedProps method
|
||||
// to render a checkbox
|
||||
Header: ({ getToggleAllRowsSelectedProps }) => (
|
||||
<div>
|
||||
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
|
||||
</div>
|
||||
),
|
||||
// The cell can use the individual row's getToggleRowSelectedProps method
|
||||
// to the render a checkbox
|
||||
Cell: ({ row }) => (
|
||||
<div>
|
||||
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
...columns,
|
||||
])
|
||||
hooks.useInstanceBeforeDimensions.push(({ headerGroups }) => {
|
||||
// fix the parent group of the selection button to not be resizable
|
||||
const selectionGroupHeader = headerGroups[0].headers[0]
|
||||
selectionGroupHeader.canResize = false
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return (
|
||||
<div {...getTableProps()} className="table">
|
||||
<div>
|
||||
{headerGroups.map(headerGroup => (
|
||||
<div {...headerGroup.getHeaderGroupProps()} className="tr">
|
||||
<div
|
||||
{...headerGroup.getHeaderGroupProps({
|
||||
style: { paddingRight: '15px' },
|
||||
})}
|
||||
className="tr"
|
||||
>
|
||||
{headerGroup.headers.map(column => (
|
||||
<div {...column.getHeaderProps()} className="th">
|
||||
<div {...column.getHeaderProps(headerProps)} className="th">
|
||||
{column.render('Header')}
|
||||
{/* Use column.getResizerProps to hook up the events correctly */}
|
||||
<div
|
||||
{...column.getResizerProps()}
|
||||
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
|
||||
/>
|
||||
{column.canResize && (
|
||||
<div
|
||||
{...column.getResizerProps()}
|
||||
className={`resizer ${
|
||||
column.isResizing ? 'isResizing' : ''
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div {...getTableBodyProps()} className="tbody">
|
||||
{rows.map((row, i) => {
|
||||
prepareRow(row)
|
||||
@@ -125,7 +212,7 @@ function Table({ columns, data }) {
|
||||
<div {...row.getRowProps()} className="tr">
|
||||
{row.cells.map(cell => {
|
||||
return (
|
||||
<div {...cell.getCellProps()} className="td">
|
||||
<div {...cell.getCellProps(cellProps)} className="td">
|
||||
{cell.render('Cell')}
|
||||
</div>
|
||||
)
|
||||
@@ -161,11 +248,13 @@ function App() {
|
||||
Header: 'Age',
|
||||
accessor: 'age',
|
||||
width: 50,
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
Header: 'Visits',
|
||||
accessor: 'visits',
|
||||
width: 50,
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
Header: 'Status',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -548,6 +548,7 @@ function calculateHeaderWidths(headers, left = 0) {
|
||||
let sumTotalMinWidth = 0
|
||||
let sumTotalWidth = 0
|
||||
let sumTotalMaxWidth = 0
|
||||
let sumTotalFlexWidth = 0
|
||||
|
||||
headers.forEach(header => {
|
||||
let { headers: subHeaders } = header
|
||||
@@ -555,13 +556,14 @@ function calculateHeaderWidths(headers, left = 0) {
|
||||
header.totalLeft = left
|
||||
|
||||
if (subHeaders && subHeaders.length) {
|
||||
const [totalMinWidth, totalWidth, totalMaxWidth] = calculateHeaderWidths(
|
||||
const [totalMinWidth, totalWidth, totalMaxWidth, totalFlexWidth] = calculateHeaderWidths(
|
||||
subHeaders,
|
||||
left
|
||||
)
|
||||
header.totalMinWidth = totalMinWidth
|
||||
header.totalWidth = totalWidth
|
||||
header.totalMaxWidth = totalMaxWidth
|
||||
header.totalFlexWidth = totalFlexWidth
|
||||
} else {
|
||||
header.totalMinWidth = header.minWidth
|
||||
header.totalWidth = Math.min(
|
||||
@@ -569,14 +571,16 @@ function calculateHeaderWidths(headers, left = 0) {
|
||||
header.maxWidth
|
||||
)
|
||||
header.totalMaxWidth = header.maxWidth
|
||||
header.totalFlexWidth = header.canResize ? header.totalWidth : 0
|
||||
}
|
||||
if (header.isVisible) {
|
||||
left += header.totalWidth
|
||||
sumTotalMinWidth += header.totalMinWidth
|
||||
sumTotalWidth += header.totalWidth
|
||||
sumTotalMaxWidth += header.totalMaxWidth
|
||||
sumTotalFlexWidth += header.totalFlexWidth
|
||||
}
|
||||
})
|
||||
|
||||
return [sumTotalMinWidth, sumTotalWidth, sumTotalMaxWidth]
|
||||
return [sumTotalMinWidth, sumTotalWidth, sumTotalMaxWidth, sumTotalFlexWidth]
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ const getHeaderProps = (props, { column }) => [
|
||||
{
|
||||
style: {
|
||||
boxSizing: 'border-box',
|
||||
flex: `${column.totalWidth} 0 auto`,
|
||||
flex: column.totalFlexWidth ? `${column.totalFlexWidth} 0 auto` : undefined,
|
||||
minWidth: `${column.totalMinWidth}px`,
|
||||
width: `${column.totalWidth}px`,
|
||||
},
|
||||
@@ -45,7 +45,7 @@ const getCellProps = (props, { cell }) => [
|
||||
{
|
||||
style: {
|
||||
boxSizing: 'border-box',
|
||||
flex: `${cell.column.totalWidth} 0 auto`,
|
||||
flex: `${cell.column.totalFlexWidth} 0 auto`,
|
||||
minWidth: `${cell.column.totalMinWidth}px`,
|
||||
width: `${cell.column.totalWidth}px`,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user