diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f7b9559cd..92cb7abb5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed +- [#1968](https://github.com/plotly/dash/pull/1968) Fix bug [#1877](https://github.com/plotly/dash/issues/1877), code which uses `merge_duplicate_headers` and `style_header_conditional` to highlight columns, it incorrectly highlights header cells. + - [#2015](https://github.com/plotly/dash/pull/2015) Fix bug [#1854](https://github.com/plotly/dash/issues/1854) in which the combination of row_selectable="single or multi" and filter_action="native" caused the JS error. - [#1976](https://github.com/plotly/dash/pull/1976) Fix [#1962](https://github.com/plotly/dash/issues/1962) in which DatePickerSingle and DatePickerRange are extremely slow when provided a long list of disabled_days. diff --git a/components/dash-table/src/dash-table/components/HeaderFactory.tsx b/components/dash-table/src/dash-table/components/HeaderFactory.tsx index ea20bbc4bb..c0e107976c 100644 --- a/components/dash-table/src/dash-table/components/HeaderFactory.tsx +++ b/components/dash-table/src/dash-table/components/HeaderFactory.tsx @@ -123,16 +123,35 @@ export default class HeaderFactory { const ops = this.getHeaderOpCells(operations, opStyles, headerOpEdges); + const filteredStyles = this.filterMergedCells( + wrapperStyles, + labelsAndIndices + ); + const headers = this.getHeaderCells( wrappers, contents, - wrapperStyles, + filteredStyles, headerEdges ); return this.getCells(ops, headers); } + filterMergedCells = memoizeOne((cellsArray, labelsAndIndices) => { + const filteredCells = []; + for (let row = 0; row < cellsArray.length; row++) { + const rowCells = []; + for (let col = 0; col < cellsArray[row].length; col++) { + if (labelsAndIndices[row][1].includes(col)) { + rowCells.push(cellsArray[row][col]); + } + } + filteredCells.push(rowCells); + } + return filteredCells; + }); + getCells = memoizeOne( (opCells: JSX.Element[][], dataCells: JSX.Element[][]) => arrayMap2(opCells, dataCells, (o, c) => diff --git a/components/dash-table/tests/selenium/test_header.py b/components/dash-table/tests/selenium/test_header.py index ca6ccd1291..5d1dd7626c 100644 --- a/components/dash-table/tests/selenium/test_header.py +++ b/components/dash-table/tests/selenium/test_header.py @@ -142,3 +142,42 @@ def test_head005_no_warnings_emitted(test): wait.until(lambda: target.column(6).get().get_attribute("colspan") == "4", 3) assert test.get_logs() == [] + + +def test_head006_style_merged_columns(test): + app = get_app( + dict( + columns=[ + {"name": ("0"), "id": "x"}, + {"name": ("0"), "id": "y"}, + {"name": ("1", "1a"), "id": "a"}, + {"name": ("1", "1b"), "id": "b"}, + {"name": ("2", "2a"), "id": "c"}, + {"name": ("2", "2b"), "id": "d"}, + ], + merge_duplicate_headers=True, + style_header_conditional=[ + { + "if": {"column_id": f"{c}"}, + "backgroundColor": "green", + "fontWeight": "bold", + } + for c in ["a", "b"] + ], + ) + ) + + test.start_server( + app, + debug=True, + use_reloader=False, + use_debugger=True, + dev_tools_hot_reload=False, + ) + + target = test.table("table") + wait.until(lambda: target.column(0).get_text(0) == "0", 3) + assert "green" in target.column(2).get(0).get_attribute("style") + assert "green" in target.column(2).get(1).get_attribute("style") + assert "green" in target.column(3).get(1).get_attribute("style") + assert test.get_logs() == []