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
48 commits
Select commit Hold shift + click to select a range
6bf7a93
- edges generation
Apr 30, 2019
781513e
- tweak border calculations
Apr 30, 2019
afa1f0e
reconcile styles
Apr 30, 2019
2d2bdb4
reconcile edges in transition zones
May 1, 2019
971c265
improve styles applied on operation columns
May 1, 2019
63c5434
improve default props
May 1, 2019
8cd350c
- improved caching
May 1, 2019
e016bb5
- add basic border styling visual tests
May 1, 2019
06ee116
update border style visual tests
May 1, 2019
a6d2fb5
new approach to reconcile borders
May 1, 2019
87ea8f8
fix edge unit tests
May 1, 2019
6d67d68
update edge tests
May 1, 2019
128da30
clean up
May 1, 2019
46cab57
simulacrum of immutability through types
May 1, 2019
5a4253d
Merge branch 'master' into border-colors-2
Marc-Andre-Rivet May 1, 2019
634ddcb
clean up ops vs. other edges usage
May 1, 2019
330f11c
Merge remote-tracking branch 'origin/master' into border-colors
May 1, 2019
ea151ca
- rework
May 1, 2019
204c240
revert filter styling regression
May 1, 2019
f57165f
revert border styling
May 1, 2019
e371078
rework style_as_list_view
May 2, 2019
1ab4982
support active cell styling again
May 2, 2019
307b650
fix active_cell (0,0) case
May 2, 2019
fa197c4
rework active_cell rework...
May 2, 2019
630d3f4
fix edge unit tests
May 2, 2019
6e592b4
fix edge tests
May 2, 2019
dcc9257
var(--accent) active border color (revert)
May 2, 2019
41c46e0
update fixture height to show border as before
May 6, 2019
e679827
simplify undefined test
May 6, 2019
2c1e4d6
edge tests
May 6, 2019
58472ed
additional case
May 6, 2019
525c36d
refactor out filter mapping logic from the filter factory
May 7, 2019
ba26e74
fix filters on update and init
May 8, 2019
2c3f41e
handle fixed rows/columns for edges
May 8, 2019
26ebf34
performance
May 8, 2019
a6ed2e3
remove css overrides & cleanup unused changes
May 8, 2019
d4af434
add it back.. does not handle fixed inside a fragment
May 8, 2019
ce238a4
refactor border style tests
May 8, 2019
2e036f7
fix filter test
May 8, 2019
1c9749f
fix standalone filter reset test
May 8, 2019
bc35085
fix ops columns styling
May 9, 2019
6d1a386
disappearing invalid filter test (will fail)
May 9, 2019
98801b9
fix disappearing invalid filter test
May 9, 2019
2be996f
add new operation columns visual tests
May 9, 2019
ea31de1
messy ops styling
May 9, 2019
f2409c3
update border visual tests
May 10, 2019
0816c53
n_fixed_rows misalignment
May 10, 2019
ea48933
update changelog
May 10, 2019
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
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,26 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- `derived_viewport_selected_row_ids` mirrors `derived_viewport_selected_rows`
- `derived_virtual_selected_row_ids` mirrors `derived_virtual_selected_rows`

