Skip to content

Commit 36a95fd

Browse files
committed
feat: Mark shiny theme stylesheets with data-shiny-theme
And store theme name if `ui.Theme()` is used
1 parent 81f642c commit 36a95fd

File tree

2 files changed

+36
-8
lines changed

2 files changed

+36
-8
lines changed

shiny/ui/_html_deps_external.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,50 @@
2626
ThemeProvider = Union[Tagifiable, HTMLDependency, List[HTMLDependency]]
2727

2828

29+
def mark_shiny_theme_stylesheets(dep: HTMLDependency, name: str = "") -> HTMLDependency:
30+
if not isinstance(dep, HTMLDependency):
31+
raise ValueError(
32+
"Expected an HTMLDependency, but received a value with type "
33+
f"{type(dep)}."
34+
)
35+
36+
if len(dep.stylesheet) > 0:
37+
for sheet in dep.stylesheet:
38+
sheet["data-shiny-theme"] = name # type: ignore
39+
40+
return dep
41+
42+
2943
def shiny_page_theme_deps(theme: str | Path | Theme | ThemeProvider | None) -> TagList:
3044
deps_bootstrap = bootstrap_deps(include_css=theme is None)
3145

3246
if theme is None:
3347
deps_theme = None
3448
elif isinstance(theme, Theme):
35-
deps_theme = theme._html_dependency()
49+
deps_theme = mark_shiny_theme_stylesheets(
50+
theme._html_dependency(),
51+
name=theme.name or theme._preset,
52+
)
3653
elif isinstance(theme, str) and theme.startswith(("http", "//")):
37-
deps_theme = head_content(link(rel="stylesheet", href=theme, type="text/css"))
54+
theme_link = link(
55+
rel="stylesheet", href=theme, type="text/css", data_shiny_theme=""
56+
)
57+
deps_theme = head_content(theme_link)
3858
elif isinstance(theme, (str, Path)):
3959
check_path(theme)
40-
deps_theme = head_content(include_css(theme))
41-
elif isinstance(theme, Tagifiable) or isinstance(theme, HTMLDependency):
42-
deps_theme = theme
60+
theme_link = include_css(theme)
61+
theme_link.attrs["data-shiny-theme"] = ""
62+
deps_theme = head_content(theme_link)
63+
elif isinstance(theme, HTMLDependency):
64+
deps_theme = mark_shiny_theme_stylesheets(theme)
4365
elif isinstance(theme, list) and all(
4466
[isinstance(dep, HTMLDependency) for dep in theme]
4567
):
46-
deps_theme = theme
68+
deps_theme = [mark_shiny_theme_stylesheets(t) for t in theme]
69+
elif isinstance(theme, Tagifiable):
70+
deps_theme = TagList(theme.tagify())
71+
for dep in deps_theme.get_dependencies():
72+
mark_shiny_theme_stylesheets(dep)
4773
else:
4874
raise ValueError(
4975
"Invalid `theme`. "

tests/pytest/test_theme.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def _page_sidebar(*args, **kwargs) -> Tag: # type: ignore
166166
)
167167
@pytest.mark.parametrize(
168168
"theme",
169-
[None, Theme("shiny"), Theme("bootstrap"), Theme("sketchy")],
169+
[None, Theme("shiny"), Theme("bootstrap", name="default"), Theme("sketchy")],
170170
)
171171
def test_page_theme_wins(page_fn: Callable[..., Tag], theme: Theme | None):
172172
ui = page_fn(
@@ -189,7 +189,9 @@ def test_page_theme_wins(page_fn: Callable[..., Tag], theme: Theme | None):
189189
]
190190

191191
for dep in deps:
192-
if dep.name in no_css:
192+
if theme is not None and dep.name.startswith("shiny-theme"):
193+
assert dep.stylesheet[0]["data-shiny-theme"] == theme.name or theme._preset # type: ignore
194+
elif dep.name in no_css:
193195
# These components should have CSS suppressed by the page-level
194196
# dependency from shiny_page_theme_deps(). If this test fails, it means
195197
# that our assumptions about how htmltools' dependency resolution works

0 commit comments

Comments
 (0)