Skip to content

Commit

Permalink
feat: color table rows if first attribute of collection is color attr…
Browse files Browse the repository at this point in the history
…ibute (#1226)
  • Loading branch information
kswenson authored Apr 23, 2024
1 parent 49ac01a commit 844bf14
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 33 deletions.
5 changes: 3 additions & 2 deletions v3/src/components/case-table/case-table-types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
CalculatedColumn, CellClickArgs, ColSpanArgs, Column, RenderEditCellProps, RenderCellProps, RenderHeaderCellProps,
RenderRowProps, RowsChangeData
CalculatedColumn, CellClickArgs, ColSpanArgs, Column, RenderCellProps, RenderEditCellProps, Renderers,
RenderHeaderCellProps, RenderRowProps, RowsChangeData
} from "react-data-grid"
import { IGroupedCase, symFirstChild } from "../../models/data/data-set-types"

Expand All @@ -18,6 +18,7 @@ export interface TRow extends IGroupedCase {
export interface TRowsChangeData extends RowsChangeData<TRow> {}
export interface TColumn extends Column<TRow> {}
export interface TCalculatedColumn extends CalculatedColumn<TRow> {}
export interface TRenderers extends Renderers<TRow, unknown> {}
export interface TRenderEditCellProps extends RenderEditCellProps<TRow> {}
export interface TRenderCellProps extends RenderCellProps<TRow> {}
export interface TRenderHeaderCellProps extends RenderHeaderCellProps<TRow> {}
Expand Down
22 changes: 10 additions & 12 deletions v3/src/components/case-table/case-table.scss
Original file line number Diff line number Diff line change
Expand Up @@ -255,19 +255,17 @@ $table-body-font-size: 8pt;
}
}

