Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use blib::bs_theme(5,"shiny") for py-shiny theme #624

Merged
merged 30 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ad9932c
Update script to have better messaging, create dataframe.js, and hand…
schloerke Jul 11, 2023
851d815
Tweak files to handle new file structures
schloerke Jul 11, 2023
fb32b08
Update to latest scripts
schloerke Jul 11, 2023
ceb8f3b
Default `ui.input_slider(ticks)` to `False`
schloerke Jul 11, 2023
3fba7b0
Update html deps script
schloerke Jul 11, 2023
da8126a
Have slider example where ticks are true
schloerke Jul 11, 2023
f525802
Add css dependencies
schloerke Jul 13, 2023
4a7b278
Update htmldeps
schloerke Jul 13, 2023
43d426b
tmp working commit
schloerke Jul 13, 2023
b6997a2
Merge branch 'main' into shiny-theme
schloerke Jul 13, 2023
d8f6260
Merge branch 'main' into shiny-theme
schloerke Jul 17, 2023
7b76efa
fix slider test
schloerke Jul 17, 2023
f7cc78c
Fix more slider tests
schloerke Jul 17, 2023
66eec78
Ignore duckdb data files
schloerke Jul 13, 2023
8c1535a
Add news entry
schloerke Jul 17, 2023
4131a37
Give more context in example app
schloerke Jul 17, 2023
167fe13
Use new separated htmldeps from bslib
schloerke Jul 17, 2023
c138a86
Less abstractions
schloerke Jul 17, 2023
e7ec0d3
Bump dev version to `0.4.0.9001`
schloerke Jul 17, 2023
9d4ea85
run deps script
schloerke Jul 17, 2023
26ac382
Include nav spacer dep
schloerke Jul 17, 2023
e635506
Get latest from bslib
schloerke Jul 18, 2023
55ed0f3
Merge branch 'main' into shiny-theme
schloerke Jul 18, 2023
72c762f
Default `inverse=True` for `x.ui.page_navbar()`
schloerke Jul 18, 2023
6a259a7
Be relaxed about break points
schloerke Jul 18, 2023
4a49681
Reset app before testing
schloerke Jul 18, 2023
e5d9189
Make changelog entry on a single line
schloerke Jul 18, 2023
5a9a97e
Adjust TODO comments
schloerke Jul 18, 2023
3908286
Remove shinyswatch from penguins app
schloerke Jul 18, 2023
03917e0
Only keep necessary font files
schloerke Jul 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### New features