[#424](https://github.com/plotly/dash-table/pull/424)
- Customizable cell borders through `style_**` props
- cell borders now no longer use `box-shadow` and use `border` instead
- Supports CSS shorthands:
border, border_bottom, border_left, border_right, border_top
- style_** props will ignore the following CSS rules:
border_bottom_color, border_bottom_left_radius, border_bottom_right_radius, border_bottom_style, border_bottom_width, border_collapse, border_color, border_corner_shape, border_image_source, border_image_width, border_left_color, border_left_style, border_left_width, border_right_color, border_right_style, border_right_width, border_spacing, border_style, border_top_color, border_top_left_radius, border_top_right_radius, border_top_style, border_top_width, border_width
- Styles priority:
1. Props priority in decreasing order
style_data_conditional
style_data
style_filter_conditional
style_filter
style_header_conditional
style_header
style_cell_conditional
style_cell
2. Within each props, higher index rules win over lower index rules
3. Previously applied styles of equal priority win over later ones (applied top to bottom, left to right)

### Changed
[#397](https://github.com/plotly/dash-table/pull/397)
- Rename `filtering_settings` to `filter`
Expand Down
15 changes: 14 additions & 1 deletion src/core/environment/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { DebugLevel, LogLevel } from 'core/Logger';
import CookieStorage from 'core/storage/Cookie';
import { DebugLevel, LogLevel } from 'core/Logger';

import { Edge } from 'dash-table/derived/edges/type';

const DASH_DEBUG = 'dash_debug';
const DASH_LOG = 'dash_log';

const DEFAULT_EDGE: Edge = '1px solid #d3d3d3';
const ACTIVE_EDGE: Edge = '1px solid var(--accent)';

interface ISearchParams {
get: (key: string) => string | null;
}
Expand Down Expand Up @@ -33,4 +38,12 @@ export default class Environment {
(LogLevel as any)[log] || LogLevel.ERROR :
LogLevel.ERROR;
}

public static get defaultEdge(): Edge {
return DEFAULT_EDGE;
}

public static get activeEdge(): Edge {
return ACTIVE_EDGE;
}
}
11 changes: 10 additions & 1 deletion src/core/math/arrayZipMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@ import * as R from 'ramda';

type Array<T> = T[];

export function arrayMap<T1, T2, TR>(
export function arrayMap<T1, TR>(
a1: Array<T1>,
cb: (d1: T1, i: number) => TR
) {
const mapArray = R.addIndex<T1, TR>(R.map);

return mapArray((iValue, i) => cb(iValue, i), a1);
}
Comment thread
Marc-Andre-Rivet marked this conversation as resolved.

export function arrayMap2<T1, T2, TR>(
a1: Array<T1>,
a2: Array<T2>,
cb: (d1: T1, d2: T2, i: number) => TR
Expand Down
75 changes: 57 additions & 18 deletions src/core/math/matrixZipMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,109 @@ import * as R from 'ramda';

type Matrix<T> = T[][];

export function matrixMap<T1, T2, TR>(
export function matrixMap<T1, TR>(
m1: Matrix<T1>,
m2: Matrix<T2>,
cb: (d1: T1, d2: T2, i: number, j: number) => TR
cb: (d1: T1, i: number, j: number) => TR
) {
const mapMatrix = R.addIndex<T1[], TR[]>(R.map);
const mapRow = R.addIndex<T1, TR>(R.map);

return mapMatrix((iRow, i) =>
mapRow(
(ijValue, j) => cb(ijValue, m2[i][j], i, j),
(ijValue, j) => cb(ijValue, i, j),
iRow
), m1
);
}

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.

Adding a 1-matrix map -- otherwise all below is essentially dealing with undefined cases


export function matrixMap2<T1, T2, TR>(
m1: Matrix<T1>,
m2: Matrix<T2> | undefined,
cb: (d1: T1, d2: T2 | undefined, i: number, j: number) => TR
) {
const mapMatrix = R.addIndex<T1[], TR[]>(R.map);
const mapRow = R.addIndex<T1, TR>(R.map);

return mapMatrix((iRow, i) =>
mapRow(
(ijValue, j) => cb(
ijValue,
m2 ? m2[i][j] : undefined,
i,
j
),
iRow
), m1
);
}

export function matrixMap3<T1, T2, T3, TR>(
m1: Matrix<T1>,
m2: Matrix<T2>,
m3: Matrix<T3>,
cb: (d1: T1, d2: T2, d3: T3, i: number, j: number) => TR
m2: Matrix<T2> | undefined,
m3: Matrix<T3> | undefined,
cb: (d1: T1, d2: T2 | undefined, d3: T3 | undefined, i: number, j: number) => TR
) {
const mapMatrix = R.addIndex<T1[], TR[]>(R.map);
const mapRow = R.addIndex<T1, TR>(R.map);

return mapMatrix((iRow, i) =>
mapRow(
(ijValue, j) => cb(ijValue, m2[i][j], m3[i][j], i, j),
(ijValue, j) => cb(
ijValue,
m2 ? m2[i][j] : undefined,
m3 ? m3[i][j] : undefined,
i,
j
),
iRow
), m1
);
}

export function matrixMap4<T1, T2, T3, T4, TR>(
m1: Matrix<T1>,
m2: Matrix<T2>,
m3: Matrix<T3>,
m4: Matrix<T4>,
cb: (d1: T1, d2: T2, d3: T3, d4: T4, i: number, j: number) => TR
m2: Matrix<T2> | undefined,
m3: Matrix<T3> | undefined,
m4: Matrix<T4> | undefined,
cb: (d1: T1, d2: T2 | undefined, d3: T3 | undefined, d4: T4 | undefined, i: number, j: number) => TR
) {
const mapMatrix = R.addIndex<T1[], TR[]>(R.map);
const mapRow = R.addIndex<T1, TR>(R.map);

return mapMatrix((iRow, i) =>
mapRow(
(ijValue, j) => cb(ijValue, m2[i][j], m3[i][j], m4[i][j], i, j),
(ijValue, j) => cb(
ijValue,
m2 ? m2[i][j] : undefined,
m3 ? m3[i][j] : undefined,
m4 ? m4[i][j] : undefined,
i,
j
),
iRow
), m1
);
}

export function matrixMapN<TR>(
cb: (i: number, j: number, ...args: any[]) => TR,
...matrices: (any[][])[]
m1: Matrix<any>,
...matrices: (any[][] | undefined)[]
) {
const m1 = matrices.slice(0, 1);
const ms = matrices.slice(1);

const mapMatrix = R.addIndex<any[], TR[]>(R.map);
const mapRow = R.addIndex<any, TR>(R.map);

return mapMatrix((iRow, i) =>
mapRow(
(ijValue, j) => cb(i, j, [ijValue, ...ms.map(m => m[i][j])]),
(ijValue, j) => cb(
i,
j,
[
ijValue,
m1[i][j],
...matrices.map(m => m ? m[i][j] : undefined)
]
),
iRow
), m1
);
Expand Down
8 changes: 8 additions & 0 deletions src/core/type/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
export type OptionalMap<T, TR extends keyof T, M> = {
[tr in TR]?: M
};
export type RequiredPluck<T, R extends keyof T> = { [r in R]: T[r] };
export type OptionalPluck<T, R extends keyof T> = { [r in R]?: T[r] };

export type RequiredProp<T, R extends keyof T> = T[R];
export type OptionalProp<T, R extends keyof T> = T[R] | undefined;

export type PropOf<T, R extends keyof T> = R;

@Marc-Andre-Rivet Marc-Andre-Rivet May 1, 2019

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.

Just defining some types to do TypeScript stuff later..

76 changes: 52 additions & 24 deletions src/dash-table/components/CellFactory.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import * as R from 'ramda';
import React from 'react';

import { matrixMap2, matrixMap3 } from 'core/math/matrixZipMap';
import { arrayMap2 } from 'core/math/arrayZipMap';

import { ICellFactoryProps } from 'dash-table/components/Table/props';
import derivedCellWrappers from 'dash-table/derived/cell/wrappers';
import derivedCellContents from 'dash-table/derived/cell/contents';
import derivedCellOperations from 'dash-table/derived/cell/operations';
import derivedCellStyles from 'dash-table/derived/cell/wrapperStyles';
import derivedCellStyles, { derivedDataOpStyles } from 'dash-table/derived/cell/wrapperStyles';
import derivedDropdowns from 'dash-table/derived/cell/dropdowns';
import { derivedRelevantCellStyles } from 'dash-table/derived/style';

import { matrixMap3 } from 'core/math/matrixZipMap';
import { arrayMap } from 'core/math/arrayZipMap';
import { IEdgesMatrices } from 'dash-table/derived/edges/type';

export default class CellFactory {

Expand All @@ -23,11 +25,12 @@ export default class CellFactory {
private readonly cellDropdowns = derivedDropdowns(),
private readonly cellOperations = derivedCellOperations(),
private readonly cellStyles = derivedCellStyles(),
private readonly dataOpStyles = derivedDataOpStyles(),
private readonly cellWrappers = derivedCellWrappers(propsFn),
private readonly relevantStyles = derivedRelevantCellStyles()
) { }

public createCells() {
public createCells(dataEdges: IEdgesMatrices | undefined, dataOpEdges: IEdgesMatrices | undefined) {
const {
active_cell,
columns,
Expand All @@ -49,30 +52,27 @@ export default class CellFactory {
virtualized
} = this.props;

const operations = this.cellOperations(
data,
virtualized.data,
virtualized.indices,
row_selectable,
row_deletable,
selected_rows,
setProps
);

const relevantStyles = this.relevantStyles(
style_cell,
style_data,
style_cell_conditional,
style_data_conditional
);

const wrapperStyles = this.cellStyles(
const cellStyles = this.cellStyles(
columns,
relevantStyles,
virtualized.data,
virtualized.offset
);

const dataOpStyles = this.dataOpStyles(
(row_selectable ? 1 : 0) + (row_deletable ? 1 : 0),
relevantStyles,
virtualized.data,
virtualized.offset
);

const dropdowns = this.cellDropdowns(
columns,
virtualized.data,
Expand All @@ -82,15 +82,25 @@ export default class CellFactory {
dropdown_properties
);

const wrappers = this.cellWrappers(
const operations = this.cellOperations(
data,
virtualized.data,
virtualized.indices,
row_selectable,
row_deletable,
selected_rows,
setProps
);

const cellWrappers = this.cellWrappers(
active_cell,
columns,
virtualized.data,
virtualized.offset,
selected_cells
);

const contents = this.cellContents(
const cellContents = this.cellContents(
active_cell,
columns,
virtualized.data,
Expand All @@ -100,15 +110,33 @@ export default class CellFactory {
dropdowns
);

const ops = matrixMap2(
operations,
dataOpStyles,
(o, s, i, j) => React.cloneElement(o, {
style: R.mergeAll([
dataOpEdges && dataOpEdges.getStyle(i, j),
s,
o.props.style
])
})
);

const cells = matrixMap3(
wrappers,
wrapperStyles,
contents,
(w, s, c) => React.cloneElement(w, { children: [c], style: s })
cellWrappers,
cellStyles,
cellContents,
(w, s, c, i, j) => React.cloneElement(w, {
children: [c],
style: R.mergeAll([
s,
dataEdges && dataEdges.getStyle(i, j)

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.

Here and above in ops, obtaining the calculated borders for this specific cell

])
})
);

return arrayMap(
operations,
return arrayMap2(
ops,
cells,
(o, c) => Array.prototype.concat(o, c)
);
Expand Down
Loading