Skip to content

Commit 3611c13

Browse files
committed
wip implement dynamic navs
1 parent c8c9190 commit 3611c13

File tree

10 files changed

+639
-806
lines changed

10 files changed

+639
-806
lines changed

shiny/ui/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from ._insert import *
2020
from ._modal import *
2121
from ._navs import *
22+
from ._navs_dynamic import *
2223
from ._notification import *
2324
from ._output import *
2425
from ._page import *

shiny/ui/_navs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
from .._docstring import add_example
2727
from ._html_dependencies import nav_deps
28+
from .._utils import drop_none
2829

2930

3031
@add_example()
@@ -678,4 +679,4 @@ def navs_bar(
678679

679680
def _nav_tag(name: str, *args: TagChildArg, **kwargs: JSXTagAttrArg) -> JSXTag:
680681
tag = jsx_tag_create("bslib." + name)
681-
return tag(nav_deps(), *args, **kwargs)
682+
return tag(nav_deps(), *args, **drop_none(kwargs))

shiny/ui/_navs_dynamic.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
__all__ = (
2+
"nav_append",
3+
"nav_prepend",
4+
"nav_insert",
5+
"nav_remove",
6+
"nav_hide",
7+
"nav_show",
8+
)
9+
10+
import sys
11+
from typing import Optional
12+
13+
if sys.version_info >= (3, 8):
14+
from typing import Literal
15+
else:
16+
from typing_extensions import Literal
17+
18+
from htmltools import JSXTag
19+
20+
from ._input_update import update_navs
21+
from ._navs import navs_hidden
22+
from ..session import Session, require_active_session
23+
from .._utils import run_coro_sync
24+
25+
26+
def nav_append(
27+
id: str,
28+
nav: JSXTag,
29+
menu_title: Optional[str] = None,
30+
select: bool = False,
31+
session: Optional[Session] = None,
32+
) -> None:
33+
34+
session = require_active_session(session)
35+
# TODO: do we need to namespace the id?
36+
# id = session.ns(id)
37+
38+
# The currrent JSX implementation of nav items is not smart enough to
39+
# to render without a navs container (maybe it could?), so we need to
40+
# wrap in one and also notify the JSX logic to not select the nav
41+
# (shiny.js handles that part via the select parameter).
42+
jsx_tag = navs_hidden(nav, selected=False)
43+
44+
msg = {
45+
"inputId": id,
46+
"menuName": menu_title,
47+
"target": None,
48+
"position": "after",
49+
"select": select,
50+
"jsxTag": session.process_ui(jsx_tag),
51+
}
52+
53+
def callback() -> None:
54+
run_coro_sync(session.send_message({"shiny-insert-tab": msg}))
55+
56+
session.on_flush(callback, once=True)
57+
58+
59+
def nav_prepend(
60+
id: str,
61+
nav: JSXTag,
62+
menu_title: Optional[str] = None,
63+
select: bool = False,
64+
session: Optional[Session] = None,
65+
) -> None:
66+
67+
session = require_active_session(session)
68+
# TODO: do we need to namespace the id?
69+
# id = session.ns(id)
70+
71+
# The currrent JSX implementation of nav items is not smart enough to
72+
# to render without a navs container (maybe it could?), so we need to
73+
# wrap in one and also notify the JSX logic to not select the nav
74+
# (shiny.js handles that part via the select parameter).
75+
jsx_tag = navs_hidden(nav, selected=False)
76+
77+
msg = {
78+
"inputId": id,
79+
"menuName": menu_title,
80+
"target": None,
81+
"position": "before",
82+
"select": select,
83+
"jsxTag": session.process_ui(jsx_tag),
84+
}
85+
86+
def callback() -> None:
87+
run_coro_sync(session.send_message({"shiny-insert-tab": msg}))
88+
89+
session.on_flush(callback, once=True)
90+
91+
92+
def nav_insert(
93+
id: str,
94+
nav: JSXTag,
95+
target: Optional[str] = None,
96+
position: Literal["after", "before"] = "after",
97+
select: bool = False,
98+
session: Optional[Session] = None,
99+
) -> None:
100+
101+
session = require_active_session(session)
102+
# TODO: do we need to namespace the id?
103+
# id = session.ns(id)
104+
105+
# The currrent JSX implementation of nav items is not smart enough to
106+
# to render without a navs container (maybe it could?), so we need to
107+
# wrap in one and also notify the JSX logic to not select the nav
108+
# (shiny.js handles that part via the select parameter).
109+
jsx_tag = navs_hidden(nav, selected=False)
110+
111+
msg = {
112+
"inputId": id,
113+
"menuName": None,
114+
"target": target,
115+
"position": position,
116+
"select": select,
117+
"jsxTag": session.process_ui(jsx_tag),
118+
}
119+
120+
def callback() -> None:
121+
run_coro_sync(session.send_message({"shiny-insert-tab": msg}))
122+
123+
session.on_flush(callback, once=True)
124+
125+
126+
def nav_remove(id: str, target: str, session: Optional[Session] = None) -> None:
127+
128+
session = require_active_session(session)
129+
# TODO: do we need to namespace the id?
130+
# id = session.ns(id)
131+
132+
msg = {"inputId": id, "target": target}
133+
134+
def callback() -> None:
135+
run_coro_sync(session.send_message({"shiny-remove-tab": msg}))
136+
137+
session.on_flush(callback, once=True)
138+
139+
140+
def nav_hide(id: str, target: str, session: Optional[Session] = None) -> None:
141+
142+
session = require_active_session(session)
143+
# TODO: do we need to namespace the id?
144+
# id = session.ns(id)
145+
146+
msg = {"inputId": id, "target": target, "type": "hide"}
147+
148+
def callback() -> None:
149+
run_coro_sync(session.send_message({"shiny-change-tab-visibility": msg}))
150+
151+
session.on_flush(callback, once=True)
152+
153+
154+
def nav_show(
155+
id: str, target: str, select: bool = False, session: Optional[Session] = None
156+
) -> None:
157+
"""
158+
Show a nav
159+
"""
160+
161+
session = require_active_session(session)
162+
163+
if select:
164+
update_navs(id, selected=target)
165+
166+
# TODO: do we need to namespace the id?
167+
# id = session.ns(id)
168+
msg = {"inputId": id, "target": target, "type": "show"}
169+
170+
def callback() -> None:
171+
run_coro_sync(session.send_message({"shiny-change-tab-visibility": msg}))
172+
173+
session.on_flush(callback, once=True)

shiny/www/shared/bslib/dist/navs.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

shiny/www/shared/bslib/dist/navs.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)