From 00cdb96b5bb35c025dfd354d30410608686bcb40 Mon Sep 17 00:00:00 2001 From: Antony Milne <49395058+antonymilne@users.noreply.github.com> Date: Tue, 21 Jan 2025 06:55:26 +0000 Subject: [PATCH] [Feat] Update to use dmc 0.15.1 Part 2 (#960) --- .stylelintignore | 1 + ...0120_121030_49395058+antonymilne_dmc_15.md | 47 ++ vizro-core/examples/dev/app.py | 2 +- vizro-core/src/vizro/_vizro.py | 8 - vizro-core/src/vizro/models/_dashboard.py | 10 +- .../src/vizro/static/css/mantine_dates.css | 472 ++++++++++++++++++ .../tests/unit/vizro/models/test_dashboard.py | 34 +- 7 files changed, 546 insertions(+), 28 deletions(-) create mode 100644 vizro-core/changelog.d/20250120_121030_49395058+antonymilne_dmc_15.md create mode 100644 vizro-core/src/vizro/static/css/mantine_dates.css diff --git a/.stylelintignore b/.stylelintignore index 554157e1f..dcd27d71d 100644 --- a/.stylelintignore +++ b/.stylelintignore @@ -1,2 +1,3 @@ **/static/css/vizro-bootstrap.min.css **/static/css/vizro-bootstrap.min.css.map +**/static/css/mantine_dates.css diff --git a/vizro-core/changelog.d/20250120_121030_49395058+antonymilne_dmc_15.md b/vizro-core/changelog.d/20250120_121030_49395058+antonymilne_dmc_15.md new file mode 100644 index 000000000..043e033fa --- /dev/null +++ b/vizro-core/changelog.d/20250120_121030_49395058+antonymilne_dmc_15.md @@ -0,0 +1,47 @@ + + + + + + +### Changed + +- Bumped library used for `vm.DatePicker` to `dash_mantine_components~=0.15.1`. ([#924](https://github.com/mckinsey/vizro/pull/924)) + + + + diff --git a/vizro-core/examples/dev/app.py b/vizro-core/examples/dev/app.py index 74ade57b7..926b289c1 100644 --- a/vizro-core/examples/dev/app.py +++ b/vizro-core/examples/dev/app.py @@ -827,6 +827,6 @@ def multiple_cards(data_frame: pd.DataFrame, n_rows: Optional[int] = 1) -> html. target="_blank", className="anchor-container", ) - app.dash.layout.children = [app.dash.layout.children, banner] + app.dash.layout.children.append(banner) server = app.dash.server app.run() diff --git a/vizro-core/src/vizro/_vizro.py b/vizro-core/src/vizro/_vizro.py index f2fa41a27..05310cbf5 100644 --- a/vizro-core/src/vizro/_vizro.py +++ b/vizro-core/src/vizro/_vizro.py @@ -8,7 +8,6 @@ from typing import TYPE_CHECKING, TypedDict, cast import dash -import dash_mantine_components as dmc import plotly.io as pio from dash.development.base_component import ComponentRegistry from flask_caching import SimpleCache @@ -53,13 +52,6 @@ def __init__(self, **kwargs): use_pages=True, ) - # Ensure external_stylesheets is a list and append the additional stylesheet - external_stylesheets = self.dash.config.external_stylesheets - self.dash.config.external_stylesheets = ( - external_stylesheets if isinstance(external_stylesheets, list) else [external_stylesheets] - ) - self.dash.config.external_stylesheets.append(dmc.styles.DATES) - # When Vizro is used as a framework, we want to include the library and framework resources. # Dash serves resources in the order 1. external_stylesheets/scripts; 2. library resources from the # ComponentRegistry; 3. resources added by append_css/scripts. diff --git a/vizro-core/src/vizro/models/_dashboard.py b/vizro-core/src/vizro/models/_dashboard.py index b0cebfd48..2720db4fc 100644 --- a/vizro-core/src/vizro/models/_dashboard.py +++ b/vizro-core/src/vizro/models/_dashboard.py @@ -172,10 +172,14 @@ def build(self): dash.page_container, ], ) + + # children=[layout] as a list rather than children=layout, so that app.dash.layout.children.append works to + # easily add things to the Dash layout. In future we might have a neater function for patching components into + # the Dash layout in which case this could change. return dmc.MantineProvider( - layout, - # Applies to all Mantine components - theme={"fontFamily": "Inter, sans-serif, Arial, serif", "primaryColor": "gray", "defaultRadius": 0}, + children=[layout], + # Use the `theme` to style all Mantine components with a Vizro theme. For more info see https://www.dash-mantine-components.com/components/mantineprovider + theme={"primaryColor": "gray"}, ) def _validate_logos(self): diff --git a/vizro-core/src/vizro/static/css/mantine_dates.css b/vizro-core/src/vizro/static/css/mantine_dates.css new file mode 100644 index 000000000..2eb0c61f5 --- /dev/null +++ b/vizro-core/src/vizro/static/css/mantine_dates.css @@ -0,0 +1,472 @@ +/* Downloaded version of https://unpkg.com/@mantine/dates@7.14.3/styles.css. + This is the stylesheet that corresponds to dmc.styles.DATES given at + https://github.com/snehilvj/dash-mantine-components/blob/master/dash_mantine_components/styles.py. + This ensures vizro can be used offline. */ +.m_468e7eda { + padding-top: 0; + padding-bottom: 0; + appearance: none; +} + +.m_468e7eda::-webkit-calendar-picker-indicator { + display: none; +} + +.m_468e7eda::-webkit-clear-button { + display: none; +} + +.m_468e7eda::-webkit-datetime-edit-hour-field, +.m_468e7eda::-webkit-datetime-edit-minute-field, +.m_468e7eda::-webkit-datetime-edit-second-field, +.m_468e7eda::-webkit-datetime-edit-ampm-field { + padding-top: 0; + max-height: calc(1.875rem * var(--mantine-scale)); + display: inline; +} + +.m_468e7eda::-webkit-datetime-edit-hour-field:focus, +.m_468e7eda::-webkit-datetime-edit-minute-field:focus, +.m_468e7eda::-webkit-datetime-edit-second-field:focus, +.m_468e7eda::-webkit-datetime-edit-ampm-field:focus { + background-color: var(--mantine-primary-color-filled); + color: var(--mantine-color-white); +} + +.m_396ce5cb { + --day-size-xs: calc(1.875rem * var(--mantine-scale)); + --day-size-sm: calc(2.25rem * var(--mantine-scale)); + --day-size-md: calc(2.625rem * var(--mantine-scale)); + --day-size-lg: calc(3rem * var(--mantine-scale)); + --day-size-xl: calc(3.375rem * var(--mantine-scale)); + --day-size: var(--day-size-sm); + + width: var(--day-size, var(--day-size-sm)); + height: var(--day-size, var(--day-size-sm)); + font-size: calc(var(--day-size) / 2.8); + display: inline-flex; + justify-content: center; + align-items: center; + user-select: none; + cursor: pointer; + background-color: transparent; + border-radius: var(--mantine-radius-default); + color: var(--mantine-color-text); + opacity: 1; +} + +@media (hover: hover) { + [data-mantine-color-scheme="light"] + .m_396ce5cb:hover:where( + :not([data-static], [data-disabled], [data-selected], [data-in-range]) + ) { + background-color: var(--mantine-color-gray-0); + } + + [data-mantine-color-scheme="dark"] + .m_396ce5cb:hover:where( + :not([data-static], [data-disabled], [data-selected], [data-in-range]) + ) { + background-color: var(--mantine-color-dark-5); + } +} + +@media (hover: none) { + [data-mantine-color-scheme="light"] + .m_396ce5cb:active:where( + :not([data-static], [data-disabled], [data-selected], [data-in-range]) + ) { + background-color: var(--mantine-color-gray-0); + } + + [data-mantine-color-scheme="dark"] + .m_396ce5cb:active:where( + :not([data-static], [data-disabled], [data-selected], [data-in-range]) + ) { + background-color: var(--mantine-color-dark-5); + } +} + +.m_396ce5cb:where([data-static]) { + user-select: auto; + cursor: default; +} + +.m_396ce5cb:where([data-weekend]) { + color: var(--mantine-color-red-6); +} + +.m_396ce5cb:where([data-outside]) { + color: var(--mantine-color-dimmed); + opacity: 0.5; +} + +.m_396ce5cb:where(:disabled, [data-disabled]) { + color: var(--mantine-color-dimmed); + cursor: not-allowed; + opacity: 0.5; +} + +.m_396ce5cb:where([data-hidden]) { + display: none; +} + +:where([data-mantine-color-scheme="light"]) + .m_396ce5cb:where( + [data-today][data-highlight-today]:not([data-selected], [data-in-range]) + ) { + border: 1px solid var(--mantine-color-gray-4); +} + +:where([data-mantine-color-scheme="dark"]) + .m_396ce5cb:where( + [data-today][data-highlight-today]:not([data-selected], [data-in-range]) + ) { + border: 1px solid var(--mantine-color-dark-4); +} + +.m_396ce5cb:where([data-in-range]) { + background-color: var(--mantine-primary-color-light-hover); + border-radius: 0; +} + +@media (hover: hover) { + .m_396ce5cb:where([data-in-range]):hover:where( + :not([data-disabled], [data-static]) + ) { + background-color: var(--mantine-primary-color-light); + } +} + +@media (hover: none) { + .m_396ce5cb:where([data-in-range]):active:where( + :not([data-disabled], [data-static]) + ) { + background-color: var(--mantine-primary-color-light); + } +} + +.m_396ce5cb:where([data-first-in-range]) { + border-radius: 0; + border-start-start-radius: var(--mantine-radius-default); + border-end-start-radius: var(--mantine-radius-default); +} + +.m_396ce5cb:where([data-last-in-range]) { + border-radius: 0; + border-end-end-radius: var(--mantine-radius-default); + border-start-end-radius: var(--mantine-radius-default); +} + +.m_396ce5cb:where([data-last-in-range][data-first-in-range]) { + border-radius: var(--mantine-radius-default); +} + +.m_396ce5cb:where([data-selected]) { + background-color: var(--mantine-primary-color-filled); + color: var(--mantine-primary-color-contrast); +} + +@media (hover: hover) { + .m_396ce5cb:where([data-selected]):hover:where( + :not([data-disabled], [data-static]) + ) { + background-color: var(--mantine-primary-color-filled-hover); + } +} + +@media (hover: none) { + .m_396ce5cb:where([data-selected]):active:where( + :not([data-disabled], [data-static]) + ) { + background-color: var(--mantine-primary-color-filled-hover); + } +} + +.m_18a3eca { + color: var(--mantine-color-dimmed); + font-weight: normal; + font-size: var(--wr-fz, var(--mantine-font-size-sm)); + text-transform: capitalize; + padding-bottom: calc(var(--wr-spacing, var(--mantine-spacing-sm)) / 2); +} + +.m_cc9820d3 { + border-collapse: collapse; + table-layout: fixed; +} + +.m_8f457cd5 { + padding: 0; +} + +.m_8f457cd5:where([data-with-spacing]) { + padding: calc(0.03125rem * var(--mantine-scale)); +} + +.m_6cff9dea { + --wn-size-xs: calc(1.875rem * var(--mantine-scale)); + --wn-size-sm: calc(2.25rem * var(--mantine-scale)); + --wn-size-md: calc(2.625rem * var(--mantine-scale)); + --wn-size-lg: calc(3rem * var(--mantine-scale)); + --wn-size-xl: calc(3.375rem * var(--mantine-scale)); + + color: var(--mantine-color-dimmed); + font-weight: normal; + font-size: calc(var(--wn-size, var(--wn-size-sm)) / 2.8); + text-align: center; + width: var(--wn-size, var(--wn-size-sm)); +} + +.m_dc6a3c71 { + --dpc-size-xs: calc(1.875rem * var(--mantine-scale)); + --dpc-size-sm: calc(2.25rem * var(--mantine-scale)); + --dpc-size-md: calc(2.625rem * var(--mantine-scale)); + --dpc-size-lg: calc(3rem * var(--mantine-scale)); + --dpc-size-xl: calc(3.375rem * var(--mantine-scale)); + --dpc-size: var(--dpc-size-sm); + + font-size: var(--dpc-fz, var(--mantine-font-size-sm)); + height: var(--dpc-size); + width: calc( + (var(--dpc-size) * 7) / 3 + calc(0.09375rem * var(--mantine-scale)) + ); + display: flex; + justify-content: center; + align-items: center; + user-select: none; + cursor: pointer; + background-color: transparent; + color: var(--mantine-color-text); + opacity: 1; + border-radius: var(--mantine-radius-default); +} + +@media (hover: hover) { + :where([data-mantine-color-scheme="light"]) + .m_dc6a3c71:hover:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-gray-0); + } + + :where([data-mantine-color-scheme="dark"]) + .m_dc6a3c71:hover:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-dark-5); + } +} + +@media (hover: none) { + :where([data-mantine-color-scheme="light"]) + .m_dc6a3c71:active:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-gray-0); + } + + :where([data-mantine-color-scheme="dark"]) + .m_dc6a3c71:active:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-dark-5); + } +} + +.m_dc6a3c71:where(:disabled, [data-disabled]) { + color: var(--mantine-color-dimmed); + cursor: not-allowed; + opacity: 0.5; +} + +.m_dc6a3c71:where([data-selected]) { + background-color: var(--mantine-primary-color-filled); + color: var(--mantine-primary-color-contrast, var(--mantine-color-white)); +} + +@media (hover: hover) { + .m_dc6a3c71:where([data-selected]):hover { + background-color: var(--mantine-primary-color-filled-hover); + } +} + +@media (hover: none) { + .m_dc6a3c71:where([data-selected]):active { + background-color: var(--mantine-primary-color-filled-hover); + } +} + +.m_dc6a3c71:where([data-in-range]) { + background-color: var(--mantine-primary-color-light-hover); + border-radius: 0; +} + +@media (hover: hover) { + .m_dc6a3c71:where([data-in-range]):hover { + background-color: var(--mantine-primary-color-light); + } +} + +@media (hover: none) { + .m_dc6a3c71:where([data-in-range]):active { + background-color: var(--mantine-primary-color-light); + } +} + +.m_dc6a3c71:where([data-first-in-range]) { + border-radius: 0; + border-start-start-radius: var(--mantine-radius-default); + border-end-start-radius: var(--mantine-radius-default); +} + +.m_dc6a3c71:where([data-last-in-range]) { + border-radius: 0; + border-end-end-radius: var(--mantine-radius-default); + border-start-end-radius: var(--mantine-radius-default); +} + +.m_dc6a3c71:where([data-first-in-range][data-last-in-range]) { + border-radius: var(--mantine-radius-default); +} + +.m_9206547b { + border-collapse: collapse; + border-width: 0; +} + +.m_c5a19c7d { + padding: 0; +} + +.m_c5a19c7d:where([data-with-spacing]) { + padding: calc(0.03125rem * var(--mantine-scale)); +} + +.m_2a6c32d { + border-collapse: collapse; + border-width: 0; + cursor: pointer; +} + +.m_fe27622f { + padding: 0; +} + +.m_fe27622f:where([data-with-spacing]) { + padding: calc(0.03125rem * var(--mantine-scale)); +} + +.m_730a79ed { + --dch-control-size-xs: calc(1.875rem * var(--mantine-scale)); + --dch-control-size-sm: calc(2.25rem * var(--mantine-scale)); + --dch-control-size-md: calc(2.625rem * var(--mantine-scale)); + --dch-control-size-lg: calc(3rem * var(--mantine-scale)); + --dch-control-size-xl: calc(3.375rem * var(--mantine-scale)); + --dch-control-size: var(--dch-control-size-sm); + + display: flex; + max-width: calc( + var(--dch-control-size) * 8 + calc(0.4375rem * var(--mantine-scale)) + ); + margin-bottom: var(--mantine-spacing-xs); +} + +.m_f6645d97, +.m_2351eeb0 { + height: var(--dch-control-size); + border-radius: var(--mantine-radius-default); + display: flex; + justify-content: center; + align-items: center; + user-select: none; + opacity: 1; + cursor: pointer; +} + +@media (hover: hover) { + [data-mantine-color-scheme="light"] + .m_f6645d97:hover:where(:not([data-disabled], :disabled)), + [data-mantine-color-scheme="light"] + .m_2351eeb0:hover:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-gray-0); + } + + [data-mantine-color-scheme="dark"] + .m_f6645d97:hover:where(:not([data-disabled], :disabled)), + [data-mantine-color-scheme="dark"] + .m_2351eeb0:hover:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-dark-5); + } +} + +@media (hover: none) { + [data-mantine-color-scheme="light"] + .m_f6645d97:active:where(:not([data-disabled], :disabled)), + [data-mantine-color-scheme="light"] + .m_2351eeb0:active:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-gray-0); + } + + [data-mantine-color-scheme="dark"] + .m_f6645d97:active:where(:not([data-disabled], :disabled)), + [data-mantine-color-scheme="dark"] + .m_2351eeb0:active:where(:not([data-disabled], :disabled)) { + background-color: var(--mantine-color-dark-5); + } +} + +.m_f6645d97:where(:disabled, [data-disabled]), +.m_2351eeb0:where(:disabled, [data-disabled]) { + opacity: 0.2; + cursor: not-allowed; +} + +.m_2351eeb0 { + width: var(--dch-control-size); +} + +.m_f6645d97 { + flex: 1; + font-size: var(--dch-fz, var(--mantine-font-size-sm)); + font-weight: 500; + text-transform: capitalize; +} + +.m_367dc749 { + width: 60%; + height: 60%; +} + +.m_367dc749:where([data-direction="next"]) { + transform: rotate(270deg); +} + +:where([dir="rtl"]) .m_367dc749:where([data-direction="next"]) { + transform: rotate(90deg); +} + +.m_367dc749:where([data-direction="previous"]) { + transform: rotate(90deg); +} + +:where([dir="rtl"]) .m_367dc749:where([data-direction="previous"]) { + transform: rotate(270deg); +} + +.m_30b26e33 { + display: flex; + gap: var(--mantine-spacing-md); +} + +.m_6fa5e2aa { + cursor: pointer; + line-height: unset; +} + +.m_6fa5e2aa:where([data-read-only]) { + cursor: default; +} + +.m_208d2562 { + display: flex; + align-items: stretch; + margin-top: var(--mantine-spacing-md); +} + +.m_62ee059 { + flex: 1; + margin-inline-end: var(--mantine-spacing-md); +} diff --git a/vizro-core/tests/unit/vizro/models/test_dashboard.py b/vizro-core/tests/unit/vizro/models/test_dashboard.py index c40e10cf9..c14a09307 100644 --- a/vizro-core/tests/unit/vizro/models/test_dashboard.py +++ b/vizro-core/tests/unit/vizro/models/test_dashboard.py @@ -277,22 +277,24 @@ def test_dashboard_build(self, vizro_app, page_1, page_2): ) expected_dashboard_container = dmc.MantineProvider( - html.Div( - id="dashboard-container", - children=[ - html.Div(id="vizro_version", children=vizro.__version__, hidden=True), - dcc.Store( - id="vizro_themes", - data={ - "vizro_dark": dashboard_vizro_dark, - "vizro_light": dashboard_vizro_light, - }, - ), - ActionLoop._create_app_callbacks(), - dash.page_container, - ], - ), - theme={"fontFamily": "Inter, sans-serif, Arial, serif", "primaryColor": "gray", "defaultRadius": 0}, + children=[ + html.Div( + id="dashboard-container", + children=[ + html.Div(id="vizro_version", children=vizro.__version__, hidden=True), + dcc.Store( + id="vizro_themes", + data={ + "vizro_dark": dashboard_vizro_dark, + "vizro_light": dashboard_vizro_light, + }, + ), + ActionLoop._create_app_callbacks(), + dash.page_container, + ], + ) + ], + theme={"primaryColor": "gray"}, ) assert_component_equal(dashboard.build(), expected_dashboard_container)