diff --git a/panel/dist/css/card.css b/panel/dist/css/card.css index 0bef45dc4e..c6d408a4bf 100644 --- a/panel/dist/css/card.css +++ b/panel/dist/css/card.css @@ -1,48 +1,56 @@ :host(.card) { - border: 1px solid rgba(0,0,0,.125); - border-radius: 0.25rem; + border: 1px solid rgba(0,0,0,.125); + border-radius: 0.25rem; } :host(.accordion) { - border: 1px solid rgba(0,0,0,.125); + border: 1px solid rgba(0,0,0,.125); } .card-header { - align-items: center; - background-color: rgba(0, 0, 0, 0.03); - border-radius: 0.25rem; - display: inline-flex; - justify-content: start; - width: 100%; + align-items: center; + background-color: rgba(0, 0, 0, 0.03); + border: 1px solid; + border-radius: 0.25rem; + display: inline-flex; + justify-content: start; + position: sticky; + left: 0; + width: 100%; } .accordion-header { - align-items: center; - background-color: rgba(0, 0, 0, 0.03); - border-radius: 0; - display: flex; - justify-content: start; - width: 100%; + align-items: center; + background-color: rgba(0, 0, 0, 0.03); + border: 1px solid; + border-radius: 0; + display: flex; + justify-content: start; + position: sticky; + left: 0; + width: 100%; } .card-button { - background-color: transparent; - margin-left: 0.5em; - margin-right: 0.5em; + background-color: transparent; + margin-left: 0.5em; + margin-right: 0.5em; } .card-header-row { - position: relative !important; + margin-bottom: auto; + margin-top: auto; + position: relative !important; } .card-title { - align-items: center; - font-size: 1.4em; - font-weight: bold; - overflow-wrap: break-word; + align-items: center; + font-size: 1.4em; + font-weight: bold; + overflow-wrap: break-word; } .card-header-row > .bk { - overflow-wrap: break-word; - text-align: center; + overflow-wrap: break-word; + text-align: center; } diff --git a/panel/layout/base.py b/panel/layout/base.py index 2e00aa0ed2..35b31548fa 100644 --- a/panel/layout/base.py +++ b/panel/layout/base.py @@ -72,11 +72,10 @@ def __repr__(self, depth: int = 0, max_depth: int = 10) -> str: # Callback API #---------------------------------------------------------------- - def _init_params(self) -> Dict[str, Any]: - return { - p: v for p, v in self.param.values().items() - if v is not None and p != 'objects' - } + def _process_param_change(self, params: Dict[str, Any]) -> Dict[str, Any]: + if ('styles' in params or 'sizing_mode' in params) and self.sizing_mode in ('stretch_width', 'stretch_both'): + params['styles'] = dict(params.get('styles', {}), **{'overflow-x': 'auto'}) + return super()._process_param_change(params) def _update_model( self, events: Dict[str, param.parameterized.Event], msg: Dict[str, Any], @@ -86,6 +85,10 @@ def _update_model( inverse = {v: k for k, v in self._property_mapping.items() if v is not None} preprocess = any(inverse.get(k, k) in self._preprocess_params for k in msg) + # ALERT: Find a better way to handle this + if 'styles' in msg and root is model and 'overflow-x' in msg['styles']: + del msg['styles']['overflow-x'] + obj_key = self._property_mapping['objects'] if obj_key in msg: old = events['objects'].old @@ -159,6 +162,16 @@ def _get_model( # Public API #---------------------------------------------------------------- + def get_root( + self, doc: Optional[Document] = None, comm: Optional[Comm] = None, + preprocess: bool = True + ) -> Model: + root = super().get_root(doc, comm, preprocess) + # ALERT: Find a better way to handle this + if hasattr(root, 'styles') and 'overflow-x' in root.styles: + del root.styles['overflow-x'] + return root + def select(self, selector=None): """ Iterates over the Viewable and any potential children in the diff --git a/panel/layout/card.py b/panel/layout/card.py index 233cd47c4a..2ead932a6d 100644 --- a/panel/layout/card.py +++ b/panel/layout/card.py @@ -108,7 +108,7 @@ def _update_header(self, *events): from ..pane import HTML, panel if self.header is None: params = { - 'object': '%s' % (self.title or "​"), + 'object': f'

{self.title}

