Skip to content

Commit 0d44c2b

Browse files
authored
Merge branch 'main' into feat/otel
2 parents 6aaaf43 + f981ed6 commit 0d44c2b

File tree

9 files changed

+104
-18
lines changed

9 files changed

+104
-18
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
* `updateActionButton()`/`updateActionLink()` now correctly renders HTML content passed to the `label` argument. (#4249)
1010

11+
* Fixed an issue where `updateSelectizeInput(options = list(plugins="remove_button"))` could lead to multiple remove buttons. (#4275)
12+
1113
## Changes
1214

1315
* The return value of `actionButton()`/`actionLink()` changed slightly: `label` and `icon` are wrapped in an additional HTML container element. This allows for: 1. `updateActionButton()`/`updateActionLink()` to distinguish between the `label` and `icon` when making updates and 2. spacing between `label` and `icon` to be more easily customized via CSS.

inst/www/shared/shiny.js

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/www/shared/shiny.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/www/shared/shiny.min.css

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

inst/www/shared/shiny.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.

inst/www/shared/shiny.min.js.map

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

inst/www/shared/shiny_scss/shiny.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,13 @@ textarea.textarea-autoresize.form-control {
480480
cursor: not-allowed;
481481
}
482482

483+
// Selectize's remove_button plugin has a bug that can lead to multiple remove
484+
// buttons being displayed when options get updated. This prevents that from
485+
// happening (see #4274 for reprex)
486+
.shiny-input-select .selectize-input > .item > .remove:not(:first-child) {
487+
display: none;
488+
}
489+
483490
/* Hidden tabPanels */
484491
.nav-hidden {
485492
/* override anything bootstrap sets for `.nav` */

srcts/src/bindings/input/selectInput.ts

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,23 @@ type SelectInputReceiveMessageData = {
1313
value?: string;
1414
};
1515

16-
type SelectizeOptions = Selectize.IOptions<string, unknown>;
1716
type SelectizeInfo = Selectize.IApi<string, unknown> & {
18-
settings: SelectizeOptions;
17+
settings: Selectize.IOptions<string, unknown>;
18+
};
19+
20+
type SelectizeOptions = Selectize.IOptions<string, unknown> & {
21+
// Provide some stronger typing for the Selectize options
22+
labelField: "label";
23+
valueField: "value";
24+
searchField: ["label"];
25+
onItemRemove?: (value: string) => void;
26+
onDropdownClose?: () => void;
27+
};
28+
29+
// Adds a py-shiny specific "option" that makes the
30+
// input_selectize(remove_button) parameter possible
31+
type SelectizeShinyOptions = SelectizeOptions & {
32+
shinyRemoveButton?: "none" | "true" | "false" | "both";
1933
};
2034

2135
function getLabelNode(el: SelectHTMLElement): JQuery<HTMLElement> {
@@ -244,13 +258,7 @@ class SelectInputBinding extends InputBinding {
244258

245259
if (config.length === 0) return undefined;
246260

247-
let options: SelectizeOptions & {
248-
labelField: "label";
249-
valueField: "value";
250-
searchField: ["label"];
251-
onItemRemove?: (value: string) => void;
252-
onDropdownClose?: () => void;
253-
} = $.extend(
261+
let options: SelectizeShinyOptions = $.extend(
254262
{
255263
labelField: "label",
256264
valueField: "value",
@@ -259,6 +267,8 @@ class SelectInputBinding extends InputBinding {
259267
JSON.parse(config.html()),
260268
);
261269

270+
options = this._addShinyRemoveButton(options, el.hasAttribute("multiple"));
271+
262272
// selectize created from selectInput()
263273
if (typeof config.data("nonempty") !== "undefined") {
264274
el.nonempty = true;
@@ -305,6 +315,44 @@ class SelectInputBinding extends InputBinding {
305315

306316
return control;
307317
}
318+
319+
// Translate shinyRemoveButton option into selectize plugins
320+
private _addShinyRemoveButton(
321+
options: SelectizeShinyOptions,
322+
multiple: boolean,
323+
): SelectizeOptions {
324+
let removeButton = options.shinyRemoveButton;
325+
if (removeButton === undefined) {
326+
return options;
327+
}
328+
329+
// None really means 'smart default'
330+
if (removeButton === "none") {
331+
removeButton = multiple ? "true" : "false";
332+
}
333+
334+
if (removeButton === "false") {
335+
return options;
336+
}
337+
338+
const plugins = [];
339+
if (removeButton === "both") {
340+
plugins.push("remove_button", "clear_button");
341+
} else if (removeButton === "true") {
342+
plugins.push(multiple ? "remove_button" : "clear_button");
343+
}
344+
345+
// Add plugins to existing plugins if not already present
346+
return {
347+
...options,
348+
plugins: Array.from(
349+
new Set([
350+
...(Array.isArray(options.plugins) ? options.plugins : []),
351+
...plugins,
352+
]),
353+
),
354+
};
355+
}
308356
}
309357

310358
export { SelectInputBinding };

srcts/types/src/bindings/input/selectInput.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ type SelectInputReceiveMessageData = {
99
url?: string;
1010
value?: string;
1111
};
12-
type SelectizeOptions = Selectize.IOptions<string, unknown>;
1312
type SelectizeInfo = Selectize.IApi<string, unknown> & {
14-
settings: SelectizeOptions;
13+
settings: Selectize.IOptions<string, unknown>;
1514
};
1615
declare class SelectInputBinding extends InputBinding {
1716
find(scope: HTMLElement): JQuery<HTMLElement>;
@@ -32,6 +31,7 @@ declare class SelectInputBinding extends InputBinding {
3231
unsubscribe(el: HTMLElement): void;
3332
initialize(el: SelectHTMLElement): void;
3433
protected _selectize(el: SelectHTMLElement, update?: boolean): SelectizeInfo | undefined;
34+
private _addShinyRemoveButton;
3535
}
3636
export { SelectInputBinding };
3737
export type { SelectInputReceiveMessageData };

0 commit comments

Comments
 (0)