* `shiny run` now takes a `--reload-dir <DIR>` argument that indicates a directory `--reload` should (recursively) monitor for changes, in addition to the app's parent directory. Can be used more than once. (#353)
* The default theme has been updated to use Bootstrap 5 with custom Shiny style enhancements. (#624)


### Bug fixes

Expand Down
10 changes: 7 additions & 3 deletions e2e/controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -1374,10 +1374,14 @@ def __init__(

def expect_tick_labels(
self,
value: ListPatternOrStr,
value: ListPatternOrStr | None,
*,
timeout: Timeout = None,
) -> None:
if value is None:
playwright_expect(self.loc_irs_ticks).to_have_count(0)
return

playwright_expect(self.loc_irs_ticks).to_have_text(value, timeout=timeout)

def expect_animate(self, exists: bool, *, timeout: Timeout = None) -> None:
Expand Down Expand Up @@ -1553,10 +1557,10 @@ def slow_move(x: float, y: float, delay: float = sleep_time) -> None:
)

def _grid_bb(self, *, timeout: Timeout = None) -> FloatRect:
grid = self.loc_container.locator(".irs-grid")
grid = self.loc_irs.locator("> .irs > .irs-line")
grid_bb = grid.bounding_box(timeout=timeout)
if grid_bb is None:
raise RuntimeError("Couldn't find bounding box for .irs-grid")
raise RuntimeError("Couldn't find bounding box for .irs-line")
return grid_bb

def _handle_center(
Expand Down
1 change: 1 addition & 0 deletions e2e/inputs/input_slider/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def slider_row(
pre="$",
sep=",",
animate=True,
ticks=True,
),
slider_row(
"Looping Animation",
Expand Down
12 changes: 6 additions & 6 deletions e2e/inputs/input_slider/test_input_slider_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_slider_regular(page: Page, local_app: ShinyAppProc) -> None:
s0.expect_min("0")
s0.expect_max("1000")
s0.expect_step("1")
s0.expect_ticks("true")
s0.expect_ticks("false")
s0.expect_sep(",")
s0.expect_pre(None)
s0.expect_post(None)
Expand All @@ -27,7 +27,7 @@ def test_slider_regular(page: Page, local_app: ShinyAppProc) -> None:
s0.expect_animate(exists=False)
OutputTextVerbatim(page, "txt0").expect_value("500")

new_val = "36"
new_val = "20"
s0.set(new_val)
s0.expect_value(new_val)
OutputTextVerbatim(page, "txt0").expect_value(new_val)
Expand All @@ -42,7 +42,7 @@ def test_slider_range(page: Page, local_app: ShinyAppProc) -> None:
s1.expect_min("1")
s1.expect_max("1000")
s1.expect_step("1")
s1.expect_ticks("true")
s1.expect_ticks("false")
s1.expect_sep(",")
s1.expect_pre(None)
s1.expect_post(None)
Expand All @@ -52,7 +52,7 @@ def test_slider_range(page: Page, local_app: ShinyAppProc) -> None:
s1.expect_animate(exists=False)
OutputTextVerbatim(page, "txt1").expect_value("(200, 500)")

new_val = ("605", "885")
new_val = ("605", "840")
s1.set(new_val, max_err_values=1000)
try:
s1.expect_value((MISSING, MISSING)) # type: ignore
Expand Down Expand Up @@ -97,7 +97,7 @@ def test_slider_loop(page: Page, local_app: ShinyAppProc) -> None:
s3.expect_min("1")
s3.expect_max("2000")
s3.expect_step("10")
s3.expect_ticks("true")
s3.expect_ticks("false")
s3.expect_sep(",")
s3.expect_pre(None)
s3.expect_post(None)
Expand Down Expand Up @@ -131,7 +131,7 @@ def test_slider_play(page: Page, local_app: ShinyAppProc) -> None:
s4.expect_min("0")
s4.expect_max("5")
s4.expect_step("1")
s4.expect_ticks("true")
s4.expect_ticks("false")
s4.expect_sep(",")
s4.expect_pre(None)
s4.expect_post(None)
Expand Down
4 changes: 2 additions & 2 deletions e2e/inputs/test_input_checkbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_input_checkbox_kitchen(page: Page, app: ShinyAppProc) -> None:
somevalue.expect_checked(False)
somevalue.expect_width(None)

# TODO-barret test output value
# TODO-karan test output value

somevalue.set(True)

Expand All @@ -28,4 +28,4 @@ def test_input_checkbox_kitchen(page: Page, app: ShinyAppProc) -> None:
somevalue.toggle()
somevalue.expect_checked(True)

# TODO-barret test output value
# TODO-karan test output value
2 changes: 1 addition & 1 deletion e2e/inputs/test_input_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ def test_input_file_kitchen(page: Page, app: ShinyAppProc) -> None:

file1.expect_complete()

# TODO-barret; Test UI output to not be empty
# TODO-karan; Test UI output to not be empty
6 changes: 2 additions & 4 deletions e2e/inputs/test_input_slider.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ def test_input_slider_kitchen(page: Page, slider_app: ShinyAppProc) -> None:

expect(obs.loc_label).to_have_text("Number of bins:")

obs.expect_tick_labels(
["10", "19", "28", "37", "46", "55", "64", "73", "82", "91", "100"]
)
obs.expect_tick_labels(None)
obs.expect_value("30")

obs.expect_animate(False)
Expand All @@ -27,7 +25,7 @@ def test_input_slider_kitchen(page: Page, slider_app: ShinyAppProc) -> None:
obs.expect_max("100")
# obs.expect_from()
obs.expect_step("1")
obs.expect_ticks("true")
obs.expect_ticks("false")
obs.expect_sep(",")
obs.expect_pre(None)
obs.expect_post(None)
Expand Down
2 changes: 2 additions & 0 deletions e2e/outputs/test_output_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ def test_output_text_kitchen(page: Page, app: ShinyAppProc) -> None:
verb = OutputTextVerbatim(page, "verb")
verb_no_placeholder = OutputTextVerbatim(page, "verb_no_placeholder")

txt.set("") # Reset text

text.expect_value("")
text.expect_inline(False)

Expand Down
3 changes: 3 additions & 0 deletions examples/duckdb/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
cities.csv
weather_forecasts.csv
weather.db
2 changes: 0 additions & 2 deletions examples/penguins/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

import pandas as pd
import seaborn as sns
import shinyswatch
from colors import bg_palette, palette

import shiny.experimental as x
Expand Down Expand Up @@ -44,7 +43,6 @@
ui.input_switch("by_species", "Show species", value=True),
ui.input_switch("show_margins", "Show marginal plots", value=True),
),
shinyswatch.theme.pulse(),
ui.output_ui("value_boxes"),
x.ui.output_plot("scatter", fill=True),
)
Expand Down
1 change: 0 additions & 1 deletion js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions js/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
{
"name": "shiny-dataframe-binding",
"version": "1.0.0",
"description": "",
"private": true,
"license": "MIT",
"main": "index.js",
"scripts": {
"build": "tsc -noEmit && eslint . && tsx build.ts",
"watch": "npx nodemon --exec 'npm run build' --ext '*' --ignore dist/ --ignore esbuild-metadata.json"
},
"author": "",
"license": "MIT",
"devDependencies": {
"@preact/compat": "^17.1.2",
"@tanstack/react-virtual": "^3.0.0-beta.54",
Expand Down
110 changes: 95 additions & 15 deletions scripts/htmlDependencies.R
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#!/usr/bin/env Rscript

message("Checking for node / npm")
if (Sys.which("npm")[["npm"]] == "") {
stop("Please install node / npm before running script")
}

versions <- list()

# Use local lib path for installing packages so we don't pollute the user's library
message("Installing GitHub packages: bslib, shiny, htmltools")
withr::local_temp_libpaths()
pak::pkg_install(c("rstudio/bslib@main", "rstudio/shiny@main", "rstudio/htmltools@main"))
ignore <- capture.output({
pak::pkg_install(c("rstudio/bslib@main", "rstudio/shiny@main", "rstudio/htmltools@main"))
})
# pak::pkg_install(c("cran::bslib", "cran::shiny", "cran::htmltools"))

versions["shiny_html_deps"] <- as.character(packageVersion("shiny"))
Expand Down Expand Up @@ -33,8 +41,8 @@ bslib_version <- pkg_source_version("bslib")
shiny_version <- pkg_source_version("shiny")
htmltools_version <- pkg_source_version("htmltools")

library(htmltools)
library(bslib)
library(htmltools, quietly = TRUE, warn.conflicts = FALSE)
library(bslib, quietly = TRUE, warn.conflicts = FALSE)

shiny_path <- fs::path(getwd(), "shiny")
www <- fs::path(shiny_path, "www")
Expand Down Expand Up @@ -77,24 +85,36 @@ copy_from_pkg <- function(pkg_name, pkg_dir, local_dir, version_dir = fs::path_d
}


# ------------------------------------------------------------------------------
message("Copy bslib components")
# Copy over bslib's components directory
copy_from_pkg("bslib", "components", x_www_bslib_components)
# Remove unused Sass files
copy_from_pkg("bslib", "components/dist", x_www_bslib_components)
# Remove non-minified files
fs::file_delete(
fs::dir_ls(x_www_bslib_components, type = "file", regexp = "\\.scss$")
fs::dir_ls(
x_www_bslib_components,
type = "file",
recurse = TRUE,
regexp = "\\.(min\\.|css)",
invert = TRUE
)
)
# Remove unused tag require
fs::file_delete(fs::path(x_www_bslib_components, "tag-require.js"))


# ------------------------------------------------------------------------------
message("Copy htmltools - fill")
# Copy over htmltools's fill directory
copy_from_pkg("htmltools", "fill", fs::path(x_www, "htmltools", "fill"))




# ------------------------------------------------------------------------------
message("Copy shiny www/shared")
# Copy over shiny's www/shared directory
copy_from_pkg("shiny", "www/shared", www_shared, www_shared)


# ------------------------------------------------------------------------------
message("Cleanup shiny www/shared")
# Don't need legacy (hopefully)
fs::dir_delete(fs::path(www_shared, "legacy"))
# Don't need dataTables (hopefully)
Expand All @@ -105,8 +125,40 @@ fs::file_delete(
fs::dir_ls(www_shared, type = "file", regexp = "jquery")
)


# ------------------------------------------------------------------------------
message("Save ionRangeSlider dep")

# Upgrade to Bootstrap 5 by default
deps <- bs_theme_dependencies(bs_theme(version = 5))
shiny_theme <- bslib::bs_theme(version = 5, preset = "shiny")
# Save iorange slider dep
# Get _dynamic_ ionrangeslider dep
ion_dep <- shiny:::ionRangeSliderDependencyCSS(shiny_theme)
if (inherits(ion_dep, "html_dependency")) {
ion_dep <- list(ion_dep)
}
# Save to temp folder
temp_ion_dep_dir <- fs::path_temp("shiny-ion-range-slider")
fs::dir_create(temp_ion_dep_dir)
withr::with_options(
list(htmltools.dir.version = FALSE),
ignore <- lapply(ion_dep, htmltools::copyDependencyToDir, temp_ion_dep_dir)
)
# Overwrite css file
ion_dep_dir <- fs::path(www_shared, "ionrangeslider")
fs::file_move(
fs::path(temp_ion_dep_dir, "ionRangeSlider", "ionRangeSlider.css"),
fs::path(ion_dep_dir, "css", "ion.rangeSlider.css")
)
# Cleanup
fs::dir_delete(temp_ion_dep_dir)

# TODO - make a UI object and save its dependencies. Loop through the different UI elements of bslib and save them accordingly. Similar to shiny::input_slider? instead of reaching into the `:::`


message("Save bootstrap bundle")
# Save htmldeps
deps <- bslib::bs_theme_dependencies(shiny_theme)
withr::with_options(
list(htmltools.dir.version = FALSE),
ignore <- lapply(deps, copyDependencyToDir, www_shared)
Expand All @@ -123,20 +175,37 @@ write_json(
)
)

message("Reduce font files")
font_txt <- unlist(strsplit(readLines("shiny/www/shared/bootstrap/font.css"), ";"))
woff_files <- list.files("shiny/www/shared/bootstrap/fonts", pattern = "\\.woff", full.names = TRUE)
ignored <- lapply(woff_files, function(woff_file) {
file_name <- basename(woff_file)
if (!any(grepl(file_name, font_txt, fixed = TRUE))) {
unlink(woff_file)
}
})


# ------------------------------------------------------------------------------
message("Cleanup bootstrap bundle")
# This additional bs3compat HTMLDependency() only holds
# the JS shim for tab panel logic, which we don't need
# since we're generating BS5+ tab markup. Note, however,
# we still do have bs3compat's CSS on the page, which
# comes in via the bootstrap HTMLDependency()
fs::dir_delete(fs::path(www_shared, "bs3compat"))


# ------------------------------------------------------------------------------
message("Save requirejs")
requirejs_version <- "2.3.6"
versions["requirejs"] <- requirejs_version
requirejs <- fs::path(www_shared, "requirejs")
fs::dir_create(requirejs)
download.file(
paste0("https://cdnjs.cloudflare.com/ajax/libs/require.js/", requirejs_version, "/require.min.js"),
fs::path(requirejs, "require.min.js")
fs::path(requirejs, "require.min.js"),
quiet = TRUE
)

shims <- fs::path(getwd(), "scripts", "define-shims.js")
Expand All @@ -149,6 +218,8 @@ cat(
)


# ------------------------------------------------------------------------------
message("Save _versions.py")
version_vars <- paste0(names(versions), " = ", "\"", versions, "\"\n", collapse = "")
version_all <- paste0(
collapse = "",
Expand All @@ -165,9 +236,8 @@ cat(
)



# ------------------------------------------------------------------------------
# Copy x assets to shiny main_x assets
message("Copy www/shared/_x assets")

if (fs::dir_exists(main_x_www)) fs::dir_delete(main_x_www)

Expand All @@ -183,7 +253,17 @@ fs::dir_copy(x_www_htmltools_fill, main_x_htmltools_fill)
fs::file_delete(
fs::dir_ls(
fs::path(main_x_bslib_components, "components"),
regexp="(_version|sidebar)",
regexp="(_version|sidebar|nav_spacer)",
invert = TRUE
)
)


# ------------------------------------------------------------------------------
message("Create dataframe.js via npm")

js_path <- fs::path_abs(fs::path(shiny_path, "..", "js"))
ignore <- system(
paste0("cd ", js_path, " && npm install && npm run build"),
intern = TRUE
)
2 changes: 1 addition & 1 deletion shiny/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""A package for building reactive web applications."""

__version__ = "0.4.0.9000"
__version__ = "0.4.0.9001"

from ._shinyenv import is_pyodide as _is_pyodide

Expand Down
Loading