Skip to content

Commit 9fd03b2

Browse files
committed
Simplify to always include clear_button plugin
1 parent 9c1e6f6 commit 9fd03b2

File tree

2 files changed

+19
-31
lines changed

2 files changed

+19
-31
lines changed

shiny/ui/_input_select.py

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def input_selectize(
5858
selected: Optional[str | list[str]] = None,
5959
multiple: bool = False,
6060
width: Optional[str] = None,
61-
remove_button: Optional[bool] = None,
61+
remove_button: bool = True,
6262
options: Optional[dict[str, Jsonifiable | JSEval]] = None,
6363
) -> Tag:
6464
"""
@@ -84,9 +84,10 @@ def input_selectize(
8484
width
8585
The CSS width, e.g. '400px', or '100%'
8686
remove_button
87-
Whether to add a remove button. This uses the `clear_button` and `remove_button`
88-
selectize plugins which can also be supplied as options. By default it will apply a
89-
remove button to multiple selections, but not single selections.
87+
Whether to add a remove button. When `True` (the default), both the
88+
'clear_button' and 'remove_button' plugins are included. If you want just one
89+
plugin, set this to `False` and specify the desired plugin in the `options`
90+
argument (i.e., `options = {"plugins": ["remove_button"]}`).
9091
options
9192
A dictionary of options. See the documentation of selectize.js for possible options.
9293
If you want to pass a JavaScript function, wrap the string in `ui.JS`.
@@ -200,8 +201,8 @@ def input_select(
200201
"Use `input_selectize()` instead of passing `selectize=True`."
201202
)
202203

203-
if isinstance(remove_button, MISSING_TYPE):
204-
remove_button = None
204+
if isinstance(remove_button, MISSING_TYPE) or remove_button is None:
205+
remove_button = True
205206
else:
206207
warn_deprecated(
207208
"`remove_button` parameter of `input_select()` is deprecated. "
@@ -244,7 +245,7 @@ def _input_select_impl(
244245
selectize: bool = False,
245246
width: Optional[str] = None,
246247
size: Optional[str] = None,
247-
remove_button: Optional[bool] = None,
248+
remove_button: bool = True,
248249
options: Optional[dict[str, Jsonifiable | JSEval]] = None,
249250
) -> Tag:
250251
if options is not None and selectize is False:
@@ -261,7 +262,15 @@ def _input_select_impl(
261262
if options is None:
262263
options = {}
263264

264-
plugins = _get_default_plugins(remove_button, multiple, choices_)
265+
# Although 'remove_button' is primarily for multiple=True and 'clear_button' is for
266+
# multiple=False, we include both in either case since:
267+
# 1. When multiple=True, 'clear_button' can be used to clear _all_ selected items.
268+
# 2. When multiple=False, 'remove_button' is effectively a no-op.
269+
# 3. By including both, we can simplify the client-side logic needed to retain
270+
# these plugins across update_selectize(options=...) calls
271+
default_plugins = None
272+
if remove_button or remove_button is None:
273+
default_plugins = json.dumps(["remove_button", "clear_button"])
265274

266275
choices_tags = _render_choices(choices_, selected)
267276

@@ -283,7 +292,7 @@ def _input_select_impl(
283292
# Which option values should be interpreted as JS?
284293
data_eval=json.dumps(extract_js_keys(options)),
285294
# Supply and retain these plugins across updates (on the client)
286-
data_default_plugins=json.dumps(plugins),
295+
data_default_plugins=default_plugins,
287296
),
288297
selectize_deps() if selectize else None,
289298
),
@@ -292,26 +301,6 @@ def _input_select_impl(
292301
)
293302

294303

295-
def _get_default_plugins(
296-
remove_button: bool | None,
297-
multiple: bool,
298-
choices_: _SelectChoices,
299-
) -> tuple[str, ...]:
300-
if remove_button:
301-
# remove_button: remove _each_ item when multiple=True
302-
# clear_button: clear _all_ items when multiple=True
303-
return ("remove_button", "clear_button")
304-
305-
if remove_button is None:
306-
if multiple:
307-
return ("remove_button", "clear_button")
308-
if "" in choices_:
309-
# Only show clear button if there is an empty choice
310-
return ("clear_button",)
311-
312-
return ()
313-
314-
315304
def _normalize_choices(x: SelectChoicesArg) -> _SelectChoices:
316305
if x is None:
317306
raise TypeError("`choices` must be a list, tuple, or dict.")

shiny/ui/_input_update.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,7 @@ def update_selectize(
766766

767767
session = require_active_session(session)
768768

769-
# Unless specified otherwise, the default plugins are retained
770-
# across updates (by the client)
769+
# Don't change default plugins unless explicitly specified
771770
default_plugins = None
772771
if remove_button is True:
773772
default_plugins = json.dumps(["remove_button", "clear_button"])

0 commit comments

Comments
 (0)