' if self.title else "​", 'css_classes': self.title_css_classes, 'margin': (5, 0) } diff --git a/panel/tests/layout/test_accordion.py b/panel/tests/layout/test_accordion.py index 8385137eab..6455a22f6c 100644 --- a/panel/tests/layout/test_accordion.py +++ b/panel/tests/layout/test_accordion.py @@ -50,9 +50,9 @@ def test_accordion_constructor(document, comm): assert all(isinstance(c, Card) for c in model.children) card1, card2 = model.children - assert card1.children[0].children[0].text == 'Div1' + assert card1.children[0].children[0].text == '<h3>Div1</h3>' assert card1.children[1] is div1 - assert card2.children[0].children[0].text == 'Div2' + assert card2.children[0].children[0].text == '<h3>Div2</h3>' assert card2.children[1] is div2 @@ -69,9 +69,11 @@ def test_accordion_implicit_constructor(document, comm): assert all(isinstance(c, Card) for c in model.children) card1, card2 = model.children - assert card1.children[0].children[0].text == p1.name == 'Div1' + assert p1.name == 'Div1' + assert card1.children[0].children[0].text == '<h3>Div1</h3>' assert card1.children[1] is div1 - assert card2.children[0].children[0].text == p2.name == 'Div2' + assert p2.name == 'Div2' + assert card2.children[0].children[0].text == '<h3>Div2</h3>' assert card2.children[1] is div2 @@ -88,9 +90,9 @@ def test_accordion_constructor_with_named_objects(document, comm): assert all(isinstance(c, Card) for c in model.children) card1, card2 = model.children - assert card1.children[0].children[0].text == 'Tab1' + assert card1.children[0].children[0].text == '<h3>Tab1</h3>' assert card1.children[1] is div1 - assert card2.children[0].children[0].text == 'Tab2' + assert card2.children[0].children[0].text == '<h3>Tab2</h3>' assert card2.children[1] is div2 diff --git a/panel/tests/layout/test_card.py b/panel/tests/layout/test_card.py index 2f536c3ba7..5f329af7ca 100644 --- a/panel/tests/layout/test_card.py +++ b/panel/tests/layout/test_card.py @@ -46,14 +46,14 @@ def test_card_get_root_title(document, comm): assert isinstance(model, CardModel) assert model.children == [header, div1, div2] - assert header.children[0].text == "Test" + assert header.children[0].text == '<h3>Test</h3>' div3 = Div() layout.header = div3 assert header.children[0] is div3 layout.header = None - assert header.children[0].text == "Test" + assert header.children[0].text == '<h3>Test</h3>' def test_card_get_root_header(document, comm): diff --git a/panel/theme/css/bootstrap.css b/panel/theme/css/bootstrap.css index a7217184ba..d777c936c5 100644 --- a/panel/theme/css/bootstrap.css +++ b/panel/theme/css/bootstrap.css @@ -79,8 +79,8 @@ button.accordion-header { :host(.card-title) h1, :host(.card-title) h2, :host(.card-title) h3, :host(.card-title) h4, :host(.card-title) h5, :host(.card-title) h6 { - margin-block-end: 0; - margin-block-start: 0; + margin-block-end: 0.2em; + margin-block-start: 0.2em; } /* Tabs styling */ diff --git a/panel/theme/css/fast.css b/panel/theme/css/fast.css index 17e4aa1bfa..d33402152a 100644 --- a/panel/theme/css/fast.css +++ b/panel/theme/css/fast.css @@ -156,8 +156,8 @@ canvas, img { :host(.card-title) h1, :host(.card-title) h2, :host(.card-title) h3, :host(.card-title) h4, :host(.card-title) h5, :host(.card-title) h6 { - margin-block-end: 0; - margin-block-start: 0; + margin-block-end: 0.2em; + margin-block-start: 0.2em; } /* Tabs */ diff --git a/panel/theme/css/material.css b/panel/theme/css/material.css index ca0cf2fb40..9b4cafc5ae 100644 --- a/panel/theme/css/material.css +++ b/panel/theme/css/material.css @@ -47,8 +47,8 @@ button.mdc-button.mdc-card-button { :host(.card-title) h1, :host(.card-title) h2, :host(.card-title) h3, :host(.card-title) h4, :host(.card-title) h5, :host(.card-title) h6 { - margin-block-end: 0; - margin-block-start: 0; + margin-block-end: 0.2em; + margin-block-start: 0.2em; } /* Tabs styling */ diff --git a/panel/theme/css/native.css b/panel/theme/css/native.css index 7837fd1332..c09eec5204 100644 --- a/panel/theme/css/native.css +++ b/panel/theme/css/native.css @@ -26,3 +26,9 @@ color: var(--surface-text-color); background-color: var(--surface-color); } + +:host(.card-title) h1, :host(.card-title) h2, :host(.card-title) h3, +:host(.card-title) h4, :host(.card-title) h5, :host(.card-title) h6 { + margin-block-end: 0.2em; + margin-block-start: 0.2em; +}