Compare commits

...
19 Commits
Author SHA1 Message Date
Tanner Linsley d8aec06496 6.5.3 2017-08-02 13:39:42 -06:00
Tanner Linsley 8efeef3b8b Fix onClick proxying and eslint 2017-08-02 13:39:34 -06:00
Tanner Linsley 8004e7a85f 6.5.2 2017-08-02 13:25:44 -06:00
Tanner Linsley 84af88916a Fix Typo 2017-08-02 13:16:54 -06:00
Tanner Linsley 9846bf1905 Provide onClick handleOriginal function
Fixes #406
2017-08-02 13:15:16 -06:00
Tanner Linsley bf88dda5dc Revert to page 1 on filter change
Fixes #273
2017-08-02 12:36:49 -06:00
Tanner Linsley 7f5779a833 Some simple event propagation fixes (but not the 100% fix) 2017-08-02 12:10:46 -06:00
Tanner Linsley 8792bd95a0 Move onFetchData for better timing and reliability
Fixes #294
2017-08-02 08:59:54 -06:00
ldsteinandTanner Linsley 098b1fec51 Max width NaN fix (#415)
* Added button to reset table state in Controlled Component story

* Fix maxWidth style when value is NaN

* code formatting
2017-08-01 21:27:40 -06:00
Tanner Linsley 750cfe3ac4 Fix Linting 2017-07-31 10:37:12 -06:00
Tanner Linsley 370f443347 Fix pivot header groups
Fixes #376
2017-07-31 10:29:41 -06:00
Tanner Linsley 67f8c9adf1 Cleanup 2017-07-31 09:36:29 -06:00
Tanner Linsley 867cc25899 Fixed display of inputs and checkboxes
Fixes #398
2017-07-31 09:27:03 -06:00
Caroline ShawandTanner Linsley 639630946c Update README to reflect updates (#400) 2017-07-25 14:01:17 -06:00
qmorelandTanner Linsley 688afd2947 [refs #321]: correct makePathArray function in utils (#326) 2017-07-19 14:43:32 -06:00
Tanner LinsleyandGitHub bbebf02a55 Update README.md 2017-07-17 15:01:04 -06:00
Tanner LinsleyandGitHub f4d3c2d7bb Update README.md 2017-07-17 15:00:31 -06:00
Tanner LinsleyandGitHub f8634e771e Update README.md 2017-07-11 14:32:10 -06:00
emyarodandTanner Linsley ba74ab3ce8 Fix typo (#380) 2017-07-08 10:22:24 -06:00
8 changed files with 162 additions and 108 deletions
+17 -3
View File
@@ -28,6 +28,11 @@
<img alt="" src="https://img.shields.io/badge/%24-Donate-brightgreen.svg" />
</a>
<br />
<br />
[![Sponsor](https://app.codesponsor.io/embed/zpmS8V9r31sBSCeVzP7Wm6Sr/tannerlinsley/react-table.svg)](https://app.codesponsor.io/link/zpmS8V9r31sBSCeVzP7Wm6Sr/tannerlinsley/react-table)
## Versions
This document refers to version 6.x.x of react-table.
@@ -588,12 +593,21 @@ This makes it extremely easy to add, say... a row click callback!
<ReactTable
getTdProps={(state, rowInfo, column, instance) => {
return {
onClick: e => {
onClick: (e, handleOriginal) => {
console.log('A Td Element was clicked!')
console.log('it produced this event:', e)
console.log('It was in this column:', column)
console.log('It was in this row:', rowInfo)
console.log('It was in this table instance:', instance)
// IMPORTANT! React-Table uses onClick internally to trigger
// events like expanding SubComponents and pivots.
// By default a custom 'onClick' handler will override this functionality.
// If you want to fire the original onClick handler, call the
// 'handleOriginal' function.
if (handleOriginal) {
handleOriginal()
}
}
}
}}
@@ -766,7 +780,7 @@ Here are the props and their corresponding callbacks that control the state of t
onPageSizeChange={(pageSize, pageIndex) => {...}} // Called when the pageSize is changed by the user. The resolve page is also sent to maintain approximate position in the data
onSortedChange={(newSorted, column, shiftKey) => {...}} // Called when a sortable column header is clicked with the column itself and if the shiftkey was held. If the column is a pivoted column, `column` will be an array of columns
onExpandedChange={(newExpanded, index, event) => {...}} // Called when an expander is clicked. Use this to manage `expandedRows`
onFilteredChange={(column, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFiltersChange handler by the filterRender option.
onFilteredChange={(column, value) => {...}} // Called when a user enters a value into a filter input field or the value passed to the onFiltersChange handler by the Filter option.
onResizedChange={(newResized, event) => {...}} // Called when a user clicks on a resizing component (the right edge of a column header)
/>
```
@@ -858,7 +872,7 @@ If you want to override a particular column's filtering method, you can set the
By default, `filterMethod` is passed a single row of data at a time, and you are responsible for returning `true` or `false`, indicating whether it should be shown.
Alternatively, you can set `filterAll` to `true`, and `fitlerMethod` will be passed the entire array of rows to be filtered, and you will then be responsible for returning the new filtered array. This is extremely handy when you need to utilize a utility like fuzzy matching that requires the entire array of items.
Alternatively, you can set `filterAll` to `true`, and `filterMethod` will be passed the entire array of rows to be filtered, and you will then be responsible for returning the new filtered array. This is extremely handy when you need to utilize a utility like fuzzy matching that requires the entire array of items.
To completely override the filter that is shown, you can set the `Filter` column option. Using this option you can specify the JSX that is shown. The option is passed an `onChange` method which must be called with the the value that you wan't to pass to the `filterMethod` option whenever the filter has changed.
+21 -9
View File
@@ -21,7 +21,8 @@ const columns = [{
}, {
Header: 'Last Name',
id: 'lastName',
accessor: d => d.lastName
accessor: d => d.lastName,
width: 170
}]
}, {
Header: 'Info',
@@ -31,21 +32,31 @@ const columns = [{
}]
}]
function makeDefaultState()
{
return {
sorted: [],
page: 0,
pageSize: 10,
expanded: {},
resized: [],
filtered: []
}
}
class Story extends React.PureComponent {
constructor () {
super()
this.state = {
sorted: [],
page: 0,
pageSize: 10,
expanded: {},
resized: [],
filtered: []
}
this.state = makeDefaultState()
this.resetState = this.resetState.bind(this)
}
resetState(){
this.setState(makeDefaultState())
}
render () {
return (
<div>
<div className='table-wrap'>
<ReactTable
className='-striped -highlight'
@@ -70,6 +81,7 @@ class Story extends React.PureComponent {
/>
</div>
<br />
<div style={{float:'right'}}><button onClick={this.resetState}>Reset State</button></div>
<pre><code><strong>this.state ===</strong> {JSON.stringify(this.state, null, 2)}</code></pre>
<br />
</div>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "6.5.1",
"version": "6.5.3",
"description": "A fast, lightweight, opinionated table and datagrid built on React",
"license": "MIT",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
+40 -26
View File
@@ -261,8 +261,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const flexStyles = {
flex: `${flex} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}
return (
@@ -352,8 +352,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const isResizable = _.getFirstDefined(column.resizable, resizable, false)
const resizer = isResizable
? (<ResizerComponent
onMouseDown={e => this.resizeColumnStart(column, e, false)}
onTouchStart={e => this.resizeColumnStart(column, e, true)}
onMouseDown={e => this.resizeColumnStart(e, column, false)}
onTouchStart={e => this.resizeColumnStart(e, column, true)}
{...resizerProps}
/>)
: null
@@ -376,8 +376,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
toggleSort={e => {
isSortable && this.sortColumn(column, e.shiftKey)
@@ -475,8 +475,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
{...rest}
>
@@ -574,7 +574,7 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
const value = cellInfo.value
let interactionProps
let useOnExpanderClick
let isBranch
let isPreview
@@ -626,17 +626,10 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
if (cellInfo.pivoted || cellInfo.expander) {
// Make it expandable by defualt
cellInfo.expandable = true
interactionProps = {
onClick: onExpanderClick,
}
useOnExpanderClick = true
// If pivoted, has no subRows, and does not have a subComponent, do not make expandable
if (cellInfo.pivoted) {
if (!cellInfo.subRows) {
if (!SubComponent) {
cellInfo.expandable = false
interactionProps = {}
}
}
if (cellInfo.pivoted && !cellInfo.subRows && !SubComponent) {
cellInfo.expandable = false
}
}
@@ -693,6 +686,27 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
}
}
const resolvedOnExpanderClick = useOnExpanderClick
? onExpanderClick
: () => {}
// If there are multiple onClick events, make sure they don't override eachother. This should maybe be expanded to handle all function attributes
const interactionProps = {
onClick: resolvedOnExpanderClick,
}
if (tdProps.rest.onClick) {
interactionProps.onClick = e => {
tdProps.rest.onClick(e, () => resolvedOnExpanderClick(e))
}
}
if (columnProps.rest.onClick) {
interactionProps.onClick = e => {
columnProps.rest.onClick(e, () => resolvedOnExpanderClick(e))
}
}
// Return the cell
return (
<TdComponent
@@ -706,12 +720,12 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
{...interactionProps}
{...tdProps.rest}
{...columnProps.rest}
{...interactionProps}
>
{resolvedCell}
</TdComponent>
@@ -798,8 +812,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={{
...styles,
flex: `${flex} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
{...tdProps.rest}
>
@@ -878,8 +892,8 @@ export default class ReactTable extends Methods(Lifecycle(Component)) {
style={{
...styles,
flex: `${width} 0 auto`,
width: `${width}px`,
maxWidth: `${maxWidth}px`,
width: _.asPx(width),
maxWidth: _.asPx(maxWidth),
}}
{...columnProps.rest}
{...tFootTdProps.rest}
-23
View File
@@ -21,7 +21,6 @@ $expandSize = 7px
.rt-thead
flex: 1 0 auto
display: flex
// overflow-y: scroll
flex-direction: column
-webkit-user-select: none;
-moz-user-select: none;
@@ -303,28 +302,6 @@ $expandSize = 7px
font-weight: normal
outline:none
input:not([type="checkbox"]):not([type="radio"])
select
appearance: none
&::-ms-expand
display: none
.select-wrap
position:relative
display:inline-block
select
padding: 5px 15px 5px 7px
min-width:100px
&:after
content: ''
position: absolute
right: 8px
top: 50%
transform: translate(0, -50%)
border-color: #999 transparent transparent
border-style: solid
border-width: 5px 5px 2.5px
.rt-resizing
.rt-th
.rt-td
+16 -1
View File
@@ -99,6 +99,11 @@ export default Base =>
Object.assign(newResolvedState, this.getSortedData(newResolvedState))
}
// Set page to 0 if filters change
if (oldState.filtered !== newResolvedState.filtered) {
newResolvedState.page = 0
}
// Calculate pageSize all the time
if (newResolvedState.sortedData) {
newResolvedState.pages = newResolvedState.manual
@@ -114,6 +119,16 @@ export default Base =>
)
}
return this.setState(newResolvedState, cb)
return this.setState(newResolvedState, () => {
cb && cb()
if (
oldState.page !== newResolvedState.page ||
oldState.pageSize !== newResolvedState.pageSize ||
oldState.sorted !== newResolvedState.sorted ||
oldState.filtered !== newResolvedState.filtered
) {
this.fireFetchData()
}
})
}
}
+58 -42
View File
@@ -55,7 +55,7 @@ export default Base =>
columnsWithExpander = [expanderColumn, ...columnsWithExpander]
}
const makeDecoratedColumn = column => {
const makeDecoratedColumn = (column, parentColumn) => {
let dcol
if (column.expander) {
dcol = {
@@ -70,6 +70,16 @@ export default Base =>
}
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
if (parentColumn) {
dcol.parentColumn = parentColumn
}
// First check for string accessor
if (typeof dcol.accessor === 'string') {
dcol.id = dcol.id || dcol.accessor
const accessorString = dcol.accessor
@@ -77,6 +87,7 @@ export default Base =>
return dcol
}
// Fall back to functional accessor (but require an ID)
if (dcol.accessor && !dcol.id) {
console.warn(dcol)
throw new Error(
@@ -84,30 +95,26 @@ export default Base =>
)
}
// Fall back to an undefined accessor
if (!dcol.accessor) {
dcol.accessor = d => undefined
}
// Ensure minWidth is not greater than maxWidth if set
if (dcol.maxWidth < dcol.minWidth) {
dcol.minWidth = dcol.maxWidth
}
return dcol
}
// Decorate the columns
const decorateAndAddToAll = col => {
const decoratedColumn = makeDecoratedColumn(col)
const decorateAndAddToAll = (column, parentColumn) => {
const decoratedColumn = makeDecoratedColumn(column, parentColumn)
allDecoratedColumns.push(decoratedColumn)
return decoratedColumn
}
let allDecoratedColumns = []
const allDecoratedColumns = []
const decoratedColumns = columnsWithExpander.map((column, i) => {
if (column.columns) {
return {
...column,
columns: column.columns.map(decorateAndAddToAll),
columns: column.columns.map(d => decorateAndAddToAll(d, column)),
}
} else {
return decorateAndAddToAll(column)
@@ -156,8 +163,17 @@ export default Base =>
}
})
let PivotParentColumn = pivotColumns.reduce(
(prev, current) =>
prev && prev === current.parentColumn && current.parentColumn,
pivotColumns[0].parentColumn
)
let PivotGroupHeader = hasHeaderGroups && PivotParentColumn.Header
PivotGroupHeader = PivotGroupHeader || (() => <strong>Pivoted</strong>)
let pivotColumnGroup = {
header: () => <strong>Group</strong>,
Header: PivotGroupHeader,
columns: pivotColumns.map(col => ({
...this.props.pivotDefaults,
...col,
@@ -438,7 +454,6 @@ export default Base =>
}
this.setStateWithData(newState, () => {
onPageChange && onPageChange(page)
this.fireFetchData()
})
}
@@ -457,7 +472,6 @@ export default Base =>
},
() => {
onPageSizeChange && onPageSizeChange(newPageSize, newPage)
this.fireFetchData()
}
)
}
@@ -570,7 +584,6 @@ export default Base =>
},
() => {
onSortedChange && onSortedChange(newSorted, column, additive)
this.fireFetchData()
}
)
}
@@ -599,12 +612,12 @@ export default Base =>
},
() => {
onFilteredChange && onFilteredChange(newFiltering, column, value)
this.fireFetchData()
}
)
}
resizeColumnStart (column, event, isTouch) {
resizeColumnStart (event, column, isTouch) {
event.stopPropagation()
const parentWidth = event.target.parentElement.getBoundingClientRect()
.width
@@ -615,6 +628,7 @@ export default Base =>
pageX = event.pageX
}
this.trapEvents = true
this.setStateWithData(
{
currentlyResizing: {
@@ -637,33 +651,8 @@ export default Base =>
)
}
resizeColumnEnd (event) {
let isTouch = event.type === 'touchend' || event.type === 'touchcancel'
if (isTouch) {
document.removeEventListener('touchmove', this.resizeColumnMoving)
document.removeEventListener('touchcancel', this.resizeColumnEnd)
document.removeEventListener('touchend', this.resizeColumnEnd)
}
// If its a touch event clear the mouse one's as well because sometimes
// the mouseDown event gets called as well, but the mouseUp event doesn't
document.removeEventListener('mousemove', this.resizeColumnMoving)
document.removeEventListener('mouseup', this.resizeColumnEnd)
document.removeEventListener('mouseleave', this.resizeColumnEnd)
// The touch events don't propagate up to the sorting's onMouseDown event so
// no need to prevent it from happening or else the first click after a touch
// event resize will not sort the column.
if (!isTouch) {
this.setStateWithData({
skipNextSort: true,
currentlyResizing: false,
})
}
}
resizeColumnMoving (event) {
event.stopPropagation()
const { onResizedChange } = this.props
const { resized, currentlyResizing } = this.getResolvedState()
@@ -698,4 +687,31 @@ export default Base =>
}
)
}
resizeColumnEnd (event) {
event.stopPropagation()
let isTouch = event.type === 'touchend' || event.type === 'touchcancel'
if (isTouch) {
document.removeEventListener('touchmove', this.resizeColumnMoving)
document.removeEventListener('touchcancel', this.resizeColumnEnd)
document.removeEventListener('touchend', this.resizeColumnEnd)
}
// If its a touch event clear the mouse one's as well because sometimes
// the mouseDown event gets called as well, but the mouseUp event doesn't
document.removeEventListener('mousemove', this.resizeColumnMoving)
document.removeEventListener('mouseup', this.resizeColumnEnd)
document.removeEventListener('mouseleave', this.resizeColumnEnd)
// The touch events don't propagate up to the sorting's onMouseDown event so
// no need to prevent it from happening or else the first click after a touch
// event resize will not sort the column.
if (!isTouch) {
this.setStateWithData({
skipNextSort: true,
currentlyResizing: false,
})
}
}
}
+9 -3
View File
@@ -19,6 +19,7 @@ export default {
compactObject,
isSortingDesc,
normalizeComponent,
asPx,
}
function get (obj, path, def) {
@@ -142,6 +143,11 @@ function groupBy (xs, key) {
}, {})
}
function asPx (value) {
value = Number(value)
return Number.isNaN(value) ? null : value + 'px'
}
function isArray (a) {
return Array.isArray(a)
}
@@ -153,8 +159,8 @@ function isArray (a) {
function makePathArray (obj) {
return flattenDeep(obj)
.join('.')
.replace('[', '.')
.replace(']', '')
.replace(/\[/g, '.')
.replace(/\]/g, '')
.split('.')
}
@@ -173,7 +179,7 @@ function splitProps ({ className, style, ...rest }) {
return {
className,
style,
rest,
rest: rest || {},
}
}