-
-
Notifications
You must be signed in to change notification settings - Fork 73
Issue 256, 257, 608 - Add conditional styling capabilities #729
Changes from 2 commits
edc3bf1
a02c8d3
09d7f53
6ce6ef6
4fa6feb
fe025ef
c843e7e
6e007b3
e8257d4
de55351
ee5b9ff
6f93020
6a0bc64
2af76ce
b6d6300
43c00fb
56b29fb
1db84eb
df99bf6
622325b
ce95cfc
65df9b2
254fb2c
b8d482c
7252b03
53753e1
7e9601b
345918a
bb1f6e5
8085950
e6d05fb
d387aae
e3d6fca
8350c64
b5065ef
22fc0ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,11 @@ import { ColumnId, Datum, ColumnType, IColumn } from 'dash-table/components/Tabl | |
import { QuerySyntaxTree } from 'dash-table/syntax-tree'; | ||
import { IConvertedStyle } from 'dash-table/derived/style'; | ||
|
||
export interface IActiveElement { | ||
is_active?: boolean; | ||
is_selected?: boolean; | ||
} | ||
|
||
export interface IConditionalElement { | ||
filter_query?: string; | ||
} | ||
|
@@ -13,11 +18,11 @@ export interface IIndexedHeaderElement { | |
} | ||
|
||
export interface IIndexedRowElement { | ||
row_index?: number | 'odd' | 'even'; | ||
row_index?: number[] | number | 'odd' | 'even'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Support array of values |
||
} | ||
|
||
export interface INamedElement { | ||
column_id?: ColumnId; | ||
column_id?: ColumnId[] | ColumnId; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Support array of values |
||
} | ||
|
||
export interface ITypedElement { | ||
|
@@ -29,17 +34,31 @@ export interface IEditableElement { | |
} | ||
|
||
export type ConditionalBasicFilter = INamedElement & ITypedElement; | ||
export type ConditionalDataCell = IConditionalElement & IIndexedRowElement & INamedElement & ITypedElement & IEditableElement; | ||
export type ConditionalDataCell = IActiveElement & IConditionalElement & IIndexedRowElement & INamedElement & ITypedElement & IEditableElement; | ||
export type ConditionalCell = INamedElement & ITypedElement; | ||
export type ConditionalHeader = IIndexedHeaderElement & INamedElement & ITypedElement; | ||
|
||
function ifAstFilter(ast: QuerySyntaxTree, datum: Datum) { | ||
return ast.isValid && ast.evaluate(datum); | ||
} | ||
|
||
export function ifColumnActive(condition: IActiveElement | undefined, active: boolean, selected: boolean) { | ||
if (!condition) { | ||
return true; | ||
} | ||
|
||
// Apply active if active, apply selected if selected AND not active (active and selected styling don't overlap) | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return (condition.is_active === undefined || active === condition.is_active) && | ||
(condition.is_selected === undefined || (selected === condition.is_selected && !active)); | ||
} | ||
|
||
export function ifColumnId(condition: INamedElement | undefined, columnId: ColumnId) { | ||
return !condition || | ||
condition.column_id === undefined || | ||
if (!condition || condition.column_id === undefined) { | ||
return true; | ||
} | ||
|
||
return Array.isArray(condition.column_id) ? | ||
R.contains(columnId, condition.column_id) : | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
condition.column_id === columnId; | ||
} | ||
|
||
|
@@ -56,9 +75,11 @@ export function ifRowIndex(condition: IIndexedRowElement | undefined, rowIndex: | |
} | ||
|
||
const rowCondition = condition.row_index; | ||
return typeof rowCondition === 'number' ? | ||
rowIndex === rowCondition : | ||
rowCondition === 'odd' ? rowIndex % 2 === 1 : rowIndex % 2 === 0; | ||
return typeof rowCondition === 'string' ? | ||
rowCondition === 'odd' ? rowIndex % 2 === 1 : rowIndex % 2 === 0 : | ||
Array.isArray(rowCondition) ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check for array |
||
R.contains(rowIndex, rowCondition) : | ||
rowIndex === rowCondition; | ||
} | ||
|
||
export function ifHeaderIndex(condition: IIndexedHeaderElement | undefined, headerIndex: number) { | ||
|
@@ -68,9 +89,11 @@ export function ifHeaderIndex(condition: IIndexedHeaderElement | undefined, head | |
} | ||
|
||
const headerCondition = condition.header_index; | ||
return typeof headerCondition === 'number' ? | ||
headerIndex === headerCondition : | ||
headerCondition === 'odd' ? headerIndex % 2 === 1 : headerIndex % 2 === 0; | ||
return typeof headerCondition === 'string' ? | ||
headerCondition === 'odd' ? headerIndex % 2 === 1 : headerIndex % 2 === 0 : | ||
Marc-Andre-Rivet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Array.isArray(headerCondition) ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check for array |
||
R.contains(headerIndex, headerCondition) : | ||
headerIndex === headerCondition; | ||
} | ||
|
||
export function ifFilter(condition: IConditionalElement | undefined, datum: Datum) { | ||
|
@@ -89,13 +112,20 @@ export function ifEditable(condition: IEditableElement | undefined, isEditable: | |
|
||
export type Filter<T> = (s: T[]) => T[]; | ||
|
||
export const matchesDataCell = (datum: Datum, i: number, column: IColumn): Filter<IConvertedStyle> => R.filter<IConvertedStyle>((style => | ||
export const matchesDataCell = ( | ||
datum: Datum, | ||
i: number, column: IColumn, | ||
active: boolean, | ||
selected: boolean | ||
): Filter<IConvertedStyle> => R.filter<IConvertedStyle>((style => | ||
style.matchesActive(active, selected) && | ||
style.matchesRow(i) && | ||
style.matchesColumn(column) && | ||
style.matchesFilter(datum) | ||
)); | ||
|
||
export const matchesFilterCell = (column: IColumn): Filter<IConvertedStyle> => R.filter<IConvertedStyle>((style => | ||
!style.checksActive() && | ||
style.matchesColumn(column) | ||
)); | ||
|
||
|
@@ -105,6 +135,7 @@ export const matchesHeaderCell = (i: number, column: IColumn): Filter<IConverted | |
)); | ||
|
||
export const matchesDataOpCell = (datum: Datum, i: number): Filter<IConvertedStyle> => R.filter<IConvertedStyle>((style => | ||
!style.checksActive() && | ||
!style.checksColumn() && | ||
style.matchesRow(i) && | ||
style.matchesFilter(datum) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,12 @@ import * as R from 'ramda'; | |
import { CSSProperties } from 'react'; | ||
|
||
import { memoizeOneFactory } from 'core/memoizer'; | ||
import { Data, Columns, IViewportOffset, SelectedCells } from 'dash-table/components/Table/props'; | ||
import { Data, Columns, IViewportOffset, SelectedCells, ICellCoordinates } from 'dash-table/components/Table/props'; | ||
import { IConvertedStyle, getDataCellStyle, getDataOpCellStyle } from '../style'; | ||
import { traverseMap2, shallowClone } from 'core/math/matrixZipMap'; | ||
|
||
import isActiveCell from 'dash-table/derived/cell/isActive'; | ||
|
||
const SELECTED_CELL_STYLE = { backgroundColor: 'var(--selected-background)' }; | ||
|
||
const partialGetter = ( | ||
|
@@ -16,28 +18,39 @@ const partialGetter = ( | |
) => traverseMap2( | ||
data, | ||
columns, | ||
(datum, column, i) => getDataCellStyle(datum, i + offset.rows, column)(styles) | ||
(datum, column, i) => getDataCellStyle(datum, i + offset.rows, column, false, false)(styles) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Partial getter now assume all cells are active=False, selected=False |
||
); | ||
|
||
const getter = ( | ||
styles: CSSProperties[][], | ||
baseline: CSSProperties[][], | ||
columns: Columns, | ||
styles: IConvertedStyle[], | ||
data: Data, | ||
offset: IViewportOffset, | ||
activeCell: ICellCoordinates, | ||
selectedCells: SelectedCells | ||
) => { | ||
styles = shallowClone(styles); | ||
baseline = shallowClone(baseline); | ||
|
||
R.forEach(({ row: i, column: j }) => { | ||
i -= offset.rows; | ||
j -= offset.columns; | ||
const iNoOffset = i - offset.rows; | ||
const jNoOffset = j - offset.columns; | ||
|
||
if (i < 0 || j < 0 || styles.length <= i || styles[i].length <= j) { | ||
if (iNoOffset < 0 || jNoOffset < 0 || baseline.length <= iNoOffset || baseline[iNoOffset].length <= jNoOffset) { | ||
return; | ||
} | ||
|
||
styles[i][j] = R.merge(styles[i][j], SELECTED_CELL_STYLE); | ||
const active = isActiveCell(activeCell, i, j); | ||
|
||
const style = { | ||
...SELECTED_CELL_STYLE, | ||
...getDataCellStyle(data[i], i + offset.rows, columns[j], active, true)(styles) | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Combine default selected cell styling with calculated style |
||
|
||
baseline[iNoOffset][jNoOffset] = style; | ||
}, selectedCells); | ||
|
||
return styles; | ||
return baseline; | ||
}; | ||
|
||
const opGetter = ( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New styling conditions