From 64d127ca0237ece11ba30fcd3a6f3c34e32e123d Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Tue, 18 Apr 2023 17:12:27 -0500 Subject: [PATCH 1/2] Allow page_navbar to accept HTML dependencies --- shiny/ui/_navs.py | 44 +++++++++++++++++++++++++++++++------------- shiny/ui/_page.py | 26 ++++++++++++++------------ 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/shiny/ui/_navs.py b/shiny/ui/_navs.py index c115dd4b5..cb55763e6 100644 --- a/shiny/ui/_navs.py +++ b/shiny/ui/_navs.py @@ -16,9 +16,9 @@ import copy import re -from typing import Any, Optional, cast +from typing import Any, Optional, Sequence, cast -from htmltools import Tag, TagChild, TagList, div, tags +from htmltools import MetadataNode, Tag, TagChild, TagList, div, tags from .._docstring import add_example from .._namespaces import resolve_id @@ -335,7 +335,7 @@ def nav_menu( class NavSet: - args: tuple[NavSetArg] + args: tuple[NavSetArg | MetadataNode] ul_class: str id: Optional[str] selected: Optional[str] @@ -344,7 +344,7 @@ class NavSet: def __init__( self, - *args: NavSetArg, + *args: NavSetArg | MetadataNode, ul_class: str, id: Optional[str], selected: Optional[str], @@ -676,7 +676,7 @@ class NavSetPillList(NavSet): def __init__( self, - *args: NavSetArg, + *args: NavSetArg | MetadataNode, ul_class: str, id: Optional[str], selected: Optional[str], @@ -705,7 +705,7 @@ def layout(self, nav: TagChild, content: TagChild) -> Tag: def navset_pill_list( - *args: NavSetArg, + *args: NavSetArg | MetadataNode, id: Optional[str] = None, selected: Optional[str] = None, header: TagChild = None, @@ -776,7 +776,7 @@ class NavSetBar(NavSet): def __init__( self, - *args: NavSetArg, + *args: NavSetArg | MetadataNode, ul_class: str, title: TagChild, id: Optional[str], @@ -853,7 +853,7 @@ def layout(self, nav: TagChild, content: TagChild) -> TagList: def navset_bar( - *args: NavSetArg, + *args: NavSetArg | MetadataNode | Sequence[MetadataNode], title: TagChild, id: Optional[str] = None, selected: Optional[str] = None, @@ -922,8 +922,16 @@ def navset_bar( See :func:`~shiny.ui.nav`. """ + # If args contains any lists, flatten them into args. + new_args: Sequence[NavSetArg | MetadataNode] = [] + for arg in args: + if isinstance(arg, (list, tuple)): + new_args.extend(arg) + else: + new_args.append(cast(NavSetArg, arg)) + return NavSetBar( - *args, + *new_args, ul_class="nav navbar-nav", id=resolve_id(id) if id else None, selected=selected, @@ -942,7 +950,7 @@ def navset_bar( # Utilities for rendering navs # -----------------------------------------------------------------------------\ def render_navset( - *items: NavSetArg, + *items: NavSetArg | MetadataNode, ul_class: str, id: Optional[str], selected: Optional[str], @@ -950,16 +958,26 @@ def render_navset( ) -> tuple[Tag, Tag]: tabsetid = private_random_int(1000, 10000) + # Separate MetadataNodes from NavSetArgs. + metadata_args = [x for x in items if isinstance(x, MetadataNode)] + navset_args = [x for x in items if not isinstance(x, MetadataNode)] + # If the user hasn't provided a selected value, use the first one if selected is None: - for x in items: + for x in navset_args: selected = x.get_value() if selected is not None: break - ul_tag = tags.ul(bootstrap_deps(), class_=ul_class, id=id, data_tabsetid=tabsetid) + ul_tag = tags.ul( + bootstrap_deps(), + metadata_args, + class_=ul_class, + id=id, + data_tabsetid=tabsetid, + ) div_tag = div(class_="tab-content", data_tabsetid=tabsetid) - for i, x in enumerate(items): + for i, x in enumerate(navset_args): nav, contents = x.resolve( selected, {**context, "tabsetid": tabsetid, "index": i} ) diff --git a/shiny/ui/_page.py b/shiny/ui/_page.py index bce8f7215..2f16d32a7 100644 --- a/shiny/ui/_page.py +++ b/shiny/ui/_page.py @@ -7,12 +7,9 @@ "page_bootstrap", ) -from typing import Any, Optional +from typing import Optional, Sequence -# Tagifiable isn't used directly in this file, but it seems to necessary to import -# it somewhere for Sphinx to work cleanly. -from htmltools import Tagifiable # pyright: ignore[reportUnusedImport] # noqa: F401 -from htmltools import Tag, TagChild, TagList, div, tags +from htmltools import MetadataNode, Tag, TagAttrs, TagChild, TagList, div, tags from .._docstring import add_example from .._namespaces import resolve_id @@ -24,7 +21,7 @@ def page_navbar( - *args: NavSetArg, + *args: NavSetArg | MetadataNode | Sequence[MetadataNode], title: Optional[str | Tag | TagList] = None, id: Optional[str] = None, selected: Optional[str] = None, @@ -39,7 +36,7 @@ def page_navbar( lang: Optional[str] = None, ) -> Tag: """ - Create a navbar with a navs bar and a title. + Create a page with a navbar and a title. Parameters ---------- @@ -123,7 +120,10 @@ def page_navbar( @add_example() def page_fluid( - *args: Any, title: Optional[str] = None, lang: Optional[str] = None, **kwargs: str + *args: TagChild | TagAttrs, + title: Optional[str] = None, + lang: Optional[str] = None, + **kwargs: str, ) -> Tag: """ Create a fluid page. @@ -162,7 +162,10 @@ def page_fluid( @add_example() def page_fixed( - *args: Any, title: Optional[str] = None, lang: Optional[str] = None, **kwargs: str + *args: TagChild | TagAttrs, + title: Optional[str] = None, + lang: Optional[str] = None, + **kwargs: str, ) -> Tag: """ Create a fixed page. @@ -201,7 +204,7 @@ def page_fixed( # TODO: implement theme (just Bootswatch for now?) def page_bootstrap( - *args: Any, title: Optional[str] = None, lang: Optional[str] = None + *args: TagChild | TagAttrs, title: Optional[str] = None, lang: Optional[str] = None ) -> Tag: """ Create a Bootstrap UI page container. @@ -230,6 +233,5 @@ def page_bootstrap( :func:`~shiny.ui.page_navbar` """ - page = TagList(*bootstrap_deps(), *args) head = tags.title(title) if title else None - return tags.html(tags.head(head), tags.body(page), lang=lang) + return tags.html(tags.head(head), tags.body(*bootstrap_deps(), *args), lang=lang) From 3f8b82c83a176265d0844ab15f834330642ced83 Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Tue, 18 Apr 2023 20:42:14 -0500 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef76bfa3a..ec4f81daa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Other changes +* `page_navbar` now accepts shinyswatch themes. (#455) ## [0.3.0] - 2023-04-03