From 0c954f8ca4588247c735e69605505d63b90626a7 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Wed, 10 Jun 2026 19:24:55 +0200 Subject: [PATCH 01/52] Keep table header divider matching the border in Jupyter and docs --- src/easydiffraction/display/tablers/pandas.py | 21 +++++++++++-- .../display/tablers/test_pandas.py | 30 +++++++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/easydiffraction/display/tablers/pandas.py b/src/easydiffraction/display/tablers/pandas.py index 5327cb830..9a2f65295 100644 --- a/src/easydiffraction/display/tablers/pandas.py +++ b/src/easydiffraction/display/tablers/pandas.py @@ -120,17 +120,32 @@ def _build_html(self, alignments: object, df: object) -> str: border = f'1px solid {BORDER_COLOR}' header = f'{_CELL_STYLE}; border-bottom: {border}; font-weight: bold' index = f'{_CELL_STYLE}; color: {INDEX_COLOR}; font-weight: normal; text-align: right' + # ``display: table`` overrides MkDocs Material's + # ``table:not([class]) { display: inline-block }`` rule. Left as + # inline-block the table drops out of the collapsing-border model, + # so the header's translucent ``border-bottom`` stacks into a + # darker line than the outer border and stops one pixel short of + # the right edge. The wrapping ``overflow-x: auto`` div (added + # below) restores the horizontal scrolling that Material's + # ``inline-block`` would otherwise have provided for wide tables. table_style = ( - f'border: {border}; border-collapse: collapse; margin-top: 0.5em; margin-left: 0.5em' + f'border: {border}; border-collapse: collapse; display: table; ' + f'margin-top: 0.5em; margin-left: 0.5em' ) header_cells = ''.join( f'{html.escape(str(column))}' for column, align in zip(columns, aligns, strict=False) ) + # ``border-bottom: 0`` neutralises hosts (e.g. JupyterLab's + # ``.jp-RenderedHTMLCommon thead``) that paint an opaque header + # rule on the thead element. Left in place that rule wins the + # border collapse and recolours the divider; zeroing it keeps the + # header/body divider the same translucent grey as the outer + # border, sourced only from the header cells' ``border-bottom``. head = ( f'' - f'' + f'' f'{header_cells}' ) parts = [head] @@ -142,7 +157,7 @@ def _build_html(self, alignments: object, df: object) -> str: index_cell = f'' parts.append(f'{index_cell}{cells}') parts.append('
{html.escape(str(idx))}
') - return ''.join(parts) + return f'
{"".join(parts)}
' def build_renderable(self, alignments: object, df: object) -> object: """ diff --git a/tests/unit/easydiffraction/display/tablers/test_pandas.py b/tests/unit/easydiffraction/display/tablers/test_pandas.py index 321bb52ea..d5b13592b 100644 --- a/tests/unit/easydiffraction/display/tablers/test_pandas.py +++ b/tests/unit/easydiffraction/display/tablers/test_pandas.py @@ -23,10 +23,36 @@ class TestPandasTableBackend: def test_build_renderable_returns_table_html(self): html = _backend().build_renderable(['left', 'right'], _indexed({'A': [1.0], 'B': [2.0]})) assert isinstance(html, str) - assert html.startswith('' in html + assert '' in html + def test_table_is_wrapped_in_horizontal_scroll_container(self): + """A wrapping ``overflow-x: auto`` div keeps wide tables scrolling. + + Forcing ``display: table`` (below) drops Material's + ``inline-block``, which is what provided horizontal scrolling for + wide tables; the wrapper restores it. + """ + html = _backend().build_renderable(['left'], _indexed({'A': [1.0]})) + assert html.startswith('
' in html + def test_no_style_or_script_block_survives_untrusted_reopen(self): """All styling is inline -- no