Skip to content
This repository was archived by the owner on Aug 29, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
2af1d3e
WIP
Sep 27, 2018
0646dc0
wip
Sep 27, 2018
cdb93f5
wip
Sep 27, 2018
50053fa
further down the rabbit hole..
Sep 27, 2018
fcc1edb
Merge remote-tracking branch 'origin/develop' into 3.1-refactor-cells…
Sep 27, 2018
70048e2
fix dropdown navigation regression
Sep 27, 2018
d5bed92
fix selected row regression
Sep 28, 2018
f03d02f
renaming / restructuring
Sep 28, 2018
7bebb9d
rename/restructure
Sep 28, 2018
4473467
- clean up zipping
Sep 28, 2018
966681f
rework style/ast cache
Sep 28, 2018
75736ed
clean up
Sep 28, 2018
219da49
clean up
Sep 28, 2018
1bbc70e
build update
Sep 28, 2018
172d3ab
improve rendering perf
Sep 28, 2018
ed7053c
optimize wrappers generation
Sep 28, 2018
1d93552
build config
Sep 28, 2018
b91af6a
- fix typing regression
Oct 1, 2018
72231b8
- fix navigation regression
Oct 1, 2018
61d3b74
simplify slightly the derived props / ui
Oct 1, 2018
443d380
fix copy/paste regressions
Oct 1, 2018
47be714
clean up wrapper props
Oct 1, 2018
4c16af0
clean up
Oct 1, 2018
c4a3609
merge with develop
Oct 1, 2018
54a9b49
fix regression on conditional dropdowns
Oct 2, 2018
617ce7b
wip, fp the headers
Oct 2, 2018
caecaf5
fp content, wrappers, labels, indices from header factory
Oct 2, 2018
e8b6751
fix regressions
Oct 2, 2018
f3b4671
fp the table itself
Oct 2, 2018
bf28720
fix typing and behavior for table fp
Oct 2, 2018
dd47d51
Merge remote-tracking branch 'origin/develop' into 3.1-refactor-cells…
Oct 3, 2018
b3cee9f
fix sorting icon regression
Oct 3, 2018
a177af2
fix regression
Oct 3, 2018
0c7be88
regression
Oct 3, 2018
d85c35f
fix column name regression with only 1 header row
Oct 3, 2018
1544031
fix header actions regression
Oct 3, 2018
9334516
Merge remote-tracking branch 'origin/develop' into 3.1-refactor-cells…
Oct 3, 2018
0af48b8
Merge pull request #122 from plotly/107-save-on-tab
valentijnnieman Oct 3, 2018
89fdd74
add width percentage support + content_style
Oct 3, 2018
ed6c5c9
fix style application on mount
Oct 3, 2018
7c4ea41
Merge remote-tracking branch 'origin/master' into issue-118-width-beh…
Oct 3, 2018
4479b3f
fix visual regression with empty df
Oct 4, 2018
23e0da7
only apply row style when necessary
Oct 4, 2018
453ad08
Merge remote-tracking branch 'origin/master' into develop
Oct 4, 2018
ec5f601
fix tab test (no offset)
Oct 4, 2018
114c3b8
clean up header styling
Oct 4, 2018
d0d4217
use dash-* classes
Oct 4, 2018
e62800f
support default column width (override input behavior)
Oct 4, 2018
0cd7e2c
fix regression edit cell in n-th page
Oct 4, 2018
7a0b167
fix editing on non-first page (continued)
Oct 4, 2018
fd2ec45
merge develop into 3.1-refactor-cell-rendering
Oct 4, 2018
8033eb8
fix test
Oct 4, 2018
4935887
fit to content behavior
Oct 5, 2018
3afa253
fix regressions
Oct 5, 2018
b83bb86
fix lint
Oct 5, 2018
995f1da
Merge remote-tracking branch 'origin/3.1-refactor-cells-rendering' in…
Oct 5, 2018
3de7cb4
Merge remote-tracking branch 'origin/develop' into 3.1-issue118-width…
Oct 5, 2018
b059da4
add column width visual tests
Oct 9, 2018
a7bd135
fix dropdown minimum size when using default width
Oct 9, 2018
70ebd67
sizing examples
Oct 9, 2018
586babd
black
Oct 9, 2018
8f86751
fix navigation test regression
Oct 9, 2018
ab03404
fix regressions in visual tests
Oct 10, 2018
f84a0b4
default column width - fix dropdown width eval
Oct 10, 2018
00553a7
default width columns
Oct 10, 2018
ab9b192
percy - add delay before screenshot (attempt to fix FF visual tests)
Oct 10, 2018
9c92a63
debugging selenium
Oct 10, 2018
b4e521e
fix black
Oct 10, 2018
55efbe3
debug selenium
Oct 10, 2018
0b98396
debug selenium
Oct 10, 2018
6b2ba8b
fix black
Oct 10, 2018
529fcf2
debug selenium
Oct 10, 2018
ec6a6f2
debug selenium
Oct 10, 2018
da48b49
debug selenium
Oct 10, 2018
766cbc7
undo all selenium modifications
Oct 10, 2018
d064508
default column width
Oct 10, 2018
8e8429f
- fixed rows+columns height evaluated correctly
Oct 10, 2018
2283fc8
remove dead code
Oct 10, 2018
3f64aa1
remove .only from tests
Oct 10, 2018
c3cb872
add data-dash-column to filter cells
Oct 10, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,41 @@ Derived properties allow the component to expose complex state that can be usefu

