diff --git a/.github/py-shiny/pytest-browsers/action.yaml b/.github/py-shiny/pytest-browsers/action.yaml new file mode 100644 index 000000000..b9f470277 --- /dev/null +++ b/.github/py-shiny/pytest-browsers/action.yaml @@ -0,0 +1,30 @@ +name: 'Custom merge queue browsers' +description: 'Trim down pytest browsers for any github event other than merge_group.' +inputs: + all-browsers: + description: 'Force all pytest browsers to used when testing' + required: false + default: 'false' +outputs: + browsers: + description: 'pytest browsers to use' + value: ${{ steps.browsers.outputs.browsers }} +runs: + using: "composite" + steps: + - name: Determine browsers to use + shell: bash + id: browsers + run: | + if [ "${{ inputs.all-browsers }}" == "true" ]; then + echo "Using all browsers!" + exit 0 + fi + + if [ "${{ github.event_name }}" == "pull_request" ]; then + echo "Using chrome browser only!" + echo 'browsers=PYTEST_BROWSERS="--browser chromium"' >> "$GITHUB_OUTPUT" + fi + + echo "No custom pytest browsers!" + exit 0 diff --git a/.github/py-shiny/setup/action.yaml b/.github/py-shiny/setup/action.yaml index 1fd5b6253..e96f99619 100644 --- a/.github/py-shiny/setup/action.yaml +++ b/.github/py-shiny/setup/action.yaml @@ -4,7 +4,7 @@ inputs: python-version: description: 'Python version to use' required: false - default: "3.11" + default: "3.12" runs: using: "composite" steps: @@ -25,7 +25,6 @@ runs: shell: bash run: | pip install https://github.com/rstudio/py-htmltools/tarball/main - pip install https://github.com/posit-dev/py-shinylive/tarball/main make install-deps - name: Install diff --git a/.github/workflows/build-docs.yaml b/.github/workflows/build-docs.yaml index 3da9dda42..4a4ee9b9e 100644 --- a/.github/workflows/build-docs.yaml +++ b/.github/workflows/build-docs.yaml @@ -1,40 +1,43 @@ -name: Build API docs +name: Build API docs and Shinylive for GitHub Pages on: workflow_dispatch: push: branches: ["main"] pull_request: + merge_group: jobs: - build: + build-docs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11"] + python-version: ["3.12"] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip run: python -m pip install --upgrade pip + # ===================================================== + # API docs + # ===================================================== - name: Install Quarto uses: quarto-dev/quarto-actions/setup@v2 with: - version: 1.3.340 + version: 1.4.549 - name: Install dependencies run: | cd docs make ../venv - . ../venv/bin/activate && pip install https://github.com/posit-dev/py-htmltools/tarball/main https://github.com/posit-dev/py-shinylive/tarball/main make deps - name: Run quartodoc @@ -42,26 +45,68 @@ jobs: cd docs make quartodoc + # ===================================================== + # Shinylive + # ===================================================== + - name: Check out shinylive + if: github.ref == 'refs/heads/main' + uses: actions/checkout@v4 + with: + repository: rstudio/shinylive + ref: main + path: shinylive-repo + + - name: Update shinylive's copy of shiny and htmltools + if: github.ref == 'refs/heads/main' + run: | + cd shinylive-repo + make submodules + make submodules-pull-shiny + make submodules-pull-htmltools + + - name: Build shinylive + if: github.ref == 'refs/heads/main' + run: | + cd shinylive-repo + make all + + # TODO-future; Install updated shinylive assets via updated py-shinylive pkg + + # ===================================================== + # Build site + # ===================================================== + - name: Build site + if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'merge_group' || startsWith(github.head_ref, 'docs') }} run: | cd docs make site + # ===================================================== + # Deploy + # ===================================================== + + - name: Move built API docs and shinylive to single directory + if: github.ref == 'refs/heads/main' + run: | + mkdir deploy + mv docs/_site deploy/docs + mv shinylive-repo/_shinylive deploy/shinylive + - name: Upload site artifact if: github.ref == 'refs/heads/main' uses: actions/upload-pages-artifact@v1 with: - path: "docs/_site" - + path: "deploy" deploy: if: github.ref == 'refs/heads/main' - needs: build + needs: build-docs # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: - pages: write # to deploy to Pages - id-token: write # to verify the deployment originates from an appropriate source + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source # Deploy to the github-pages environment environment: diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index 6108b3055..ddc857c25 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -5,23 +5,24 @@ on: push: branches: ["main", "rc-*"] pull_request: + merge_group: release: types: [published] schedule: - cron: "0 8 * * *" jobs: - build: + check: runs-on: ubuntu-latest strategy: matrix: # "3.10" must be a string; otherwise it is interpreted as 3.1. - python-version: ["3.11", "3.10", "3.9", "3.8"] + python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"] os: [ubuntu-latest, windows-latest, macOS-latest] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup py-shiny id: install uses: ./.github/py-shiny/setup @@ -31,62 +32,76 @@ jobs: - name: Run unit tests if: steps.install.outcome == 'success' && (success() || failure()) run: | - make test + make check-tests - - name: Type check with pyright + - name: Type check if: steps.install.outcome == 'success' && (success() || failure()) run: | - make pyright + make check-types - - name: Lint with flake8 + - name: Lint code if: steps.install.outcome == 'success' && (success() || failure()) run: | - make lint + make check-lint - - name: black and isort + - name: Verify code formatting if: steps.install.outcome == 'success' && (success() || failure()) run: | - make check + make check-format playwright-shiny: runs-on: ${{ matrix.os }} if: github.event_name != 'release' strategy: matrix: - python-version: ["3.11", "3.10", "3.9", "3.8"] + python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"] os: [ubuntu-latest] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup py-shiny uses: ./.github/py-shiny/setup with: python-version: ${{ matrix.python-version }} + - name: Determine browsers for testing + uses: ./.github/py-shiny/pytest-browsers + id: browsers + with: + all-browsers: ${{ startsWith(github.head_ref, 'playwright') }} + - name: Display browser + shell: bash + run: echo '${{ steps.browsers.outputs.browsers }}' - name: Run End-to-End tests timeout-minutes: 20 run: | - make playwright-shiny SUB_FILE=". -vv" + make playwright-shiny SUB_FILE=". -vv" ${{ steps.browsers.outputs.browsers }} + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: "playright-shiny-${{ matrix.os }}-${{ matrix.python-version }}-results" + path: test-results/ + retention-days: 5 playwright-examples: runs-on: ${{ matrix.os }} if: github.event_name != 'release' strategy: matrix: - python-version: ["3.11", "3.10", "3.9", "3.8"] + python-version: ["3.12", "3.11", "3.10", "3.9", "3.8"] os: [ubuntu-latest] fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup py-shiny uses: ./.github/py-shiny/setup with: python-version: ${{ matrix.python-version }} - name: Install node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "18" cache: npm @@ -96,13 +111,58 @@ jobs: run: | npm ci + - name: Determine browsers for testing + uses: ./.github/py-shiny/pytest-browsers + id: browsers + with: + all-browsers: ${{ startsWith(github.head_ref, 'playwright') }} - name: Run example app tests timeout-minutes: 20 run: | - make playwright-examples SUB_FILE=". -vv" + make playwright-examples SUB_FILE=". -vv" ${{ steps.browsers.outputs.browsers }} + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: "playright-examples-${{ matrix.os }}-${{ matrix.python-version }}-results" + path: test-results/ + retention-days: 5 + + playwright-deploys-precheck: + if: github.event_name != 'release' + runs-on: ${{ matrix.os }} + strategy: + matrix: + # Matches deploy server python version + python-version: ["3.10"] + os: [ubuntu-latest] + fail-fast: false + + steps: + - uses: actions/checkout@v4 + - name: Setup py-shiny + uses: ./.github/py-shiny/setup + with: + python-version: ${{ matrix.python-version }} + + - name: Test that deployable example apps work + timeout-minutes: 5 # ~10s locally + env: + DEPLOY_APPS: "false" + run: | + make playwright-deploys SUB_FILE=". -vv" + + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: "playright-examples-${{ matrix.os }}-${{ matrix.python-version }}-results" + path: test-results/ + retention-days: 5 playwright-deploys: + needs: [playwright-deploys-precheck] + if: github.event_name != 'release' && (github.event_name == 'push' || startsWith(github.head_ref, 'deploy')) # Only allow one `playwright-deploys` job to run at a time. (Independent of branch / PR) + # Only one is allowed to run at a time because it is deploying to the same server location. concurrency: playwright-deploys runs-on: ${{ matrix.os }} strategy: @@ -113,21 +173,20 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup py-shiny uses: ./.github/py-shiny/setup with: python-version: ${{ matrix.python-version }} - - name: Test deploys example apps locally - timeout-minutes: 5 + - name: Test that deployable example apps work + timeout-minutes: 5 # ~10s locally env: DEPLOY_APPS: "false" run: | make playwright-deploys SUB_FILE=". -vv" - - name: Deploy apps and run tests (on `push` or on `pull_request` w/ `deploy**` branch) - if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && startsWith(github.head_ref, 'deploy')) }} + - name: Deploy apps and run tests (on `push` or `deploy**` branches) env: DEPLOY_APPS: "true" DEPLOY_CONNECT_SERVER_URL: "https://rsc.radixu.com/" @@ -141,13 +200,20 @@ jobs: run: | make playwright-deploys SUB_FILE=". -vv --numprocesses 12" + - uses: actions/upload-artifact@v4 + if: failure() + with: + name: "playright-deploys-${{ matrix.os }}-${{ matrix.python-version }}-results" + path: test-results/ + retention-days: 5 + pypi: name: "Deploy to PyPI" runs-on: ubuntu-latest if: github.event_name == 'release' - needs: [build] + needs: [check] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: "Set up Python 3.10" uses: actions/setup-python@v4 with: @@ -181,10 +247,11 @@ jobs: testrail-reporting-nightly: runs-on: ${{ matrix.os }} - if: ${{ github.event_name == 'schedule' || (github.event_name == 'pull_request' && startsWith(github.head_ref, 'testrail')) }} + if: ${{ github.event_name == 'schedule' || startsWith(github.head_ref, 'testrail') }} strategy: matrix: python-version: + - "3.12" - "3.11" - "3.10" - "3.9" @@ -193,14 +260,14 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup py-shiny uses: ./.github/py-shiny/setup with: python-version: ${{ matrix.python-version }} - name: Install node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "18" cache: npm diff --git a/.github/workflows/verify-js-built.yaml b/.github/workflows/verify-js-built.yaml index 87ef94435..d38cd1a7d 100644 --- a/.github/workflows/verify-js-built.yaml +++ b/.github/workflows/verify-js-built.yaml @@ -1,9 +1,10 @@ -name: Build +name: Verify built assets on: push: branches: ["main", "rc-*"] pull_request: + merge_group: jobs: verify_js_built: diff --git a/.gitignore b/.gitignore index 70749a9e4..6f46035ff 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ docs/source/reference/ # Developer scratch area _dev/ tests/playwright/deploys/**/requirements.txt +test-results/ diff --git a/.prettierrc b/.prettierrc index 522fca5d9..29f9e0e33 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,11 @@ { - "organizeImportsSkipDestructiveCodeActions": true + "organizeImportsSkipDestructiveCodeActions": true, + "overrides": [ + { + "files": "**/*.scss", + "options": { + "printWidth": 150 + } + } + ] } diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..2bf90ed1c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "posit.shiny", + "esbenp.prettier-vscode", + "ms-python.black-formatter", + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 07dbac4c2..1664fba47 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,6 +24,10 @@ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode" }, + "[scss]": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, "[python]": { "editor.defaultFormatter": "ms-python.black-formatter", "editor.formatOnSave": true, diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f8748f92..2479fed3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,187 @@ All notable changes to Shiny for Python will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +### [UNRELEASED] -## [UNRELEASED] - YYYY-MM-DD +### Breaking Changes + +### New features + +### Bug fixes + +* Fixed #1440: When a Shiny Express app with a `www/` subdirectory was deployed to shinyapps.io or a Connect server, it would not start correctly. (#1442) + +### Other changes + +## [0.10.2] - 2024-05-28 + +### Bug fixes + +* Fixed an issue with output spinners only showing for a split second. (#1429) + +## [0.10.1] - 2024-05-23 + +### Bug fixes + +* Fixed an issue with opacity dimming occurring too often/quickly when outputs are recalculating. (#1415) + +## [0.10.0] - 2024-05-23 + +### Deprecations + +* Restored `@render.data_frame`'s (prematurely removed in v0.9.0) input value `input._selected_rows()`. Please use `.cell_selection()["rows"]` and consider `input._selected_rows()` deprecated. (#1345, #1377) + +* `@render.data_frame`'s method `.input_cell_selection()` has been renamed to `.cell_selection()`. Please use `.cell_selection()` and consider `.input_cell_selection()` deprecated. (#1407) + +* `@render.data_frame`'s input value `input._data_view_indices` has been renamed to `input._data_view_rows` for consistent naming. Please use `input._data_view_rows` and consider `input._data_view_indices` deprecated. (#1377) + +### New features + +* Added busy indicators to provide users with a visual cue when the server is busy calculating outputs or otherwise serving requests to the client. More specifically, a spinner is shown on each calculating/recalculating output, and a pulsing banner is shown at the top of the page when the app is otherwise busy. Use the new `ui.busy_indicator.options()` function to customize the appearance of the busy indicators and `ui.busy_indicator.use()` to disable/enable them. (#918) + +* Added support for creating modules using Shiny Express syntax, and using modules in Shiny Express apps. (#1220) + +* `ui.page_*()` functions gain a `theme` argument that allows you to replace the Bootstrap CSS file with a new CSS file. `theme` can be a local CSS file, a URL, or a [shinyswatch](https://posit-dev.github.io/py-shinyswatch) theme. In Shiny Express apps, `theme` can be set via `express.ui.page_opts()`. (#1334) + +### Bug fixes + +* Fixed an issue that prevented Shiny from serving the `font.css` file referenced in Shiny's Bootstrap CSS file. (#1342) + +* Removed temporary state where a data frame renderer would try to subset to selected rows that did not exist. (#1351, #1377) + +* Fix an issue in the data frame output which caused the table to freeze when filters removed previously selected cells. (#1412) + +### Other changes + +* `Session` is now an abstract base class, and `AppSession` is a concrete subclass of it. Also, `ExpressMockSession` has been renamed `ExpressStubSession` and is a concrete subclass of `Session`. (#1331) + +* The `Session` class now has a method `is_stub_session()`. For `ExpressStubSession`, this method returns `True` for , and `AppSession` objects it returns `False`. (#1331) + +* Closed #1293: The error console would display error messages if an app was disconnected and the user changed an input. (#1339) + +* Fixed an issue where some CSS files were larger than necessary because they had source maps embedded in them. (#1339) + +## [0.9.0] - 2024-04-16 + +### Breaking Changes + +* `@render.data_frame` return values of `DataTable` and `DataGrid` had their parameter of `row_selection: Literal["single", "multiple"]` become deprecated. Please use `selection_mode="row"` or `selection_mode="rows"` instead. (#1198) + +* The `col_widths` argument of `ui.layout_columns()` now sets the `sm` breakpoint by default, rather than the `md` breakpoint. For example, `col_widths=(12, 6, 6)` is now equivalent to `{"sm": (12, 6, 6)}` rather than `{"md": (12, 6, 6)}`. (#1222) + +### New features + +* `Session` objects now have a `set_message_handler(name, fn)` method that allows you to register a message handler function that will be called when a request message with the given name is received from the client (via `Shiny.shinyapp.makeRequest()` (JS)). (#1253) + +* Experimental: `@render.data_frame` return values of `DataTable` and `DataGrid` support `editable=True` to enable editing of the data table cells. (#1198) + +* `ui.card()` and `ui.value_box()` now take an `id` argument that, when provided, is used to report the full screen state of the card or value box to the server. For example, when using `ui.card(id = "my_card", full_screen = TRUE)` you can determine if the card is currently in full screen mode by reading the boolean value of `input.my_card_full_screen()`. (#1215, #1266) + +* Added support for using `shiny.express` in Quarto Dashboards. (#1217) + +* `ui.value_box()`, `ui.layout_columns()` and `ui.layout_column_wrap()` now all have `min_height` and `max_height` arguments. These are useful in filling layouts, like `ui.page_fillable()`, `ui.page_sidebar(fillable=True)` or `ui.page_navbar(fillable=True)`. For example, you can use `ui.layout_columns(min_height=300, max_height=500)` to ensure that a set of items (likely arranged in a row of columns) are always between 300 and 500 pixels tall. (#1223) + +* Added an error console which displays errors in the browser's UI. This is enabled by default when running applications locally, and can be disabled with `shiny run --no-dev-mode`. It is not enabled for applications that are deployed to a server. (#1060) + +* `shiny create` was updated to include some additional templates as well as an option to choose from the new [templates website](https://shiny.posit.co/py/templates/). (#1273, #1277, #1274) + +* `shiny.express.ui.page_opts()` now accepts additional keyword arguments that are passed to the underlying page layout chosen by `shiny.ui.page_auto()`. (#1314) + +### Bug fixes + +* On Windows, Shiny Express app files are now read in as UTF-8. (#1203) + +* `input_dark_mode()` now accepts a `style` argument that can be used to customize the appearance and position of the dark mode toggle switch. (#1207) + +* Calling `ui.update_selectize()` with `choices` and `selected` now clears the current selection before updating the choices and selected value. (#1221) + +* Fixed an issue that could happen with a `ui.card()` or `ui.value_box()` that is rendered dynamically via `@render.ui` when an updated card replaces a card that the user has expanded into full screen mode. Now the full screen state is reset for the new card or value box. If you want to update a card without potentially exiting the full-screen mode, update specific parts of the card using `ui.output_ui()` or `ui.output_text()`. (#1221) + +* `ui.layout_columns()` now correctly applies the `row_heights` at the `xs` breakpoint, if supplied. (#1222) + +* `ui.panel_conditional()` now adds the `.shiny-panel-conditional` class to the `
` element wrapping the conditional panel contents. (#1257) + +* `ui.panel_conditional()` no longer results in unwanted double padding when the parent container uses `gap` for spacing multiple elements (e.g., when used in `ui.layout_columns()`, `ui.page_fillable()`, etc). (#1266) + +* Error messages now use `var(--bs-danger)` instead of `var(--bs-danger-text-emphasis)` for the text color. (#1266) + +### Other changes + +* The fill CSS used by fillable containers (i.e. when `fillable=True`) now uses a [CSS cascade layer](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Cascade_layers) named `htmltools` to reduce the precedence order of the fill CSS. (#1228) + +## [0.8.1] - 2024-03-06 + +### Breaking Changes + +* `ui.page_sidebar()` now places the `title` element in a `.navbar` container that matches the structure of `page_navbar()`. This ensures that the title elements of `page_sidebar()` and `page_navbar()` have consistent appearance. (#1176) + +### Bug fixes + +* Shiny now compiles the Bootstrap 5-based stylesheets for component styles imported from https://github.com/rstudio/shiny. (#1191) + +* Fixed the CSS for `ui.output_ui()` to avoid unwanted double padding when its parent container uses `gap` for spacing multiple elements (e.g., `ui.layout_columns()`, `ui.page_fillable()`, etc). (#1176) + +### Other changes + +* Closed #1178: Removed run-time dependency on asgiref. (#1183) + +* The uvicorn and click packages are no longer needed when running on Emscripten. (#1187) + +* We adjusted the shadows used for cards and popovers. Cards now use a slightly smaller shadow and the same shadow style is also now used by popovers. (#1176) + +* We increased the spacing between elements just slightly. This change is most noticeable in the `layout_columns()` or `layout_column_wrap()` component. In these and other components, you can use `gap` and `padding` arguments to choose your own values, or you can set the `$bslib-spacer` (Sass) or `--bslib-spacer` (CSS) variable. (#1176) + +## [0.8.0] - 2024-03-04 + +### Breaking Changes + +* Page-level sidebars used in `ui.page_sidebar()` and `ui.page_navbar()` will now default to being initially open but collapsible on desktop devices and always open on mobile devices. You can adjust this default choice by setting `ui.sidebar(open=)`. (#1129) + +* `ui.sidebar()` is now a thin wrapper for the internal `ui.Sidebar` class. The `ui.Sidebar` class has been updated to store the sidebar's contents and settings and to delay rendering until the sidebar HTML is actually used. Because most users call `ui.sidebar()` instead of using the class directly, this change is not expected to affect many apps. (#1129) + +### New features + +* Added `ui.input_dark_mode()`, a toggle switch that allows users to switch between light and dark mode. By default, when `ui.input_dark_mode()` is added to an app, the app's color mode follows the users's system preferences, unless the app author sets the `mode` argument. When `ui.input_dark_mode(id=)` is set, the color mode is reported to the server, and server-side color mode updating is possible using `ui.update_dark_mode()`. (#1149) + +* `ui.sidebar(open=)` now accepts a dictionary with keys `desktop` and `mobile`, allowing you to independently control the initial state of the sidebar at desktop and mobile screen sizes. (#1129) + +* Closed #984: In Shiny Express apps, if there is a `"www"` subdirectory in the app's directory, Shiny will serve the files in that directory as static assets, mounted at `/`. (#1170) + +* For Shiny Express apps, added `express.app_opts()`, which allows setting application-level options, like `static_assets` and `debug`. (#1170) + +* Closed #1079: For Shiny Express apps, automatically run a `globals.py` file in the same directory as the app file, if it exists. The code in `globals.py` will be run with the session context set to `None`. (#1172) ### Bug fixes * Fixed `input_task_button` not working in a Shiny module. (#1108) + * Fixed several issues with `page_navbar()` styling. (#1124) +* Fixed `Renderer.output_id` to not contain the module namespace prefix, only the output id. (#1130) + +* Fixed gap-driven spacing between children in fillable `nav_panel()` containers. (#1152) + +* Fixed #1138: An empty value in a date or date range input would cause an error; now it is treated as `None`. (#1139) + +### Other changes + +* `@render.data_frame` now properly fills its container by default. (#1126) + +* We improved the accessibility of the full screen toggle button in cards created with `ui.card(full_screen=True)`. Full-screen cards are now also supported on mobile devices. (#1129) + +* When entering and exiting full-screen card mode, Shiny now emits a client-side custom `bslib.card` event that JavaScript-oriented users can use to react to the full screen state change. (#1129) + +* The sidebar's collapse toggle now has a high `z-index` value to ensure it always appears above elements in the main content area of `ui.layout_sidebar()`. The sidebar overlay also now receives the same high `z-index` on mobile layouts. (#1129) + +* Updated example apps to use lower-case versions of `reactive.Calc`->`reactive.calc`, `reactive.Effect`->`reactive.effect`, and `reactive.Value`->`reactive.value`. (#1164) + +* Closed #1081: The `@expressify()` function now has an option `has_docstring`. This allows the decorator to be used with functions that contain a docstring. (#1163) + +* Replaced use of `sys.stderr.write()` with `print(file=sys.stderr)`, because on some platforms `sys.stderr` can be `None`. (#1131) + +* Replaced soon-to-be deprecated `datetime` method calls when handling `shiny.datetime` inputs. (#1146) + + ## [0.7.1] - 2024-02-05 ### Bug fixes @@ -87,9 +260,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### New features * `shiny create` now allows you to select from a list of template apps. + * `shiny create` provides templates which help you build your own custom JavaScript components. + * Closed #814: The functions `reactive.Calc` and `reactive.Effect` have been changed to have lowercase names: `reactive.calc`, and `reactive.effect`. The old capitalized names are now aliases to the new lowercase names, so existing code will continue to work. Similarly, the class `reactive.Value` has a new alias, `reactive.value`, but in this case, since the original was a class, it keeps the original capitalized name as the primary name. The examples have not been changed yet, but will be changed in a future release. (#822) + * Added `ui.layout_columns()` for creating responsive column-forward layouts based on Bootstrap's 12-column CSS Grid. (#856) + * Added support for Shiny Express apps, which has a simpler, easier-to-use API than the existing API (Shiny Core). Please note that this API is still experimental and may change. (#767) ### Bug fixes @@ -99,27 +276,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Other changes * Closed #492: `shiny.ui.nav()` is now deprecated in favor of the more aptly named `shiny.ui.nav_panel()` (#876). + * Update penguins example to credit Allison Horst and drop usage of `shiny.experimental` (#798). + * `as_fillable_container()` and `as_fill_item()` no longer mutate the `Tag` object that was passed in. Instead, it returns a new `Tag` object. Also closed #856: these functions now put the `html-fill-container` and `html-fill-item` CSS classes last, instead of first. (#862) + * `App()` now accepts a server function with a single `input` parameter, or a server function with parameters `input`, `output` and `session`. Server functions with two or more than three parameters now raise an exception. (#920) ## [0.6.0] - 2023-10-30 ### Breaking Changes + * `shiny.run` only allows positional arguments for `app`, `host`, and `port`, all other arguments must be specified with keywords. ### New features + * `shiny run` now takes `reload-includes` and `reload-excludes` to allow you to define which files trigger a reload (#780). + * `shiny.run` now passes keyword arguments to `uvicorn.run` (#780). + * The `@output` decorator is no longer required for rendering functions; `@render.xxx` decorators now register themselves automatically. You can still use `@output` explicitly if you need to set specific output options (#747, #790). + * Added support for integration with Quarto (#746). + * Added `shiny.render.renderer_components` decorator to help create new output renderers (#621). + * Added `shiny.experimental.ui.popover()`, `update_popover()`, and `toggle_popover()` for easy creation (and server-side updating) of [Bootstrap popovers](https://getbootstrap.com/docs/5.3/components/popovers/). Popovers are similar to tooltips, but are more persistent, and should primarily be used with button-like UI elements (e.g. `input_action_button()` or icons) (#680). + * Added CSS classes to UI input methods (#680) . + * `Session` objects can now accept an asynchronous (or synchronous) function for `.on_flush(fn=)`, `.on_flushed(fn=)`, and `.on_ended(fn=)` (#686). + * `App()` now allows `static_assets` to represent multiple paths. To do this, pass in a dictionary instead of a string (#763). + * The `showcase_layout` argument of `value_box()` now accepts one of three character values: `"left center"`, `"top right"`, `"bottom"`. (#772) + * `value_box()` now supports many new themes and styles, or fully customizable themes using the new `value_box_theme()` function. To reflect the new capabilities, we've replaced `theme_color` with a new `theme` argument. The previous argument will continue work as expected, but with a deprecation warning. (#772) In addition to the Bootstrap theme names (`primary` ,`secondary`, etc.), you can now use the main Boostrap colors (`purple`, `blue`, `red`, etc.). You can also choose to apply the color to the background or foreground by prepending a `bg-` or `text-` prefix to the theme or color name. Finally, we've also added new gradient themes allowing you to pair any two color names as `bg-gradient-{from}-{to}` (e.g., `bg-gradient-purple-blue`). @@ -131,25 +323,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes * `shiny run` now respects the user provided `reload-dir` argument (#765). + * Fixed #646: Wrap bare value box value in `

` tags. (#668) + * Fixed #676: The `render.data_frame` selection feature was underdocumented and buggy (sometimes returning `None` as a row identifier if the pandas data frame's index had gaps in it). With this release, the selection is consistently a tuple of the 0-based row numbers of the selected rows--or `None` if no rows are selected. (#677) + * Added tests to verify that ui input methods, ui labels, ui update (value) methods, and ui output methods work within modules (#696). + * Adjusted the `@render.plot` input type to be `object` to allow for any object (if any) to be returned (#712). + * In `layout_column_wrap()`, when `width` is a CSS unit -- e.g. `width = "400px"` or `width = "25%"` -- and `fixed_width = FALSE`, `layout_column_wrap()` will ensure that the columns are at least `width` wide, unless the parent container is narrower than `width`. (#772) ### Other changes * `input_action_button()` now defaults to having whitespace around it. (#758) + * `layout_sidebar()` now uses an `