Skip to content

Commit f981ed6

Browse files
authored
feat: add shinyRemoveButton selectize.js option (for py-shiny) (#4276)
* fix: supply and retain default selectize.js plugins (for py-shiny) * `npm run build` (GitHub Actions) * Move more in a 'remove_button' attribute direction * `npm run build` (GitHub Actions) * Move to a JSON-only approach * `npm run build` (GitHub Actions) * Drop sticky update logic by always sending 'missing' value and resolving client-side * Cleanup * Don't mutate options; better typing pattern * `npm run build` (GitHub Actions) --------- Co-authored-by: cpsievert <[email protected]>
1 parent 6d6b0ea commit f981ed6

File tree

6 files changed

+94
-17
lines changed

6 files changed

+94
-17
lines changed

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.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.

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)