## RC3 - Miscellaneous fixes for pagination, virtual df and viewport df

Issue: https://github.com/plotly/dash-table/pull/112
Issue: https://github.com/plotly/dash-table/pull/112

## RC4 - Columns width percentage and default (fit to content) support

* Added prop content_style that takes values 'fit' or 'grow' (Default='fit')
* Added width percentage support
* Modified default column behavior from fixed width to 'fit content'
* Modified width, min-width, max-width interaction on columns

### Width percentage

Columns can now accept '%' width, minWidth, maxWidth

For the percentages to have meaning, the dash-table must be forced to have a width and the content of the dash-table must be forced to grow to fill the available space made available by the container (by default the table is only as big as it needs to be).

To use percentage-based column widths, add:

* content style
content_style='grow'

* table style (example)
table_style=[{ selector: '.dash-spreadsheet', rule: 'width: 100%; max-width: 100%' }]

* column with %-based width
columns=[{
id: 'column',
width: '40%'
}]

### Default column width

Columns now default to 'fit to content' when no width is defined

Note: If pagination is used or the dataframe modified, the column width will be re-evaluated on each modification.

### Interaction between width, min-width and max-width

Column min-width and max-width do not default to width value is not defined.
6 changes: 3 additions & 3 deletions dash_table/bundle.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dash_table/demo.js

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions dash_table/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,27 @@
"computed": false
}
},
"content_style": {
"type": {
"name": "enum",
"value": [
{
"value": "'fit'",
"computed": false
},
{
"value": "'grow'",
"computed": false
}
]
},
"required": false,
"description": "",
"defaultValue": {
"value": "'fit'",
"computed": false
}
},
"dataframe": {
"type": {
"name": "arrayOf",
Expand Down
2 changes: 1 addition & 1 deletion dash_table/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dash-table",
"version": "3.1.0rc3",
"version": "3.1.0rc4",
"description": "Dash table",
"main": "build/index.js",
"scripts": {
Expand Down
2 changes: 2 additions & 0 deletions demo/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class App extends Component {
columns: clone(mockData.columns).map(col => R.merge(col, {
editable_name: true,
deletable: true,
minWidth: col.width,
maxWidth: col.width

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep existing demo app behavior exactly as it was before

// type: 'dropdown'
})),
editable: true,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dash-table",
"version": "3.1.0rc3",
"version": "3.1.0rc4",
"description": "Dash table",
"main": "build/index.js",
"scripts": {
Expand Down
1 change: 0 additions & 1 deletion src/core/Stylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export default class Stylesheet {

const result = this.stylesheet.findRule(selector);
if (result) {

if (result.rule.cssText === css || result.rule.cssText === `${selector} { ${css} }`) {
return;
} else {
Expand Down
18 changes: 18 additions & 0 deletions src/core/browser/DOM.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default class DOM {
public static getFirstParentOfType(element: HTMLElement, type: string): HTMLElement | undefined {
type = type.toUpperCase();

let current: HTMLElement = element;
while (current) {
if (current.tagName.toUpperCase() === type) {
return current;
}

if (current.parentElement !== null) {
current = current.parentElement;
} else {
return;
}
}
}
}
2 changes: 2 additions & 0 deletions src/dash-table/Table.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const defaultProps = {
},
navigation: 'page',

content_style: 'fit',
filtering: false,
filtering_settings: '',
filtering_type: 'basic',
Expand Down Expand Up @@ -78,6 +79,7 @@ export const defaultProps = {
export const propTypes = {
active_cell: PropTypes.array,
columns: PropTypes.arrayOf(PropTypes.object),
content_style: PropTypes.oneOf(['fit', 'grow']),

dataframe: PropTypes.arrayOf(PropTypes.object),
dataframe_previous: PropTypes.arrayOf(PropTypes.object),
Expand Down
66 changes: 41 additions & 25 deletions src/dash-table/components/CellInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import React, {
} from 'react';
import Dropdown from 'react-select';

import DOM from 'core/browser/DOM';

import {
ICellDefaultProps,
ICellProps,
Expand Down Expand Up @@ -46,17 +48,23 @@ export default class CellInput extends PureComponent<ICellProps, ICellState> {

return !dropdown ?
this.renderValue() :
(<Dropdown
ref='dropdown'
clearable={clearable}
onChange={(newValue: any) => {
onChange(newValue ? newValue.value : newValue);
}}
onOpen={this.handleOpenDropdown}
options={dropdown}
placeholder={''}
value={value}
/>);
(<div className='dash-dropdown-cell-value-container dash-cell-value-container'>
{this.renderValue(
{ className: 'dropdown-cell-value-shadow cell-value-shadow' },
(dropdown.find(entry => entry.value === value) || { label: undefined }).label

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the label associated with the value, not the value itself for the shadow field

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the input, the shadow div is used to size the table when using default column size

)}
<Dropdown
ref='dropdown'
clearable={clearable}
onChange={(newValue: any) => {
onChange(newValue ? newValue.value : newValue);
}}
onOpen={this.handleOpenDropdown}
options={dropdown}
placeholder={''}
value={value}
/>
</div>);
}

private renderInput() {
Expand All @@ -80,22 +88,27 @@ export default class CellInput extends PureComponent<ICellProps, ICellState> {
onDoubleClick: onDoubleClick
};

return (!active && this.state.value === this.props.value) ?
const readonly = !active && this.state.value === this.props.value;

return readonly ?
this.renderValue(attributes) :
(<input
ref='textInput'
type='text'
value={this.state.value}
onBlur={this.propagateChange}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
onPaste={onPaste}
{...attributes}
/>);
(<div className='dash-input-cell-value-container dash-cell-value-container'>
{this.renderValue({ className: 'input-cell-value-shadow cell-value-shadow' })}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shadow div vor column size

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain this shadow div stuff for me in more detail? Looks interesting, but not sure why it is needed.

@Marc-Andre-Rivet Marc-Andre-Rivet Oct 10, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When not applying a width to the columns, the columns are using the width of the content to decide what size they need to be. Since inputs force the width to be a lot bigger (inputs don't exactly respect normal width/sizing flow) than necessary (~150px) they create this undesirable effect of making columns bigger when a text|number cell is selected. That happens because text|number cells don't actually contain an input element when they are not selected, they just contain a div that shows the value (having thousands of inputs in a page causes significant slowdowns for all webkit based browsers, possibly others too) -- so.. since the input is alone in the table it's capable of forcing columns into a different size..

To prevent that, the input is made to be absolutely positioned and to fill the cell. Since the selected cell might be the one causing the column to have its current width, something has to force the column width when that input is present instead of the div.. hence the shadow div with the same style as the other normal div + some stuff to make it essentially invisible / have no impact on the render for the user.

@Marc-Andre-Rivet Marc-Andre-Rivet Oct 10, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't find this solution awesome to be honest but short of figuring out (1) another way for inputs to respect the width (or have decent perf with 1k+ inputs) and (2) force dropdowns to take the actual amount of space they are supposed to do (hint: there's absolute positioning the Select implementation, so that's not really for us to decide), I don't see a better way to do this for now.

<input
ref='textInput'
type='text'
value={this.state.value}
onBlur={this.propagateChange}
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
onPaste={onPaste}
{...attributes}
/>
</div>);
}

private renderValue(attributes = {}) {
const { value } = this.propsWithDefaults;
private renderValue(attributes = {}, value?: string) {
value = value || this.propsWithDefaults.value;

return (<div
{...attributes}
Expand Down Expand Up @@ -175,7 +188,10 @@ export default class CellInput extends PureComponent<ICellProps, ICellState> {

if (dropdown && document.activeElement !== dropdown) {
// Limitation. If React >= 16 --> Use React.createRef instead to pass parent ref to child
(dropdown.wrapper.parentElement as HTMLElement).focus();
const tdParent = DOM.getFirstParentOfType(dropdown.wrapper, 'td');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cell structure changed a bit, we want the grandparent element, generalizing to finding first parent in hierarchy that matches expected type

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe here you could try using refs too instead of manual DOM searching, they're not a React 16 specific feature, here's how they're used in 15 I believe: https://reactjs.org/docs/refs-and-the-dom.html#callback-refs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wrapper is not accessible from the child (input) and the child is not accessible from the parent (injected through children) -- React 16 offers a new way to pass a parent ref into a child and that's what I had in mind for the future. I can see if I can do something here to make it better.

@Marc-Andre-Rivet Marc-Andre-Rivet Oct 10, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the ref approach is not good for practical reasons: We create the wrapper and clone it to include the child. At which point we would need to clone the child to insert the wrapper ref, which now points to the wrong child instance. Etc.

if (tdParent) {
tdParent.focus();
}
}
}
}
Loading