.cell-span {
.cell-color-swatch {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.cell-color-swatch {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;

.cell-color-swatch-interior {
width: calc(100% - 4px);
height: calc(100% - 8px);
margin-top: 0.5px;
}
.cell-color-swatch-interior {
width: calc(100% - 4px);
height: calc(100% - 8px);
margin-top: 0.5px;
}
}

Expand Down
8 changes: 6 additions & 2 deletions v3/src/components/case-table/collection-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { observer } from "mobx-react-lite"
import React, { useCallback, useEffect, useRef } from "react"
import DataGrid, { DataGridHandle } from "react-data-grid"
import { kCollectionTableBodyDropZoneBaseId } from "./case-table-drag-drop"
import { OnScrollClosestRowIntoViewFn, OnTableScrollFn, TRow } from "./case-table-types"
import { OnScrollClosestRowIntoViewFn, OnTableScrollFn, TRenderers, TRow } from "./case-table-types"
import { CollectionTableSpacer } from "./collection-table-spacer"
import { CollectionTitle } from "./collection-title"
import { customRenderRow } from "./custom-row"
import { useColumns } from "./use-columns"
import { useIndexColumn } from "./use-index-column"
import { useRows } from "./use-rows"
Expand All @@ -25,6 +26,9 @@ import styles from "./case-table-shared.scss"

type OnNewCollectionDropFn = (dataSet: IDataSet, attrId: string, beforeCollectionId: string) => void

// custom renderers for use with RDG
const renderers: TRenderers = { renderRow: customRenderRow }

interface IProps {
onMount: (collectionId: string) => void
onNewCollectionDrop: OnNewCollectionDropFn
Expand Down Expand Up @@ -130,7 +134,7 @@ export const CollectionTable = observer(function CollectionTable(props: IProps)
<CollectionTableSpacer onDrop={handleNewCollectionDrop} />
<div className="collection-table-and-title">
<CollectionTitle />
<DataGrid ref={gridRef} className="rdg-light" data-testid="collection-table-grid"
<DataGrid ref={gridRef} className="rdg-light" data-testid="collection-table-grid" renderers={renderers}
columns={columns} rows={rows} headerRowHeight={+styles.headerRowHeight} rowKeyGetter={rowKey}
rowHeight={+styles.bodyRowHeight} selectedRows={selectedRows} onSelectedRowsChange={setSelectedRows}
columnWidths={columnWidths.current} onColumnResize={handleColumnResize}
Expand Down
2 changes: 1 addition & 1 deletion v3/src/components/case-table/collection-title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const CollectionTitle = observer(function CollectionTitle() {
const data = useDataSetContext()
const collectionId = useCollectionContext()
const collection = data?.getCollection(collectionId)
const collectionName = collection?.name ?? ""
const collectionName = collection?.name || t("DG.AppController.createDataSet.collectionName")
const { isTileSelected } = useTileModelContext()
const caseCount = data?.getCasesForCollection(collection?.id).length ?? 0
const tileRef = useRef<HTMLDivElement | null>(null)
Expand Down
50 changes: 50 additions & 0 deletions v3/src/components/case-table/custom-row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { colord } from "colord"
import { observer } from "mobx-react-lite"
import React, { useEffect, useRef } from "react"
import { Row } from "react-data-grid"
import { TRenderRowProps } from "./case-table-types"
import { useCollectionContext } from "../../hooks/use-collection-context"
import { useDataSetContext } from "../../hooks/use-data-set-context"
import { IDataSet } from "../../models/data/data-set"
import { parseColorToHex } from "../../utilities/color-utils"

// have to balance background visibility vs. visibility/accessibility of rendered text
const kAlphaForRowBackground = 0.1

function getRowColor(data: IDataSet | undefined, collectionId: string, caseId: string) {
if (!data) return
// check first attribute of this collection or parent collections for a color attribute
const collectionIndex = data?.getCollectionIndex(collectionId) ?? -1
for (let i = collectionIndex; i >= 0; --i) {
const collection = i < data.collections.length ? data.collections[i] : undefined
const firstAttribute = collection?.attributes[0] ?? data.attributes[0]
if (firstAttribute?.userType === "color") {
const firstValue = data.getStrValue(caseId, firstAttribute.id)
const firstColor = firstValue && parseColorToHex(firstValue, { colorNames: true })
if (firstColor) {
// reduce alpha for text contrast/visibility
return colord(firstColor).alpha(kAlphaForRowBackground).toHex()
}
}
}
}

export const CustomRow = observer(function CustomRow(props: TRenderRowProps) {
const data = useDataSetContext()
const collectionId = useCollectionContext()
const rowRef = useRef<HTMLDivElement | null>(null)
const { row: { __id__: caseId } } = props
const rowColor = getRowColor(data, collectionId, caseId) ?? ""

useEffect(() => {
if (rowRef.current) {
rowRef.current.style.backgroundColor = rowColor
}
}, [rowColor])

return <Row ref={rowRef} {...props}></Row>
})

export function customRenderRow(key: React.Key, props: TRenderRowProps) {
return <CustomRow key={key} {...props} />
}
38 changes: 22 additions & 16 deletions v3/src/components/case-table/use-columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,33 @@ export const getNumFormatter = (formatStr: string) => {
return formatter
}

export function renderValue(str = "", num = NaN, attr?: IAttribute) {
export function renderValue(str = "", num = NaN, attr?: IAttribute, key?: number) {
const { type, userType } = attr || {}

// colors
const color = type === "color" || !userType ? parseColor(str, { colorNames: type === "color" }) : ""
if (color) {
return (
<div className="cell-color-swatch" >
<div className="cell-color-swatch-interior" style={{ background: color }} />
</div>
)
return {
value: color,
content: (
<div className="cell-color-swatch" key={key}>
<div className="cell-color-swatch-interior" style={{ background: color }} />
</div>
)
}
}

// numbers
if (isFinite(num)) {
const formatStr = attr?.format ?? kDefaultFormatStr
const formatter = getNumFormatter(formatStr)
if (formatter) return formatter(num)
if (formatter) str = formatter(num)
}

return str
return {
value: str,
content: <span className="cell-span" key={key}>{str}</span>
}
}

interface IUseColumnsProps {
Expand All @@ -63,20 +69,20 @@ export const useColumns = ({ data, indexColumn }: IUseColumnsProps) => {

// cell renderer
const RenderCell = useCallback(function({ column, row }: TRenderCellProps) {
const str = (data?.getStrValue(row.__id__, column.key) ?? "").trim()
const isParentCollapsed = row[symParent] ? caseMetadata?.isCollapsed(row[symParent]) : false
const output = isParentCollapsed
? ""
: renderValue(str, data?.getNumeric(row.__id__, column.key), data?.attrFromID(column.key))
const tooltip = typeof output === "string" ? output : str
const strValue = (data?.getStrValue(row.__id__, column.key) ?? "").trim()
const numValue = data?.getNumeric(row.__id__, column.key)
// if this is the first React render after performance rendering, add a
// random key to force React to render the contents for synchronization
const key = row[symDom]?.has(column.key) ? Math.random() : undefined
row[symDom]?.delete(column.key)
const isParentCollapsed = row[symParent] ? caseMetadata?.isCollapsed(row[symParent]) : false
const { value, content } = isParentCollapsed
? { value: "", content: null }
: renderValue(strValue, numValue, data?.attrFromID(column.key), key)
return (
<Tooltip label={tooltip} h="20px" fontSize="12px" color="white" data-testid="case-table-data-tip"
<Tooltip label={value} h="20px" fontSize="12px" color="white" data-testid="case-table-data-tip"
openDelay={1000} placement="bottom" bottom="10px" left="15px">
<span className="cell-span" key={key}>{output}</span>
{content}
</Tooltip>
)
}, [caseMetadata, data])
Expand Down

0 comments on commit 844bf14

Please sign in to comment.