-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement dynamic navs (i.e., nav_insert(), nav_remove(), nav_show(),…
… nav_hide())
- Loading branch information
Showing
7 changed files
with
320 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from shiny import * | ||
|
||
app_ui = ui.page_fluid( | ||
ui.layout_sidebar( | ||
ui.panel_sidebar( | ||
ui.input_action_button("add", "Add 'Dynamic' tab"), | ||
ui.input_action_button("removeFoo", "Remove 'Foo' tabs"), | ||
ui.input_action_button("addFoo", "Add New 'Foo' tab"), | ||
), | ||
ui.panel_main( | ||
ui.navs_tab( | ||
ui.nav("Hello", "This is the hello tab"), | ||
ui.nav("Foo", "This is the Foo tab", value="Foo"), | ||
ui.nav_menu( | ||
"Static", | ||
ui.nav("Static 1", "Static 1", value="s1"), | ||
ui.nav("Static 2", "Static 2", value="s2"), | ||
value="Menu", | ||
), | ||
id="tabs", | ||
), | ||
), | ||
) | ||
) | ||
|
||
|
||
def server(input: Inputs, output: Outputs, session: Session): | ||
@reactive.Effect() | ||
@event(input.add) | ||
def _(): | ||
id = "Dynamic-" + str(input.add()) | ||
ui.nav_insert( | ||
"tabs", | ||
ui.nav(id, id), | ||
target="s2", | ||
position="before", | ||
) | ||
|
||
@reactive.Effect() | ||
@event(input.removeFoo) | ||
def _(): | ||
ui.nav_remove("tabs", target="Foo") | ||
|
||
@reactive.Effect() | ||
@event(input.addFoo) | ||
def _(): | ||
n = str(input.addFoo()) | ||
ui.nav_insert( | ||
"tabs", | ||
ui.nav("Foo-" + n, "This is the new Foo-" + n + " tab", value="Foo"), | ||
target="Menu", | ||
position="before", | ||
select=True, | ||
) | ||
|
||
|
||
app = App(app_ui, server, debug=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
from shiny import * | ||
|
||
app_ui = ui.page_navbar( | ||
ui.nav( | ||
"Home", | ||
ui.input_action_button("hideTab", "Hide 'Foo' tab"), | ||
ui.input_action_button("showTab", "Show 'Foo' tab"), | ||
ui.input_action_button("hideMenu", "Hide 'More' nav_menu"), | ||
ui.input_action_button("showMenu", "Show 'More' nav_menu"), | ||
), | ||
ui.nav("Foo", "This is the foo tab"), | ||
ui.nav("Bar", "This is the bar tab"), | ||
ui.nav_menu( | ||
"More", | ||
ui.nav("Table", "Table page"), | ||
ui.nav("About", "About page"), | ||
"------", | ||
"Even more!", | ||
ui.nav("Email", "Email page"), | ||
), | ||
title="Navbar page", | ||
id="tabs", | ||
) | ||
|
||
|
||
def server(input: Inputs, output: Outputs, session: Session): | ||
@reactive.Effect() | ||
@event(input.hideTab) | ||
def _(): | ||
ui.nav_hide("tabs", target="Foo") | ||
|
||
@reactive.Effect() | ||
@event(input.showTab) | ||
def _(): | ||
ui.nav_show("tabs", target="Foo") | ||
|
||
@reactive.Effect() | ||
@event(input.hideMenu) | ||
def _(): | ||
ui.nav_hide("tabs", target="More") | ||
|
||
@reactive.Effect() | ||
@event(input.showMenu) | ||
def _(): | ||
ui.nav_show("tabs", target="More") | ||
|
||
|
||
app = App(app_ui, server) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
__all__ = ( | ||
"nav_insert", | ||
"nav_remove", | ||
"nav_hide", | ||
"nav_show", | ||
) | ||
|
||
import sys | ||
from typing import Optional, Union | ||
|
||
if sys.version_info >= (3, 8): | ||
from typing import Literal | ||
else: | ||
from typing_extensions import Literal | ||
|
||
from .._docstring import add_example | ||
from ._input_update import update_navs | ||
from ._navs import menu_string_as_nav | ||
from ..types import NavsArg | ||
from ..session import Session, require_active_session | ||
from .._utils import run_coro_sync | ||
|
||
|
||
@add_example() | ||
def nav_insert( | ||
id: str, | ||
nav: Union[NavsArg, str], | ||
target: Optional[str] = None, | ||
position: Literal["after", "before"] = "after", | ||
select: bool = False, | ||
session: Optional[Session] = None, | ||
) -> None: | ||
""" | ||
Insert a new nav item into a navigation container. | ||
Parameters | ||
---------- | ||
id | ||
The ``id`` of the relevant navigation container (i.e., ``navs_*()`` object). | ||
nav | ||
The navigation item to insert (typically a :func:`~shiny.ui.nav` or | ||
:func:`~shiny.ui.nav_menu`). A :func:`~shiny.ui.nav_menu` isn't allowed when the | ||
``target`` references an :func:`~shiny.ui.nav_menu` (or an item within it). A | ||
string is only allowed when the ``target`` references a | ||
:func:`~shiny.ui.nav_menu`. | ||
target | ||
The ``value`` of an existing :func:`shiny.ui.nav` item, next to which tab will | ||
be added. | ||
position | ||
The position of the new nav item relative to the target nav item. | ||
select | ||
Whether the nav item should be selected upon insertion. | ||
session | ||
A :class:`~shiny.Session` instance. If not provided, it is inferred via | ||
:func:`~shiny.session.get_current_session`. | ||
See Also | ||
-------- | ||
~nav_remove | ||
~nav_show | ||
~nav_hide | ||
~shiny.ui.nav | ||
""" | ||
|
||
session = require_active_session(session) | ||
|
||
# N.B. this is only sensible if the target is a menu, but we don't know that, | ||
# which could cause confusion of we decide to support top-level strings at some | ||
# in the future. | ||
if isinstance(nav, str): | ||
nav = menu_string_as_nav(nav) | ||
|
||
# N.B. shiny.js' is smart enough to know how to add active classes and href/id attrs | ||
li_tag, div_tag = nav.resolve(selected=None) | ||
|
||
msg = { | ||
"inputId": session.ns(id), | ||
"liTag": session._process_ui(li_tag), | ||
"divTag": session._process_ui(div_tag), | ||
"menuName": None, | ||
"target": target, | ||
"position": position, | ||
"select": select, | ||
} | ||
|
||
def callback() -> None: | ||
run_coro_sync(session._send_message({"shiny-insert-tab": msg})) | ||
|
||
session.on_flush(callback, once=True) | ||
|
||
|
||
def nav_remove(id: str, target: str, session: Optional[Session] = None) -> None: | ||
""" | ||
Remove a nav item from a navigation container. | ||
Parameters | ||
---------- | ||
id | ||
The ``id`` of the relevant navigation container (i.e., ``navs_*()`` object). | ||
target | ||
The ``value`` of an existing :func:`shiny.ui.nav` item to remove. | ||
session | ||
A :class:`~shiny.Session` instance. If not provided, it is inferred via | ||
:func:`~shiny.session.get_current_session`. | ||
See Also | ||
-------- | ||
~nav_insert | ||
~nav_show | ||
~nav_hide | ||
~shiny.ui.nav | ||
""" | ||
|
||
session = require_active_session(session) | ||
|
||
msg = {"inputId": session.ns(id), "target": target} | ||
|
||
def callback() -> None: | ||
run_coro_sync(session._send_message({"shiny-remove-tab": msg})) | ||
|
||
session.on_flush(callback, once=True) | ||
|
||
|
||
def nav_show( | ||
id: str, target: str, select: bool = False, session: Optional[Session] = None | ||
) -> None: | ||
""" | ||
Show a navigation item | ||
Parameters | ||
---------- | ||
id | ||
The ``id`` of the relevant navigation container (i.e., ``navs_*()`` object). | ||
target | ||
The ``value`` of an existing :func:`shiny.ui.nav` item to show. | ||
select | ||
Whether the nav item's content should also be shown. | ||
session | ||
A :class:`~shiny.Session` instance. If not provided, it is inferred via | ||
:func:`~shiny.session.get_current_session`. | ||
Note | ||
---- | ||
For ``nav_show()`` to be relevant/useful, a :func:`shiny.ui.nav` item must | ||
have been hidden using :func:`~nav_hide`. | ||
See Also | ||
-------- | ||
~nav_hide | ||
~nav_insert | ||
~nav_remove | ||
~shiny.ui.nav | ||
""" | ||
|
||
session = require_active_session(session) | ||
|
||
if select: | ||
update_navs(id, selected=target) | ||
|
||
msg = {"inputId": session.ns(id), "target": target, "type": "show"} | ||
|
||
def callback() -> None: | ||
run_coro_sync(session._send_message({"shiny-change-tab-visibility": msg})) | ||
|
||
session.on_flush(callback, once=True) | ||
|
||
|
||
def nav_hide(id: str, target: str, session: Optional[Session] = None) -> None: | ||
""" | ||
Hide a navigation item | ||
Parameters | ||
---------- | ||
id | ||
The ``id`` of the relevant navigation container (i.e., ``navs_*()`` object). | ||
target | ||
The ``value`` of an existing :func:`shiny.ui.nav` item to hide. | ||
session | ||
A :class:`~shiny.Session` instance. If not provided, it is inferred via | ||
:func:`~shiny.session.get_current_session`. | ||
See Also | ||
-------- | ||
~nav_show | ||
~nav_insert | ||
~nav_remove | ||
~shiny.ui.nav | ||
""" | ||
|
||
session = require_active_session(session) | ||
|
||
msg = {"inputId": session.ns(id), "target": target, "type": "hide"} | ||
|
||
def callback() -> None: | ||
run_coro_sync(session._send_message({"shiny-change-tab-visibility": msg})) | ||
|
||
session.on_flush(callback, once=True) |