New features
* Added a new `shiny.ui.Chat` class for building conversational interfaces with fully customizable and performant response generation. (1453)
* Expose `shiny.playwright`, `shiny.run`, and `shiny.pytest` modules that allow users to testing their Shiny apps. (1448, 1456, 1481)
* `shiny.playwright` contains `controller` and `expect` submodules. `controller` will contain **many** classes to interact with (and verify!) your Shiny app using Playwright. `expect` contains expectation functions that enhance standard Playwright expectation methods.
* `shiny.run` contains the `run_shiny_app` command and the return type `ShinyAppProc`. `ShinyAppProc` can be used to type the Shiny app pytest fixtures.
* `shiny.pytest` contains pytest test fixtures. The `local_app` pytest fixture is automatically available and runs a sibling `app.py` file. Where as `create_app_fixture(PATH_TO_APP)` allows for a relative path to a Shiny app to be instantiated from a different folder.
* Added CLI command `shiny add test` to add a test file to an existing Shiny app. (1461)
* `render.data_frame`, `render.DataGrid`, and `render.DataTable` now support `polars` data frames (1474).
* `render.data_frame`, `render.DataGrid`, and `render.DataTable` are now type aware. This means that the data frame renderer object's `.data()` and `.data_view()` methods will return the same type of data given the the renderer. E.g. If a `DataGrid` wrapping a `polars` data frame is returned to the renderer function, `.data_view()` will return `polars` data. (1502)
* `render.data_frame`'s `render.DataGrid` and `render.DataTable` added support for cell styling with the new `styles=` parameter. This parameter can receive a style info object (or a list of style info objects), or a function that accepts a data frame and returns a list of style info objects. Each style info object can contain the `rows` and `cols` locations where the inline `style` and/or CSS `class` should be applied. (1475)
* `render.data_frame` has added a few new methods:
* `.data_view_rows()` is a reactive value representing the sorted and filtered row numbers. This value wraps `input.<ID>_data_view_rows()`(1374)
* `.sort()` is a reactive value representing the sorted column information (dictionaries containing `col: int` and `desc: bool`). This value wraps `input.<ID>_sort()`. (1374)
* `.filter()` is a reactive value representing the filtered column information (dictionaries containing `col: int` and `value` which is either a string or a length 2 array of at least one non-`None` number). This value wraps `input.<ID>_filter()`. (1374)
* `.update_sort(sort=)` allows app authors to programmatically update the sorting of the data frame. (1374)
* `.update_filter(filter=)` allows app authors to programmatically update the filtering of the data frame. (1374)
* `render.data_frame` now accepts both a non-`"none"` `selection_mode` value and `editable=True`. (1454, 1534)
* `render.data_frame`'s `<ID>.cell_selection()` no longer returns a `None` value and now always returns a dictionary containing both the `rows` and `cols` keys. This is done to achieve more consistent author code when working with cell selection. When the value's `type="none"`, both `rows` and `cols` are empty tuples. When `type="row"`, `cols` represents all column numbers of the data. In the future, when `type="col"`, `rows` will represent all row numbers of the data. These extra values are not available in `input.<ID>_cell_selection()` as they are independent of cells being selected and are removed to reduce information being sent to and from the browser. (1376)
* Relative imports, like `from . import utils`, now can be used in Shiny Express apps. (1464)
* `ui.Theme` allows you to create custom themes for your Shiny app by recompiling [Bootstrap](https://getbootstrap.com/) and Shiny's Sass files with your own customizations. Themes created with `ui.Theme` can be passed directly to the `theme` argument of `express.ui.page_opts()` (Shiny Express) or `ui.page_*()` functions (Shiny Core) to apply the theme to the entire app. This feature requires the [libsass package](https://sass.github.io/libsass-python/) which can be installed with `pip install libsass`. (#1358)
* `ui.card_body()` can be used to wrap the contents of elements in `ui.card()`, allowing you to change parameters like `fillable` or `padding` and `gap` for groups of elements in the card. (1506)
Other changes
* `ui.input_action_button()` and `ui.update_action_button()` gain a `disabled` argument. When the button is disabled, it appears grayed out and cannot be clicked. (1465)
* The main content area of `ui.page_sidebar()` and `ui.page_navbar()` with a page-level `sidebar` now have a minimum height and width to avoid squashed content in fillable layouts. The minimum height and width are controllable via `--bslib-page-main-min-{width,height}` CSS variables. (1436)
* Added a new option to place an always-open sidebar *above the main content* on mobile screens by providing `open={"mobile": "always-above"}` to `ui.sidebar()`. (1436)
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)
* Fixed 1498: Update table related TypeScript dependencies to their latest versions. This fixed an issue where the Row Virtualizer would scroll to the end when hidden. This would cause the DOM to update numerous times, locking up the browser tab for multiple seconds. (1524, 1550)
* The return type for the data frame patch function now returns a list of `render.CellPatch` objects (which support `htmltools.TagNode` for the `value` attribute). These values will be set inside the data frame's `.data_view()` result. This also means that `.cell_patches()` will be a list of `render.CellPatch` objects. (1526)
* Made sure all `render.data_frame` cells that have been edited are now restored back to ready state to handle the off chance that the returned patches are at different locations the the original edit patches. (1529)
* `remove_all_fill(tag)` no longer modifies the original `tag` input and instead returns a modified copy of `tag`. (1538)
Deprecations
* The following deprecated functions have now been removed (1546):
* `shiny.ui.panel_sidebar()` was deprecated in v0.6.0; use `shiny.ui.sidebar()` instead.
* `shiny.ui.panel_main()` was deprecated in v0.6.0; instead pass items directly to `shiny.ui.layout_sidebar()`.
* `shiny.ui.navset_pill_card()` was deprecated in v0.6.0; use `shiny.ui.navset_card_pill()` instead.
* `shiny.ui.navset_tab_card()` was deprecated in v0.6.0; use `shiny.ui.navset_card_tab()` instead.
* `shiny.ui.nav()` was deprecated in v0.6.1; use `shiny.ui.nav_panel()` instead.
* `render.data_frame`, `render.DataGrid`, and `render.DataTable` have deprecated support for data frame types that are `pandas` compatible. Please call `.to_pandas()` on your data before it is returned to the renderer (1502). Currently, both `polars` and `pandas` data frames are supported (1474). If you'd like to add support for a new data frame type, please open an issue or a pull request.
* `render.data_frame`'s `.cell_selection()` will no longer return `None` when the selection mode is `"none"`. In addition, missing `rows` or `cols` information will be populated with appropiate values. This allows for consistent handling of the cell selection object. (1374)
* `render.data_frame`'s input value `input.<ID>_data_view_indices()` has been deprecated. Please use `<ID>.data_view_rows()` to retrieve the same information. (1377)
* `render.data_frame`'s input value `input.<ID>_column_sort()` has been deprecated. Please use `<ID>.sort()` to retrieve the same information. (1374)
* `render.data_frame`'s input value `input.<ID>_column_filter()` has been deprecated. Please use `<ID>.filter()` to retrieve the same information. (1374)
* Deprecated functions in `shiny.experimental` have been removed. By and large, these functions are now available in the main `shiny` namespace. (1540)
* We've deprecated several card-related `shiny.experimental.ui` functions that were moved to the main `shiny.ui` namespace in v0.6.0. Both `card()` and `card_body()` are no longer experimental and can be called via `shiny.ui.card()` and `shiny.ui.card_body()` directly. `shiny.experimental.ui.card_title()` is now deprecated, but can be replaced with `shiny.ui.tags.h5()` or `shiny.ui.card_header()`. (1543)