mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-09 15:08:04 -05:00
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 <cpsievert@users.noreply.github.com>
This commit is contained in:
@@ -2414,6 +2414,7 @@
|
|||||||
},
|
},
|
||||||
JSON.parse(config.html())
|
JSON.parse(config.html())
|
||||||
);
|
);
|
||||||
|
options = this._addShinyRemoveButton(options, el.hasAttribute("multiple"));
|
||||||
if (typeof config.data("nonempty") !== "undefined") {
|
if (typeof config.data("nonempty") !== "undefined") {
|
||||||
el.nonempty = true;
|
el.nonempty = true;
|
||||||
options = import_jquery19.default.extend(options, {
|
options = import_jquery19.default.extend(options, {
|
||||||
@@ -2450,6 +2451,34 @@
|
|||||||
}
|
}
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
// Translate shinyRemoveButton option into selectize plugins
|
||||||
|
_addShinyRemoveButton(options, multiple) {
|
||||||
|
let removeButton = options.shinyRemoveButton;
|
||||||
|
if (removeButton === void 0) {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
if (removeButton === "none") {
|
||||||
|
removeButton = multiple ? "true" : "false";
|
||||||
|
}
|
||||||
|
if (removeButton === "false") {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
const plugins = [];
|
||||||
|
if (removeButton === "both") {
|
||||||
|
plugins.push("remove_button", "clear_button");
|
||||||
|
} else if (removeButton === "true") {
|
||||||
|
plugins.push(multiple ? "remove_button" : "clear_button");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
plugins: Array.from(
|
||||||
|
/* @__PURE__ */ new Set([
|
||||||
|
...Array.isArray(options.plugins) ? options.plugins : [],
|
||||||
|
...plugins
|
||||||
|
])
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// srcts/src/bindings/input/slider.ts
|
// srcts/src/bindings/input/slider.ts
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
2
inst/www/shared/shiny.min.js
vendored
2
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,9 +13,23 @@ type SelectInputReceiveMessageData = {
|
|||||||
value?: string;
|
value?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SelectizeOptions = Selectize.IOptions<string, unknown>;
|
|
||||||
type SelectizeInfo = Selectize.IApi<string, unknown> & {
|
type SelectizeInfo = Selectize.IApi<string, unknown> & {
|
||||||
settings: SelectizeOptions;
|
settings: Selectize.IOptions<string, unknown>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SelectizeOptions = Selectize.IOptions<string, unknown> & {
|
||||||
|
// Provide some stronger typing for the Selectize options
|
||||||
|
labelField: "label";
|
||||||
|
valueField: "value";
|
||||||
|
searchField: ["label"];
|
||||||
|
onItemRemove?: (value: string) => void;
|
||||||
|
onDropdownClose?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Adds a py-shiny specific "option" that makes the
|
||||||
|
// input_selectize(remove_button) parameter possible
|
||||||
|
type SelectizeShinyOptions = SelectizeOptions & {
|
||||||
|
shinyRemoveButton?: "none" | "true" | "false" | "both";
|
||||||
};
|
};
|
||||||
|
|
||||||
function getLabelNode(el: SelectHTMLElement): JQuery<HTMLElement> {
|
function getLabelNode(el: SelectHTMLElement): JQuery<HTMLElement> {
|
||||||
@@ -244,13 +258,7 @@ class SelectInputBinding extends InputBinding {
|
|||||||
|
|
||||||
if (config.length === 0) return undefined;
|
if (config.length === 0) return undefined;
|
||||||
|
|
||||||
let options: SelectizeOptions & {
|
let options: SelectizeShinyOptions = $.extend(
|
||||||
labelField: "label";
|
|
||||||
valueField: "value";
|
|
||||||
searchField: ["label"];
|
|
||||||
onItemRemove?: (value: string) => void;
|
|
||||||
onDropdownClose?: () => void;
|
|
||||||
} = $.extend(
|
|
||||||
{
|
{
|
||||||
labelField: "label",
|
labelField: "label",
|
||||||
valueField: "value",
|
valueField: "value",
|
||||||
@@ -259,6 +267,8 @@ class SelectInputBinding extends InputBinding {
|
|||||||
JSON.parse(config.html()),
|
JSON.parse(config.html()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
options = this._addShinyRemoveButton(options, el.hasAttribute("multiple"));
|
||||||
|
|
||||||
// selectize created from selectInput()
|
// selectize created from selectInput()
|
||||||
if (typeof config.data("nonempty") !== "undefined") {
|
if (typeof config.data("nonempty") !== "undefined") {
|
||||||
el.nonempty = true;
|
el.nonempty = true;
|
||||||
@@ -305,6 +315,44 @@ class SelectInputBinding extends InputBinding {
|
|||||||
|
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate shinyRemoveButton option into selectize plugins
|
||||||
|
private _addShinyRemoveButton(
|
||||||
|
options: SelectizeShinyOptions,
|
||||||
|
multiple: boolean,
|
||||||
|
): SelectizeOptions {
|
||||||
|
let removeButton = options.shinyRemoveButton;
|
||||||
|
if (removeButton === undefined) {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
// None really means 'smart default'
|
||||||
|
if (removeButton === "none") {
|
||||||
|
removeButton = multiple ? "true" : "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeButton === "false") {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
const plugins = [];
|
||||||
|
if (removeButton === "both") {
|
||||||
|
plugins.push("remove_button", "clear_button");
|
||||||
|
} else if (removeButton === "true") {
|
||||||
|
plugins.push(multiple ? "remove_button" : "clear_button");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add plugins to existing plugins if not already present
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
plugins: Array.from(
|
||||||
|
new Set([
|
||||||
|
...(Array.isArray(options.plugins) ? options.plugins : []),
|
||||||
|
...plugins,
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { SelectInputBinding };
|
export { SelectInputBinding };
|
||||||
|
|||||||
@@ -9,9 +9,8 @@ type SelectInputReceiveMessageData = {
|
|||||||
url?: string;
|
url?: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
};
|
};
|
||||||
type SelectizeOptions = Selectize.IOptions<string, unknown>;
|
|
||||||
type SelectizeInfo = Selectize.IApi<string, unknown> & {
|
type SelectizeInfo = Selectize.IApi<string, unknown> & {
|
||||||
settings: SelectizeOptions;
|
settings: Selectize.IOptions<string, unknown>;
|
||||||
};
|
};
|
||||||
declare class SelectInputBinding extends InputBinding {
|
declare class SelectInputBinding extends InputBinding {
|
||||||
find(scope: HTMLElement): JQuery<HTMLElement>;
|
find(scope: HTMLElement): JQuery<HTMLElement>;
|
||||||
@@ -32,6 +31,7 @@ declare class SelectInputBinding extends InputBinding {
|
|||||||
unsubscribe(el: HTMLElement): void;
|
unsubscribe(el: HTMLElement): void;
|
||||||
initialize(el: SelectHTMLElement): void;
|
initialize(el: SelectHTMLElement): void;
|
||||||
protected _selectize(el: SelectHTMLElement, update?: boolean): SelectizeInfo | undefined;
|
protected _selectize(el: SelectHTMLElement, update?: boolean): SelectizeInfo | undefined;
|
||||||
|
private _addShinyRemoveButton;
|
||||||
}
|
}
|
||||||
export { SelectInputBinding };
|
export { SelectInputBinding };
|
||||||
export type { SelectInputReceiveMessageData };
|
export type { SelectInputReceiveMessageData };
|
||||||
|
|||||||
Reference in New Issue
Block a user