diff --git a/NAMESPACE b/NAMESPACE index 2199b085..2122911d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -62,6 +62,7 @@ export(pickerGroupUI) export(pickerInput) export(pickerOptions) export(prepare_choices) +export(prepare_slim_choices) export(prettyCheckbox) export(prettyCheckboxGroup) export(prettyRadioButtons) @@ -85,6 +86,7 @@ export(showDropMenu) export(show_alert) export(show_toast) export(sliderTextInput) +export(slimSelectInput) export(spectrumInput) export(statiCard) export(switchInput) @@ -119,6 +121,7 @@ export(updateProgressBar) export(updateRadioGroupButtons) export(updateSearchInput) export(updateSliderTextInput) +export(updateSlimSelect) export(updateSpectrumInput) export(updateStatiCard) export(updateSwitchInput) diff --git a/R/slim-select.R b/R/slim-select.R new file mode 100644 index 00000000..3a07e39c --- /dev/null +++ b/R/slim-select.R @@ -0,0 +1,264 @@ + +#' @importFrom htmltools htmlDependency +html_dependency_slimselect <- function() { + htmlDependency( + name = "slim-select", + version = "2.8.2", + src = c(file = system.file("packer", package = "shinyWidgets")), + script = "slim-select.js", + all_files = FALSE + ) +} + + +#' Prepare choices for [slimSelectInput()] +#' +#' @param .data An object of type [data.frame()]. +#' @param label Variable to use as labels (displayed to user). +#' @param value Variable to use as values (retrieved server-side). +#' @param html Alternative HTML to be displayed instaed of label. +#' @param selected Is the option must be selected ? +#' @param display Allows to hide elements of selected values. +#' @param disabled Allows the ability to disable the select dropdown as well as individual options. +#' @param mandatory When using multi select you can set a mandatory on the option to prevent capability +#' to deselect particular option. Note options with mandatory flag is not selected by default, you need select them yourselfs. +#' @param class Add CSS classes. +#' @param style Add custom styles to options. +#' @param .by Variable identifying groups to use option group feature. +#' @param selectAll Enable select all feature for options groups. +#' @param closable Allow to close options groups, one of: 'off', 'open', 'close'. +#' +#' @return A `list` to use as `choices` argument of [slimSelectInput()]. +#' @export +#' +#' @example examples/prepare_slim_choices.R +prepare_slim_choices <- function(.data, + label, + value, + html = NULL, + selected = NULL, + display = NULL, + disabled = NULL, + mandatory = NULL, + class = NULL, + style = NULL, + .by = NULL, + selectAll = NULL, + closable = NULL) { + args <- lapply( + X = enexprs( + text = label, + value = value, + html = html, + selected = selected, + display = display, + disabled = disabled, + mandatory = mandatory, + class = class, + style = style, + .by = .by, + selectAll = selectAll, + closable = closable + ), + FUN = eval_tidy, + data = as.data.frame(.data) + ) + args <- dropNulls(args) + if (!is.null(args$selectAll)) + args$selectAll <- rep_len(args$selectAll, length.out = nrow(.data)) + if (!is.null(args$closable)) + args$closable <- rep_len(args$closable, length.out = nrow(.data)) + if (!is_null(args$.by)) { + groups <- args$.by + args$.by <- NULL + args <- lapply( + X = unique(groups), + FUN = function(group) { + selectAll <- args$selectAll[groups == group][1] + args$selectAll <- NULL + closable <- args$closable[groups == group][1] + args$closable <- NULL + options <- lapply(args, `[`, groups == group) + dropNulls(list( + label = group, + selectAll = selectAll, + closable = closable, + options = lapply( + X = seq_along(options[[1]]), + FUN = function(i) { + lapply(options, `[`, i) + } + ) + )) + } + ) + } else { + args$selectAll <- NULL + args$closable <- NULL + args <- lapply( + X = seq_along(args[[1]]), + FUN = function(i) { + lapply(args, `[`, i) + } + ) + } + I(args) +} + + +#' @title Slim Select Input +#' +#' @description An advanced select dropdown, +#' based on [slim-select](https://github.com/brianvoe/slim-select) JavaScript library. +#' +#' @param choices List of values to select from. +#' You can use: +#' * `vector` a simple vector. +#' * `named list` / `named vector` in the same way as with [shiny::selectInput()] +#' * cuxtom choices prepared with [prepare_slim_choices()]. +#' @inheritParams shiny::selectInput +#' @param search Enable search feature. +#' @param placeholder Placeholder text. +#' @param allowDeselect This will allow you to deselect a value on a single/multiple select dropdown. +#' @param closeOnSelect A boolean value in which determines whether or not to close the content area upon selecting a value. +#' @param keepOrder If `TRUE` will maintain the order in which options are selected. +#' @param alwaysOpen If `TRUE` keep the select open at all times. +#' @param contentPosition Will set the css position to either relative or absolute. +#' @param ... Other settings passed to Slim Select JAvaScript method. +#' @param inline Display the widget inline. +#' +#' @return A `shiny.tag` object that can be used in a UI definition. +#' @export +#' +#' @example inst/examples/slim-select/basic/app.R +slimSelectInput <- function(inputId, + label, + choices, + selected = NULL, + multiple = FALSE, + search = TRUE, + placeholder = NULL, + allowDeselect = NULL, + closeOnSelect = !multiple, + keepOrder = NULL, + alwaysOpen = NULL, + contentPosition = NULL, + ..., + inline = FALSE, + width = NULL) { + selected <- restoreInput(id = inputId, default = selected) + data <- dropNulls(list( + data = if (inherits(choices, "AsIs")) { + if (!isTRUE(multiple) & isTRUE(allowDeselect)) { + c(list(list(placeholder = TRUE, text = placeholder, value = NULL)), list(as.list(choices))) + } else { + as.list(choices) + } + } else { + if (!isTRUE(multiple) & isTRUE(allowDeselect)) { + c(list(list(placeholder = TRUE, text = placeholder, value = NULL)), make_slim_data(choicesWithNames(choices))) + } else { + make_slim_data(choicesWithNames(choices)) + } + }, + selected = selected, + settings = dropNulls(list( + showSearch = search, + placeholderText = placeholder, + allowDeselect = allowDeselect, + closeOnSelect = closeOnSelect, + keepOrder = keepOrder, + alwaysOpen = alwaysOpen, + contentPosition = contentPosition, + ... + )) + )) + tag_select <- tags$select( + id = inputId, + class = "slim-select", + tags$script( + type = "application/json", + `data-for` = inputId, + toJSON(data, auto_unbox = TRUE, json_verbatim = TRUE) + ) + ) + if (multiple) + tag_select$attribs$multiple <- "multiple" + tags$div( + class = "form-group shiny-input-container", + class = if (isTRUE(inline)) "shiny-input-container-inline", + style = css(width = validateCssUnit(width), height = "auto"), + label_input(inputId, label), + tag_select, + tags$div(id = paste0(inputId, "-placeholder"), style = css(height = "auto")), + html_dependency_slimselect() + ) +} + + +make_slim_data <- function(choices) { + lapply( + X = seq_along(choices), + FUN = function(i) { + label <- names(choices)[i] + choice <- choices[[i]] + if (is.list(choice)) { + list( + label = label, + options = make_slim_data(choice) + ) + } else { + list(text = label, value = choice) + } + } + ) +} + + + +#' @title Update slim select from server +#' +#' @description +#' Update a [slimSelectInput()] from the server. +#' +#' +#' @inheritParams slimSelectInput +#' @inheritParams shiny::updateSelectInput +#' @param disable Disable (`TRUE`) or enable (`FALSE`) the select menu. +#' @param open Open (`TRUE`) or close (`FALSE`) the dropdown. +#' +#' @return No value. +#' +#' @seealso [slimSelectInput()] for creating a widget in the UI. +#' +#' @export +#' +#' @importFrom shiny getDefaultReactiveDomain +#' @importFrom htmltools doRenderTags +#' +#' @example inst/examples/slim-select/update/app.R +updateSlimSelect <- function(inputId, + label = NULL, + choices = NULL, + selected = NULL, + disable = NULL, + open = NULL, + session = shiny::getDefaultReactiveDomain()) { + if (!is.null(label)) + label <- doRenderTags(label) + data <- if (!is.null(choices)) { + if (inherits(choices, "AsIs")) { + as.list(choices) + } else { + make_slim_data(choicesWithNames(choices)) + } + } + message <- dropNulls(list( + label = label, + data = data, + selected = selected, + disable = disable, + open = open + )) + session$sendInputMessage(inputId, message) +} diff --git a/examples/prepare_slim_choices.R b/examples/prepare_slim_choices.R new file mode 100644 index 00000000..17a0cf0a --- /dev/null +++ b/examples/prepare_slim_choices.R @@ -0,0 +1,81 @@ + +library(shiny) +library(shinyWidgets) + +state_data <- data.frame( + name = state.name, + abb = state.abb, + region = state.region, + division = state.division +) + +ui <- fluidPage( + tags$h2("Slim Select examples"), + fluidRow( + column( + width = 3, + slimSelectInput( + inputId = "slim1", + label = "Disable some choices:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + disabled = division == "Mountain" + ), + width = "100%" + ), + verbatimTextOutput("res1") + ), + column( + width = 3, + slimSelectInput( + inputId = "slim2", + label = "Custom styles:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + style = ifelse( + division == "Mountain", + "color: blue;", + "color: red;" + ) + ), + multiple = TRUE, + placeholder = "Select a state", + width = "100%" + ), + verbatimTextOutput("res2") + ), + column( + width = 3, + slimSelectInput( + inputId = "slim3", + label = "Options groups with options:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + .by = region, + selectAll = TRUE, + closable = "close" + ), + multiple = TRUE, + width = "100%" + ), + verbatimTextOutput("res3") + ) + ) +) + +server <- function(input, output, session) { + output$res1 <- renderPrint(input$slim1) + + output$res2 <- renderPrint(input$slim2) + + output$res3 <- renderPrint(input$slim3) +} + +if (interactive()) + shinyApp(ui, server) diff --git a/inst/examples/slim-select/basic/app.R b/inst/examples/slim-select/basic/app.R new file mode 100644 index 00000000..5c11b656 --- /dev/null +++ b/inst/examples/slim-select/basic/app.R @@ -0,0 +1,114 @@ + +library(shiny) +library(shinyWidgets) +library(htmltools) + +state_data <- data.frame( + name = state.name, + abb = state.abb, + region = state.region, + division = state.division +) + +ui <- fluidPage( + tags$h2("Slim Select examples"), + fluidRow( + column( + width = 4, + + slimSelectInput( + inputId = "slim1", + label = "Single slim select:", + choices = month.name, + width = "100%" + ), + verbatimTextOutput("res1"), + + slimSelectInput( + inputId = "slim4", + label = "Allow deselect in single select:", + choices = month.name, + placeholder = "Select something:", + allowDeselect = TRUE, + width = "100%" + ), + verbatimTextOutput("res4") + + ), + column( + width = 4, + + slimSelectInput( + inputId = "slim2", + label = "Multiple slim select:", + choices = month.name, + multiple = TRUE, + placeholder = "Select a month", + width = "100%" + ), + verbatimTextOutput("res2"), + + slimSelectInput( + inputId = "slim5", + label = "Keep order:", + choices = month.name, + multiple = TRUE, + keepOrder = TRUE, + width = "100%" + ), + verbatimTextOutput("res5") + + ), + column( + width = 4, + + slimSelectInput( + inputId = "slim3", + label = "Use prepare_slim_choices:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + .by = region, + selectAll = TRUE, + closable = "close" + ), + multiple = TRUE, + width = "100%" + ), + verbatimTextOutput("res3"), + + slimSelectInput( + inputId = "slim6", + label = "Always open:", + choices = month.name, + multiple = TRUE, + alwaysOpen = TRUE, + # contentPosition = "relative", + # contentLocation = "slim6-placeholder", + width = "100%" + ) |> htmltools::tagAppendAttributes(style = css(height = "350px")), + verbatimTextOutput("res6") + + ) + ) +) + +server <- function(input, output, session) { + + output$res1 <- renderPrint(input$slim1) + + output$res2 <- renderPrint(input$slim2) + + output$res3 <- renderPrint(input$slim3) + + output$res4 <- renderPrint(input$slim4) + + output$res5 <- renderPrint(input$slim5) + + output$res6 <- renderPrint(input$slim6) + +} + +if (interactive()) + shinyApp(ui, server) diff --git a/inst/examples/slim-select/update/app.R b/inst/examples/slim-select/update/app.R new file mode 100644 index 00000000..a68fbfdf --- /dev/null +++ b/inst/examples/slim-select/update/app.R @@ -0,0 +1,109 @@ +library(shiny) +library(shinyWidgets) + +ui <- fluidPage( + tags$h2("Slim Select (update)"), + + slimSelectInput( + inputId = "sel1", + label = "Update label:", + choices = month.name + ), + verbatimTextOutput("res1"), + textInput("label_text", label = "With text:"), + textInput("label_html", label = "With HTML:"), + + slimSelectInput( + inputId = "sel2", + label = "Update selected value:", + choices = month.name + ), + verbatimTextOutput("res2"), + radioButtons("selected", "Selected value:", month.name, inline = TRUE), + + slimSelectInput( + inputId = "sel3", + label = "Update choices:", + choices = tolower(month.name) + ), + verbatimTextOutput("res3"), + radioButtons("choices", "Choices:", c("lowercase", "UPPERCASE"), inline = TRUE), + + slimSelectInput( + inputId = "sel4", + label = "Update choices + selected:", + choices = tolower(month.name) + ), + verbatimTextOutput("res4"), + radioButtons("choices_select", "Choices:", c("lowercase", "UPPERCASE"), inline = TRUE), + + slimSelectInput( + inputId = "sel5", + label = "Disable / enable:", + choices = tolower(month.name) + ), + verbatimTextOutput("res5"), + checkboxInput("disable", "Disable", value = FALSE), + + slimSelectInput( + inputId = "sel6", + label = "Open / close:", + choices = tolower(month.name) + ), + verbatimTextOutput("res6"), + checkboxInput("open", "Open?", value = FALSE) + +) + +server <- function(input, output, session) { + output$res1 <- renderPrint(input$sel1) + observe({ + req(input$label_text) + updateSlimSelect(inputId = "sel1", label = input$label_text) + }) + observe({ + req(input$label_html) + updateSlimSelect( + inputId = "sel1", + label = tags$span(input$label_html, style = "color: red;") + ) + }) + + output$res2 <- renderPrint(input$sel2) + observe({ + updateSlimSelect(inputId = "sel2", selected = input$selected) + }) + + output$res3 <- renderPrint(input$sel3) + observe({ + if (identical(input$choices, "lowercase")) { + updateSlimSelect(inputId = "sel3", choices = tolower(month.name)) + } else { + updateSlimSelect(inputId = "sel3", choices = toupper(month.name)) + } + }) + + output$res4 <- renderPrint(input$sel4) + observe({ + if (identical(input$choices_select, "lowercase")) { + choices <- tolower(month.name) + } else { + choices <- toupper(month.name) + } + selected <- sample(choices, 1) + updateSlimSelect(inputId = "sel4", choices = choices, selected = selected) + }) + + output$res5 <- renderPrint(input$sel5) + observe({ + updateSlimSelect(inputId = "sel5", disable = isTRUE(input$disable)) + }) + + observeEvent(input$open, { + updateSlimSelect(inputId = "sel6", open = input$open) + }, ignoreInit = TRUE) + +} + +if (interactive()) + shinyApp(ui, server) diff --git a/inst/packer/slim-select.js b/inst/packer/slim-select.js new file mode 100644 index 00000000..006bb246 --- /dev/null +++ b/inst/packer/slim-select.js @@ -0,0 +1 @@ +(()=>{var e={7647:(e,t,s)=>{"use strict";s.d(t,{Z:()=>l});var i=s(8081),n=s.n(i),a=s(3645),o=s.n(a)()(n());o.push([e.id,":root{--ss-primary-color: #5897fb;--ss-bg-color: #ffffff;--ss-font-color: #4d4d4d;--ss-font-placeholder-color: #8d8d8d;--ss-disabled-color: #dcdee2;--ss-border-color: #dcdee2;--ss-highlight-color: #fffb8c;--ss-success-color: #00b755;--ss-error-color: #dc3545;--ss-focus-color: #5897fb;--ss-main-height: 30px;--ss-content-height: 300px;--ss-spacing-l: 7px;--ss-spacing-m: 5px;--ss-spacing-s: 3px;--ss-animation-timing: 0.2s;--ss-border-radius: 4px}@keyframes ss-valueIn{0%{transform:scale(0);opacity:0}100%{transform:scale(1);opacity:1}}@keyframes ss-valueOut{0%{transform:scale(1);opacity:1}100%{transform:scale(0);opacity:0}}.ss-hide{display:none !important}.ss-main{display:flex;flex-direction:row;position:relative;user-select:none;color:var(--ss-font-color);min-height:var(--ss-main-height);width:100%;padding:var(--ss-spacing-s);cursor:pointer;border:1px solid var(--ss-border-color);border-radius:var(--ss-border-radius);background-color:var(--ss-bg-color);outline:0;box-sizing:border-box;transition:background-color var(--ss-animation-timing);overflow:hidden}.ss-main:focus{box-shadow:0 0 5px var(--ss-focus-color)}.ss-main.ss-disabled{background-color:var(--ss-disabled-color);cursor:not-allowed}.ss-main.ss-disabled .ss-values .ss-disabled{color:var(--ss-font-color)}.ss-main.ss-disabled .ss-values .ss-value .ss-value-delete{cursor:not-allowed}.ss-main.ss-open-above{border-top-left-radius:0px;border-top-right-radius:0px}.ss-main.ss-open-below{border-bottom-left-radius:0px;border-bottom-right-radius:0px}.ss-main .ss-values{display:inline-flex;flex-wrap:wrap;gap:var(--ss-spacing-m);flex:1 1 100%}.ss-main .ss-values .ss-placeholder{display:flex;padding:var(--ss-spacing-s) var(--ss-spacing-m) var(--ss-spacing-s) var(--ss-spacing-m);margin:auto 0px auto 0px;line-height:1em;align-items:center;width:100%;color:var(--ss-font-placeholder-color);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ss-main .ss-values .ss-max{display:flex;user-select:none;align-items:center;width:fit-content;font-size:12px;color:var(--ss-bg-color);line-height:1;padding:var(--ss-spacing-s) var(--ss-spacing-m);background-color:var(--ss-primary-color);border-radius:var(--ss-border-radius)}.ss-main .ss-values .ss-single{display:flex;margin:auto 0px auto var(--ss-spacing-s)}.ss-main .ss-values .ss-value{display:flex;user-select:none;align-items:center;width:fit-content;background-color:var(--ss-primary-color);border-radius:var(--ss-border-radius);animation-name:ss-valueIn;animation-duration:var(--ss-animation-timing);animation-timing-function:ease-out;animation-fill-mode:both}.ss-main .ss-values .ss-value.ss-value-out{animation-name:ss-valueOut;animation-duration:var(--ss-animation-timing);animation-timing-function:ease-out}.ss-main .ss-values .ss-value .ss-value-text{font-size:12px;color:var(--ss-bg-color);line-height:1;padding:var(--ss-spacing-s) var(--ss-spacing-m)}.ss-main .ss-values .ss-value .ss-value-delete{display:flex;align-items:center;height:var(--ss-spacing-l);width:var(--ss-spacing-l);padding:var(--ss-spacing-s) var(--ss-spacing-m);cursor:pointer;border-left:solid 1px var(--ss-bg-color);box-sizing:content-box}.ss-main .ss-values .ss-value .ss-value-delete svg{height:var(--ss-spacing-l);width:var(--ss-spacing-l)}.ss-main .ss-values .ss-value .ss-value-delete svg path{fill:none;stroke:var(--ss-bg-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round}.ss-main .ss-deselect{flex:0 1 auto;display:flex;align-items:center;justify-content:center;width:fit-content;height:auto;padding:0 var(--ss-spacing-m) 0 var(--ss-spacing-m)}.ss-main .ss-deselect svg{width:8px;height:8px}.ss-main .ss-deselect svg path{fill:none;stroke:var(--ss-font-color);stroke-width:20;stroke-linecap:round;stroke-linejoin:round}.ss-main .ss-arrow{flex:0 1 auto;display:flex;align-items:center;justify-content:flex-end;width:12px;height:12px;margin:auto var(--ss-spacing-m) auto var(--ss-spacing-m)}.ss-main .ss-arrow path{fill:none;stroke:var(--ss-font-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round;transition-timing-function:ease-out;transition:var(--ss-animation-timing)}.ss-content{position:absolute;display:flex;height:auto;flex-direction:column;width:auto;max-height:var(--ss-content-height);box-sizing:border-box;border:solid 1px var(--ss-border-color);background-color:var(--ss-bg-color);transition:transform var(--ss-animation-timing),opacity var(--ss-animation-timing);opacity:0;transform:scaleY(0);transform-origin:center top;overflow:hidden;z-index:10000}.ss-content.ss-relative{position:relative;height:100%}.ss-content.ss-open-above{flex-direction:column-reverse;opacity:1;transform:scaleY(1);transform-origin:center bottom;border-top-left-radius:var(--ss-border-radius);border-top-right-radius:var(--ss-border-radius)}.ss-content.ss-open-below{opacity:1;transform:scaleY(1);transform-origin:center top;border-bottom-left-radius:var(--ss-border-radius);border-bottom-right-radius:var(--ss-border-radius)}.ss-content .ss-search{flex:0 1 auto;display:flex;flex-direction:row;padding:var(--ss-spacing-l) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l)}.ss-content .ss-search input{display:inline-flex;font-size:inherit;line-height:inherit;flex:1 1 auto;width:100%;min-width:0px;padding:var(--ss-spacing-m) var(--ss-spacing-l);margin:0;border:1px solid var(--ss-border-color);border-radius:var(--ss-border-radius);background-color:var(--ss-bg-color);outline:0;text-align:left;box-sizing:border-box}.ss-content .ss-search input::placeholder{color:var(--ss-font-placeholder-color);vertical-align:middle}.ss-content .ss-search input:focus{box-shadow:0 0 5px var(--ss-focus-color)}.ss-content .ss-search .ss-addable{display:inline-flex;justify-content:center;align-items:center;cursor:pointer;flex:0 0 auto;height:auto;margin:0 0 0 var(--ss-spacing-m);border:1px solid var(--ss-border-color);border-radius:var(--ss-border-radius)}.ss-content .ss-search .ss-addable svg{display:flex;align-items:center;justify-content:flex-end;flex:0 1 auto;width:12px;height:12px;margin:auto var(--ss-spacing-m) auto var(--ss-spacing-m)}.ss-content .ss-search .ss-addable svg path{fill:none;stroke:var(--ss-font-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round}.ss-content .ss-list{flex:1 1 auto;height:auto;overflow-x:hidden;overflow-y:auto}.ss-content .ss-list .ss-error{color:var(--ss-error-color);padding:var(--ss-spacing-l)}.ss-content .ss-list .ss-searching{color:var(--ss-font-color);padding:var(--ss-spacing-l)}.ss-content .ss-list .ss-optgroup.ss-close .ss-option{display:none !important}.ss-content .ss-list .ss-optgroup .ss-optgroup-label{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:var(--ss-spacing-m) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-label-text{flex:1 1 auto;font-weight:bold;color:var(--ss-font-color)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label:has(.ss-arrow){cursor:pointer}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions{flex:0 1 auto;display:flex;flex-direction:row;align-items:center;justify-content:center;gap:var(--ss-spacing-m)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall{flex:0 0 auto;display:flex;flex-direction:row;cursor:pointer}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall:hover{opacity:.5}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall.ss-selected svg path{stroke:var(--ss-error-color)}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall span{flex:0 1 auto;display:flex;align-items:center;justify-content:center;font-size:60%;text-align:center;padding:0 var(--ss-spacing-s) 0 0}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg{flex:0 1 auto;width:13px;height:13px}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg path{fill:none;stroke:var(--ss-success-color);stroke-linecap:round;stroke-linejoin:round}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg:first-child{stroke-width:5}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-selectall svg:last-child{stroke-width:11}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-closable{flex:0 1 auto;display:flex;flex-direction:row;cursor:pointer}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-closable .ss-arrow{flex:1 1 auto;width:10px;height:10px}.ss-content .ss-list .ss-optgroup .ss-optgroup-label .ss-optgroup-actions .ss-closable .ss-arrow path{fill:none;stroke:var(--ss-font-color);stroke-width:18;stroke-linecap:round;stroke-linejoin:round;transition-timing-function:ease-out;transition:var(--ss-animation-timing)}.ss-content .ss-list .ss-optgroup .ss-option{padding:var(--ss-spacing-s) var(--ss-spacing-s) var(--ss-spacing-s) calc(var(--ss-spacing-l)*3)}.ss-content .ss-list .ss-option{display:block;padding:var(--ss-spacing-m) var(--ss-spacing-l) var(--ss-spacing-m) var(--ss-spacing-l);white-space:normal;color:var(--ss-font-color);cursor:pointer;user-select:none}.ss-content .ss-list .ss-option:hover{color:var(--ss-bg-color);background-color:var(--ss-primary-color)}.ss-content .ss-list .ss-option.ss-highlighted,.ss-content .ss-list .ss-option:not(.ss-disabled).ss-selected{color:var(--ss-bg-color);background-color:var(--ss-primary-color)}.ss-content .ss-list .ss-option.ss-disabled{cursor:not-allowed;background-color:var(--ss-disabled-color)}.ss-content .ss-list .ss-option.ss-disabled:hover{color:var(--ss-font-color)}.ss-content .ss-list .ss-option .ss-search-highlight{display:inline-block;background-color:var(--ss-highlight-color)}\n",""]);const l=o},3645:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var s="",i=void 0!==t[5];return t[4]&&(s+="@supports (".concat(t[4],") {")),t[2]&&(s+="@media ".concat(t[2]," {")),i&&(s+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),s+=e(t),i&&(s+="}"),t[2]&&(s+="}"),t[4]&&(s+="}"),s})).join("")},t.i=function(e,s,i,n,a){"string"==typeof e&&(e=[[null,e,void 0]]);var o={};if(i)for(var l=0;l0?" ".concat(h[5]):""," {").concat(h[1],"}")),h[5]=a),s&&(h[2]?(h[1]="@media ".concat(h[2]," {").concat(h[1],"}"),h[2]=s):h[2]=s),n&&(h[4]?(h[1]="@supports (".concat(h[4],") {").concat(h[1],"}"),h[4]=n):h[4]="".concat(n)),t.push(h))}},t}},8081:e=>{"use strict";e.exports=function(e){return e[1]}},4487:function(e){e.exports=function(){"use strict";class e{constructor(e){e||(e={}),this.main=e.main||"ss-main",this.placeholder=e.placeholder||"ss-placeholder",this.values=e.values||"ss-values",this.single=e.single||"ss-single",this.max=e.max||"ss-max",this.value=e.value||"ss-value",this.valueText=e.valueText||"ss-value-text",this.valueDelete=e.valueDelete||"ss-value-delete",this.valueOut=e.valueOut||"ss-value-out",this.deselect=e.deselect||"ss-deselect",this.deselectPath=e.deselectPath||"M10,10 L90,90 M10,90 L90,10",this.arrow=e.arrow||"ss-arrow",this.arrowClose=e.arrowClose||"M10,30 L50,70 L90,30",this.arrowOpen=e.arrowOpen||"M10,70 L50,30 L90,70",this.content=e.content||"ss-content",this.openAbove=e.openAbove||"ss-open-above",this.openBelow=e.openBelow||"ss-open-below",this.search=e.search||"ss-search",this.searchHighlighter=e.searchHighlighter||"ss-search-highlight",this.searching=e.searching||"ss-searching",this.addable=e.addable||"ss-addable",this.addablePath=e.addablePath||"M50,10 L50,90 M10,50 L90,50",this.list=e.list||"ss-list",this.optgroup=e.optgroup||"ss-optgroup",this.optgroupLabel=e.optgroupLabel||"ss-optgroup-label",this.optgroupLabelText=e.optgroupLabelText||"ss-optgroup-label-text",this.optgroupActions=e.optgroupActions||"ss-optgroup-actions",this.optgroupSelectAll=e.optgroupSelectAll||"ss-selectall",this.optgroupSelectAllBox=e.optgroupSelectAllBox||"M60,10 L10,10 L10,90 L90,90 L90,50",this.optgroupSelectAllCheck=e.optgroupSelectAllCheck||"M30,45 L50,70 L90,10",this.optgroupClosable=e.optgroupClosable||"ss-closable",this.option=e.option||"ss-option",this.optionDelete=e.optionDelete||"M10,10 L90,90 M10,90 L90,10",this.highlighted=e.highlighted||"ss-highlighted",this.open=e.open||"ss-open",this.close=e.close||"ss-close",this.selected=e.selected||"ss-selected",this.error=e.error||"ss-error",this.disabled=e.disabled||"ss-disabled",this.hide=e.hide||"ss-hide"}}function t(){return Math.random().toString(36).substring(2,10)}function s(e,t=50,s=!1){let i;return function(...n){const a=self,o=s&&!i;clearTimeout(i),i=setTimeout((()=>{i=null,s||e.apply(a,n)}),t),o&&e.apply(a,n)}}function i(e,t){return JSON.stringify(e)===JSON.stringify(t)}class n{constructor(e){if(this.id=e.id&&""!==e.id?e.id:t(),this.label=e.label||"",this.selectAll=void 0!==e.selectAll&&e.selectAll,this.selectAllText=e.selectAllText||"Select All",this.closable=e.closable||"off",this.options=[],e.options)for(const t of e.options)this.options.push(new a(t))}}class a{constructor(e){this.id=e.id&&""!==e.id?e.id:t(),this.value=void 0===e.value?e.text:e.value,this.text=e.text||"",this.html=e.html||"",this.selected=void 0!==e.selected&&e.selected,this.display=void 0===e.display||e.display,this.disabled=void 0!==e.disabled&&e.disabled,this.mandatory=void 0!==e.mandatory&&e.mandatory,this.placeholder=void 0!==e.placeholder&&e.placeholder,this.class=e.class||"",this.style=e.style||"",this.data=e.data||{}}}class o{constructor(e,t){this.selectType="single",this.data=[],this.selectedOrder=[],this.selectType=e,this.setData(t)}validateDataArray(e){if(!Array.isArray(e))return new Error("Data must be an array");for(let t of e)if(t instanceof n||"label"in t){if(!("label"in t))return new Error("Optgroup must have a label");if("options"in t&&t.options)for(let e of t.options){const t=this.validateOption(e);if(t)return t}}else{if(!(t instanceof a||"text"in t))return new Error("Data object must be a valid optgroup or option");{const e=this.validateOption(t);if(e)return e}}return null}validateOption(e){return"text"in e?null:new Error("Option must have a text")}partialToFullData(e){let t=[];return e.forEach((e=>{if(e instanceof n||"label"in e){let s=[];"options"in e&&e.options&&e.options.forEach((e=>{s.push(new a(e))})),s.length>0&&t.push(new n(e))}(e instanceof a||"text"in e)&&t.push(new a(e))})),t}setData(e){this.data=this.partialToFullData(e),"single"===this.selectType&&this.setSelectedBy("id",this.getSelected())}getData(){return this.filter(null,!0)}getDataOptions(){return this.filter(null,!1)}addOption(e,t=!1){if(t){let t=[new a(e)];this.setData(t.concat(this.getData()))}else this.setData(this.getData().concat(new a(e)))}setSelectedBy(e,t){let s=null,i=!1;const o=[];for(let l of this.data){if(l instanceof n)for(let n of l.options)s||(s=n),n.selected=!i&&t.includes(n[e]),n.selected&&(o.push(n),"single"===this.selectType&&(i=!0));l instanceof a&&(s||(s=l),l.selected=!i&&t.includes(l[e]),l.selected&&(o.push(l),"single"===this.selectType&&(i=!0)))}"single"===this.selectType&&s&&!i&&(s.selected=!0,o.push(s));const l=t.map((t=>{var s;return(null===(s=o.find((s=>s[e]===t)))||void 0===s?void 0:s.id)||""}));this.selectedOrder=l}getSelected(){return this.getSelectedOptions().map((e=>e.id))}getSelectedValues(){return this.getSelectedOptions().map((e=>e.value))}getSelectedOptions(){return this.filter((e=>e.selected),!1)}getOptgroupByID(e){for(let t of this.data)if(t instanceof n&&t.id===e)return t;return null}getOptionByID(e){let t=this.filter((t=>t.id===e),!1);return t.length?t[0]:null}getSelectType(){return this.selectType}getFirstOption(){let e=null;for(let t of this.data)if(t instanceof n?e=t.options[0]:t instanceof a&&(e=t),e)break;return e}search(e,t){return""===(e=e.trim())?this.getData():this.filter((s=>t(s,e)),!0)}filter(e,t){const s=[];return this.data.forEach((i=>{if(i instanceof n){let o=[];if(i.options.forEach((i=>{e&&!e(i)||(t?o.push(new a(i)):s.push(new a(i)))})),o.length>0){let e=new n(i);e.options=o,s.push(e)}}i instanceof a&&(e&&!e(i)||s.push(new a(i)))})),s}selectedOrderOptions(e){const t=[];return this.selectedOrder.forEach((s=>{const i=e.find((e=>e.id===s));i&&t.push(i)})),e.forEach((e=>{let s=!1;t.forEach((t=>{e.id!==t.id||(s=!0)})),s||t.push(e)})),t}}class l{constructor(e,t,s,i){this.store=s,this.settings=e,this.classes=t,this.callbacks=i,this.main=this.mainDiv(),this.content=this.contentDiv(),this.updateClassStyles(),this.updateAriaAttributes(),this.settings.contentLocation.appendChild(this.content.main)}enable(){this.main.main.classList.remove(this.classes.disabled),this.content.search.input.disabled=!1}disable(){this.main.main.classList.add(this.classes.disabled),this.content.search.input.disabled=!0}open(){this.main.arrow.path.setAttribute("d",this.classes.arrowOpen),this.main.main.classList.add("up"===this.settings.openPosition?this.classes.openAbove:this.classes.openBelow),this.main.main.setAttribute("aria-expanded","true"),this.moveContent();const e=this.store.getSelectedOptions();if(e.length){const t=e[e.length-1].id,s=this.content.list.querySelector('[data-id="'+t+'"]');s&&this.ensureElementInView(this.content.list,s)}}close(){this.main.main.classList.remove(this.classes.openAbove),this.main.main.classList.remove(this.classes.openBelow),this.main.main.setAttribute("aria-expanded","false"),this.content.main.classList.remove(this.classes.openAbove),this.content.main.classList.remove(this.classes.openBelow),this.main.arrow.path.setAttribute("d",this.classes.arrowClose)}updateClassStyles(){if(this.main.main.className="",this.main.main.removeAttribute("style"),this.content.main.className="",this.content.main.removeAttribute("style"),this.main.main.classList.add(this.classes.main),this.content.main.classList.add(this.classes.content),""!==this.settings.style&&(this.main.main.style.cssText=this.settings.style,this.content.main.style.cssText=this.settings.style),this.settings.class.length)for(const e of this.settings.class)""!==e.trim()&&(this.main.main.classList.add(e.trim()),this.content.main.classList.add(e.trim()));"relative"===this.settings.contentPosition&&this.content.main.classList.add("ss-"+this.settings.contentPosition)}updateAriaAttributes(){this.main.main.role="combobox",this.main.main.setAttribute("aria-haspopup","listbox"),this.main.main.setAttribute("aria-controls",this.content.main.id),this.main.main.setAttribute("aria-expanded","false"),this.content.main.setAttribute("role","listbox")}mainDiv(){var e;const t=document.createElement("div");t.dataset.id=this.settings.id,t.setAttribute("aria-label",this.settings.ariaLabel),t.tabIndex=0,t.onkeydown=e=>{switch(e.key){case"ArrowUp":case"ArrowDown":return this.callbacks.open(),"ArrowDown"===e.key?this.highlight("down"):this.highlight("up"),!1;case"Tab":return this.callbacks.close(),!0;case"Enter":case" ":this.callbacks.open();const t=this.content.list.querySelector("."+this.classes.highlighted);return t&&t.click(),!1;case"Escape":return this.callbacks.close(),!1}return!0},t.onclick=e=>{this.settings.disabled||(this.settings.isOpen?this.callbacks.close():this.callbacks.open())};const s=document.createElement("div");s.classList.add(this.classes.values),t.appendChild(s);const i=document.createElement("div");i.classList.add(this.classes.deselect);const n=null===(e=this.store)||void 0===e?void 0:e.getSelectedOptions();!this.settings.allowDeselect||this.settings.isMultiple&&n&&n.length<=0?i.classList.add(this.classes.hide):i.classList.remove(this.classes.hide),i.onclick=e=>{if(e.stopPropagation(),this.settings.disabled)return;let t=!0;const s=this.store.getSelectedOptions();if(this.callbacks.beforeChange&&(t=!0===this.callbacks.beforeChange([],s)),t){if(this.settings.isMultiple)this.callbacks.setSelected([],!1),this.updateDeselectAll();else{const e=this.store.getFirstOption(),t=e?e.id:"";this.callbacks.setSelected(t,!1)}this.settings.closeOnSelect&&this.callbacks.close(),this.callbacks.afterChange&&this.callbacks.afterChange(this.store.getSelectedOptions())}};const a=document.createElementNS("http://www.w3.org/2000/svg","svg");a.setAttribute("viewBox","0 0 100 100");const o=document.createElementNS("http://www.w3.org/2000/svg","path");o.setAttribute("d",this.classes.deselectPath),a.appendChild(o),i.appendChild(a),t.appendChild(i);const l=document.createElementNS("http://www.w3.org/2000/svg","svg");l.classList.add(this.classes.arrow),l.setAttribute("viewBox","0 0 100 100");const r=document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d",this.classes.arrowClose),this.settings.alwaysOpen&&l.classList.add(this.classes.hide),l.appendChild(r),t.appendChild(l),{main:t,values:s,deselect:{main:i,svg:a,path:o},arrow:{main:l,path:r}}}mainFocus(e){"click"!==e&&this.main.main.focus({preventScroll:!0})}placeholder(){const e=this.store.filter((e=>e.placeholder),!1);let t=this.settings.placeholderText;e.length&&(""!==e[0].html?t=e[0].html:""!==e[0].text&&(t=e[0].text));const s=document.createElement("div");return s.classList.add(this.classes.placeholder),s.innerHTML=t,s}renderValues(){this.settings.isMultiple?(this.renderMultipleValues(),this.updateDeselectAll()):this.renderSingleValue()}renderSingleValue(){const e=this.store.filter((e=>e.selected&&!e.placeholder),!1),t=e.length>0?e[0]:null;if(t){const e=document.createElement("div");e.classList.add(this.classes.single),t.html?e.innerHTML=t.html:e.innerText=t.text,this.main.values.innerHTML=e.outerHTML}else this.main.values.innerHTML=this.placeholder().outerHTML;this.settings.allowDeselect&&e.length?this.main.deselect.main.classList.remove(this.classes.hide):this.main.deselect.main.classList.add(this.classes.hide)}renderMultipleValues(){let e=this.main.values.childNodes,t=this.store.filter((e=>e.selected&&e.display),!1);if(0===t.length)return void(this.main.values.innerHTML=this.placeholder().outerHTML);{const e=this.main.values.querySelector("."+this.classes.placeholder);e&&e.remove()}if(t.length>this.settings.maxValuesShown){const e=document.createElement("div");return e.classList.add(this.classes.max),e.textContent=this.settings.maxValuesMessage.replace("{number}",t.length.toString()),void(this.main.values.innerHTML=e.outerHTML)}{const e=this.main.values.querySelector("."+this.classes.max);e&&e.remove()}this.settings.keepOrder&&(t=this.store.selectedOrderOptions(t));let s=[];for(let i=0;ie.id===a),!1).length||s.push(n))}for(const e of s)e.classList.add(this.classes.valueOut),setTimeout((()=>{this.main.values.hasChildNodes()&&this.main.values.contains(e)&&this.main.values.removeChild(e)}),100);e=this.main.values.childNodes;for(let s=0;s{if(t.preventDefault(),t.stopPropagation(),this.settings.disabled)return;let s=!0;const i=this.store.getSelectedOptions(),o=i.filter((t=>t.selected&&t.id!==e.id),!0);if(!(this.settings.minSelected&&o.length{this.callbacks.search(e.target.value)}),100),t.onkeydown=e=>{switch(e.key){case"ArrowUp":case"ArrowDown":return"ArrowDown"===e.key?this.highlight("down"):this.highlight("up"),!1;case"Tab":return this.callbacks.close(),!0;case"Escape":return this.callbacks.close(),!1;case" ":const t=this.content.list.querySelector("."+this.classes.highlighted);return!t||(t.click(),!1);case"Enter":if(this.callbacks.addable)return i.click(),!1;{const e=this.content.list.querySelector("."+this.classes.highlighted);if(e)return e.click(),!1}return!0}return!0},e.appendChild(t),this.callbacks.addable){i.classList.add(this.classes.addable);const t=document.createElementNS("http://www.w3.org/2000/svg","svg");t.setAttribute("viewBox","0 0 100 100");const s=document.createElementNS("http://www.w3.org/2000/svg","path");s.setAttribute("d",this.classes.addablePath),t.appendChild(s),i.appendChild(t),i.onclick=e=>{if(e.preventDefault(),e.stopPropagation(),!this.callbacks.addable)return;const t=this.content.search.input.value.trim();if(""===t)return void this.content.search.input.focus();const s=e=>{let t=new a(e);if(this.callbacks.addOption(t),this.settings.isMultiple){let e=this.store.getSelected();e.push(t.id),this.callbacks.setSelected(e,!0)}else this.callbacks.setSelected([t.id],!0);this.callbacks.search(""),this.settings.closeOnSelect&&setTimeout((()=>{this.callbacks.close()}),100)},i=this.callbacks.addable(t);!1!==i&&null!=i&&(i instanceof Promise?i.then((e=>{"string"==typeof e?s({text:e,value:e}):i instanceof Error?this.renderError(i.message):s(e)})):"string"==typeof i?s({text:i,value:i}):i instanceof Error?this.renderError(i.message):s(i))},e.appendChild(i),n.addable={main:i,svg:t,path:s}}return n}searchFocus(){this.content.search.input.focus()}getOptions(e=!1,t=!1,s=!1){let i="."+this.classes.option;return e&&(i+=":not(."+this.classes.placeholder+")"),t&&(i+=":not(."+this.classes.disabled+")"),s&&(i+=":not(."+this.classes.hide+")"),Array.from(this.content.list.querySelectorAll(i))}highlight(e){const t=this.getOptions(!0,!0,!0);if(0===t.length)return;if(1===t.length&&!t[0].classList.contains(this.classes.highlighted))return void t[0].classList.add(this.classes.highlighted);let s=!1;for(const e of t)e.classList.contains(this.classes.highlighted)&&(s=!0);if(!s)for(const e of t)if(e.classList.contains(this.classes.selected)){e.classList.add(this.classes.highlighted);break}for(let s=0;s=0?s-1:t.length-1];a.classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,a);const o=a.parentElement;if(o&&o.classList.contains(this.classes.close)){const e=o.querySelector("."+this.classes.optgroupLabel);e&&e.click()}return}t["down"===e?0:t.length-1].classList.add(this.classes.highlighted),this.ensureElementInView(this.content.list,t["down"===e?0:t.length-1])}listDiv(){const e=document.createElement("div");return e.classList.add(this.classes.list),e}renderError(e){this.content.list.innerHTML="";const t=document.createElement("div");t.classList.add(this.classes.error),t.textContent=e,this.content.list.appendChild(t)}renderSearching(){this.content.list.innerHTML="";const e=document.createElement("div");e.classList.add(this.classes.searching),e.textContent=this.settings.searchingText,this.content.list.appendChild(e)}renderOptions(e){if(this.content.list.innerHTML="",0===e.length){const e=document.createElement("div");return e.classList.add(this.classes.search),this.callbacks.addable?e.innerHTML=this.settings.addableText.replace("{value}",this.content.search.input.value):e.innerHTML=this.settings.searchText,void this.content.list.appendChild(e)}this.settings.allowDeselect&&!this.settings.isMultiple&&(this.store.filter((e=>e.placeholder),!1).length||this.store.addOption(new a({text:"",value:"",selected:!1,placeholder:!0}),!0));for(const t of e){if(t instanceof n){const e=document.createElement("div");e.classList.add(this.classes.optgroup);const s=document.createElement("div");s.classList.add(this.classes.optgroupLabel),e.appendChild(s);const i=document.createElement("div");i.classList.add(this.classes.optgroupLabelText),i.textContent=t.label,s.appendChild(i);const n=document.createElement("div");if(n.classList.add(this.classes.optgroupActions),s.appendChild(n),this.settings.isMultiple&&t.selectAll){const e=document.createElement("div");e.classList.add(this.classes.optgroupSelectAll);let s=!0;for(const e of t.options)if(!e.selected){s=!1;break}s&&e.classList.add(this.classes.selected);const i=document.createElement("span");i.textContent=t.selectAllText,e.appendChild(i);const a=document.createElementNS("http://www.w3.org/2000/svg","svg");a.setAttribute("viewBox","0 0 100 100"),e.appendChild(a);const o=document.createElementNS("http://www.w3.org/2000/svg","path");o.setAttribute("d",this.classes.optgroupSelectAllBox),a.appendChild(o);const l=document.createElementNS("http://www.w3.org/2000/svg","path");l.setAttribute("d",this.classes.optgroupSelectAllCheck),a.appendChild(l),e.addEventListener("click",(e=>{e.preventDefault(),e.stopPropagation();const i=this.store.getSelected();if(s){const e=i.filter((e=>{for(const s of t.options)if(e===s.id)return!1;return!0}));this.callbacks.setSelected(e,!0)}else{const e=i.concat(t.options.map((e=>e.id)));for(const e of t.options)this.store.getOptionByID(e.id)||this.callbacks.addOption(e);this.callbacks.setSelected(e,!0)}})),n.appendChild(e)}if("off"!==t.closable){const i=document.createElement("div");i.classList.add(this.classes.optgroupClosable);const a=document.createElementNS("http://www.w3.org/2000/svg","svg");a.setAttribute("viewBox","0 0 100 100"),a.classList.add(this.classes.arrow),i.appendChild(a);const o=document.createElementNS("http://www.w3.org/2000/svg","path");a.appendChild(o),t.options.some((e=>e.selected))||""!==this.content.search.input.value.trim()?(i.classList.add(this.classes.open),o.setAttribute("d",this.classes.arrowOpen)):"open"===t.closable?(e.classList.add(this.classes.open),o.setAttribute("d",this.classes.arrowOpen)):"close"===t.closable&&(e.classList.add(this.classes.close),o.setAttribute("d",this.classes.arrowClose)),s.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),e.classList.contains(this.classes.close)?(e.classList.remove(this.classes.close),e.classList.add(this.classes.open),o.setAttribute("d",this.classes.arrowOpen)):(e.classList.remove(this.classes.open),e.classList.add(this.classes.close),o.setAttribute("d",this.classes.arrowClose))})),n.appendChild(i)}e.appendChild(s);for(const s of t.options)e.appendChild(this.option(s));this.content.list.appendChild(e)}t instanceof a&&this.content.list.appendChild(this.option(t))}}option(e){if(e.placeholder){const e=document.createElement("div");return e.classList.add(this.classes.option),e.classList.add(this.classes.hide),e}const t=document.createElement("div");return t.dataset.id=e.id,t.id=e.id,t.classList.add(this.classes.option),t.setAttribute("role","option"),e.class&&e.class.split(" ").forEach((e=>{t.classList.add(e)})),e.style&&(t.style.cssText=e.style),this.settings.searchHighlight&&""!==this.content.search.input.value.trim()?t.innerHTML=this.highlightText(""!==e.html?e.html:e.text,this.content.search.input.value,this.classes.searchHighlighter):""!==e.html?t.innerHTML=e.html:t.textContent=e.text,this.settings.showOptionTooltips&&t.textContent&&t.setAttribute("title",t.textContent),e.display||t.classList.add(this.classes.hide),e.disabled&&t.classList.add(this.classes.disabled),e.selected&&this.settings.hideSelected&&t.classList.add(this.classes.hide),e.selected?(t.classList.add(this.classes.selected),t.setAttribute("aria-selected","true"),this.main.main.setAttribute("aria-activedescendant",t.id)):(t.classList.remove(this.classes.selected),t.setAttribute("aria-selected","false")),t.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation();const s=this.store.getSelected(),i=t.currentTarget,n=String(i.dataset.id);if(e.disabled||e.selected&&!this.settings.allowDeselect)return;if(this.settings.isMultiple&&this.settings.maxSelected<=s.length&&!e.selected||this.settings.isMultiple&&this.settings.minSelected>=s.length&&e.selected)return;let a=!1;const o=this.store.getSelectedOptions();let l=[];this.settings.isMultiple&&(l=e.selected?o.filter((e=>e.id!==n)):o.concat(e)),this.settings.isMultiple||(l=e.selected?[]:[e]),this.callbacks.beforeChange||(a=!0),this.callbacks.beforeChange&&(a=!1!==this.callbacks.beforeChange(l,o)),a&&(this.store.getOptionByID(n)||this.callbacks.addOption(e),this.callbacks.setSelected(l.map((e=>e.id)),!1),this.settings.closeOnSelect&&this.callbacks.close(),this.callbacks.afterChange&&this.callbacks.afterChange(l))})),t}destroy(){this.main.main.remove(),this.content.main.remove()}highlightText(e,t,s){let i=e;const n=new RegExp("(?![^<]*>)("+t.trim()+")(?![^<]*>[^<>]*${l}`),i}moveContentAbove(){const e=this.main.main.offsetHeight,t=this.content.main.offsetHeight;this.main.main.classList.remove(this.classes.openBelow),this.main.main.classList.add(this.classes.openAbove),this.content.main.classList.remove(this.classes.openBelow),this.content.main.classList.add(this.classes.openAbove);const s=this.main.main.getBoundingClientRect();this.content.main.style.margin="-"+(e+t-1)+"px 0px 0px 0px",this.content.main.style.top=s.top+s.height+window.scrollY+"px",this.content.main.style.left=s.left+window.scrollX+"px",this.content.main.style.width=s.width+"px"}moveContentBelow(){this.main.main.classList.remove(this.classes.openAbove),this.main.main.classList.add(this.classes.openBelow),this.content.main.classList.remove(this.classes.openAbove),this.content.main.classList.add(this.classes.openBelow);const e=this.main.main.getBoundingClientRect();this.content.main.style.margin="-1px 0px 0px 0px","relative"!==this.settings.contentPosition&&(this.content.main.style.top=e.top+e.height+window.scrollY+"px",this.content.main.style.left=e.left+window.scrollX+"px",this.content.main.style.width=e.width+"px")}ensureElementInView(e,t){const s=e.scrollTop+e.offsetTop,i=s+e.clientHeight,n=t.offsetTop,a=n+t.clientHeight;ni&&(e.scrollTop+=a-i)}putContent(){const e=this.main.main.offsetHeight,t=this.main.main.getBoundingClientRect(),s=this.content.main.offsetHeight;return window.innerHeight-(t.top+e)<=s&&t.top>s?"up":"down"}updateDeselectAll(){if(!this.store||!this.settings)return;const e=this.store.getSelectedOptions(),t=e&&e.length>0,s=this.settings.isMultiple,i=this.settings.allowDeselect,n=this.main.deselect.main,a=this.classes.hide;!i||s&&!t?n.classList.add(a):n.classList.remove(a)}}class r{constructor(e){this.listen=!1,this.observer=null,this.select=e,this.valueChange=this.valueChange.bind(this),this.select.addEventListener("change",this.valueChange,{passive:!0}),this.observer=new MutationObserver(this.observeCall.bind(this)),this.changeListen(!0)}enable(){this.select.disabled=!1}disable(){this.select.disabled=!0}hideUI(){this.select.tabIndex=-1,this.select.style.display="none",this.select.setAttribute("aria-hidden","true")}showUI(){this.select.removeAttribute("tabindex"),this.select.style.display="",this.select.removeAttribute("aria-hidden")}changeListen(e){this.listen=e,e&&this.observer&&this.observer.observe(this.select,{subtree:!0,childList:!0,attributes:!0}),e||this.observer&&this.observer.disconnect()}valueChange(e){return this.listen&&this.onValueChange&&this.onValueChange(this.getSelectedOptions()),!0}observeCall(e){if(!this.listen)return;let t=!1,s=!1,i=!1;for(const n of e){if(n.target===this.select&&("disabled"===n.attributeName&&(s=!0),"class"===n.attributeName&&(t=!0),"childList"===n.type)){for(const e of n.addedNodes)if("OPTION"===e.nodeName&&e.value===this.select.value){this.select.dispatchEvent(new Event("change"));break}i=!0}"OPTGROUP"!==n.target.nodeName&&"OPTION"!==n.target.nodeName||(i=!0)}t&&this.onClassChange&&this.onClassChange(this.select.className.split(" ")),s&&this.onDisabledChange&&(this.changeListen(!1),this.onDisabledChange(this.select.disabled),this.changeListen(!0)),i&&this.onOptionsChange&&(this.changeListen(!1),this.onOptionsChange(this.getData()),this.changeListen(!0))}getData(){let e=[];const t=this.select.childNodes;for(const s of t)"OPTGROUP"===s.nodeName&&e.push(this.getDataFromOptgroup(s)),"OPTION"===s.nodeName&&e.push(this.getDataFromOption(s));return e}getDataFromOptgroup(e){let t={id:e.id,label:e.label,selectAll:!!e.dataset&&"true"===e.dataset.selectall,selectAllText:e.dataset?e.dataset.selectalltext:"Select all",closable:e.dataset?e.dataset.closable:"off",options:[]};const s=e.childNodes;for(const e of s)"OPTION"===e.nodeName&&t.options.push(this.getDataFromOption(e));return t}getDataFromOption(e){return{id:e.id,value:e.value,text:e.text,html:e.dataset&&e.dataset.html?e.dataset.html:"",selected:e.selected,display:"none"!==e.style.display,disabled:e.disabled,mandatory:!!e.dataset&&"true"===e.dataset.mandatory,placeholder:"true"===e.dataset.placeholder,class:e.className,style:e.style.cssText,data:e.dataset}}getSelectedOptions(){let e=[];const t=this.select.childNodes;for(const s of t){if("OPTGROUP"===s.nodeName){const t=s.childNodes;for(const s of t)if("OPTION"===s.nodeName){const t=s;t.selected&&e.push(this.getDataFromOption(t))}}if("OPTION"===s.nodeName){const t=s;t.selected&&e.push(this.getDataFromOption(t))}}return e}getSelectedValues(){return this.getSelectedOptions().map((e=>e.value))}setSelected(e){this.changeListen(!1);const t=this.select.childNodes;for(const s of t){if("OPTGROUP"===s.nodeName){const t=s.childNodes;for(const s of t)if("OPTION"===s.nodeName){const t=s;t.selected=e.includes(t.id)}}if("OPTION"===s.nodeName){const t=s;t.selected=e.includes(t.id)}}this.changeListen(!0)}setSelectedByValue(e){this.changeListen(!1);const t=this.select.childNodes;for(const s of t){if("OPTGROUP"===s.nodeName){const t=s.childNodes;for(const s of t)if("OPTION"===s.nodeName){const t=s;t.selected=e.includes(t.value)}}if("OPTION"===s.nodeName){const t=s;t.selected=e.includes(t.value)}}this.changeListen(!0)}updateSelect(e,t,s){this.changeListen(!1),e&&(this.select.dataset.id=e),t&&(this.select.style.cssText=t),s&&(this.select.className="",s.forEach((e=>{""!==e.trim()&&this.select.classList.add(e.trim())}))),this.changeListen(!0)}updateOptions(e){this.changeListen(!1),this.select.innerHTML="";for(const t of e)t instanceof n&&this.select.appendChild(this.createOptgroup(t)),t instanceof a&&this.select.appendChild(this.createOption(t));this.select.dispatchEvent(new Event("change",{bubbles:!0})),this.changeListen(!0)}createOptgroup(e){const t=document.createElement("optgroup");if(t.id=e.id,t.label=e.label,e.selectAll&&(t.dataset.selectAll="true"),"off"!==e.closable&&(t.dataset.closable=e.closable),e.options)for(const s of e.options)t.appendChild(this.createOption(s));return t}createOption(e){const t=document.createElement("option");return t.id=e.id,t.value=e.value,t.innerHTML=e.text,""!==e.html&&t.setAttribute("data-html",e.html),e.selected&&(t.selected=e.selected),e.disabled&&(t.disabled=!0),e.display||(t.style.display="none"),e.placeholder&&t.setAttribute("data-placeholder","true"),e.mandatory&&t.setAttribute("data-mandatory","true"),e.class&&e.class.split(" ").forEach((e=>{t.classList.add(e)})),e.data&&"object"==typeof e.data&&Object.keys(e.data).forEach((s=>{t.setAttribute("data-"+function(e){const t=e.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase()));return e[0]===e[0].toUpperCase()?t.substring(1):t}(s),e.data[s])})),t}destroy(){this.changeListen(!1),this.select.removeEventListener("change",this.valueChange),this.observer&&(this.observer.disconnect(),this.observer=null),delete this.select.dataset.id,this.showUI()}}class c{constructor(e){this.id="",this.style="",this.class=[],this.isMultiple=!1,this.isOpen=!1,this.isFullOpen=!1,this.intervalMove=null,e||(e={}),this.id="ss-"+t(),this.style=e.style||"",this.class=e.class||[],this.disabled=void 0!==e.disabled&&e.disabled,this.alwaysOpen=void 0!==e.alwaysOpen&&e.alwaysOpen,this.showSearch=void 0===e.showSearch||e.showSearch,this.focusSearch=void 0===e.focusSearch||e.focusSearch,this.ariaLabel=e.ariaLabel||"Combobox",this.searchPlaceholder=e.searchPlaceholder||"Search",this.searchText=e.searchText||"No Results",this.searchingText=e.searchingText||"Searching...",this.searchHighlight=void 0!==e.searchHighlight&&e.searchHighlight,this.closeOnSelect=void 0===e.closeOnSelect||e.closeOnSelect,this.contentLocation=e.contentLocation||document.body,this.contentPosition=e.contentPosition||"absolute",this.openPosition=e.openPosition||"auto",this.placeholderText=void 0!==e.placeholderText?e.placeholderText:"Select Value",this.allowDeselect=void 0!==e.allowDeselect&&e.allowDeselect,this.hideSelected=void 0!==e.hideSelected&&e.hideSelected,this.keepOrder=void 0!==e.keepOrder&&e.keepOrder,this.showOptionTooltips=void 0!==e.showOptionTooltips&&e.showOptionTooltips,this.minSelected=e.minSelected||0,this.maxSelected=e.maxSelected||1e3,this.timeoutDelay=e.timeoutDelay||200,this.maxValuesShown=e.maxValuesShown||20,this.maxValuesMessage=e.maxValuesMessage||"{number} selected",this.addableText=e.addableText||'Press "Enter" to add {value}'}}return class{constructor(t){var i;if(this.events={search:void 0,searchFilter:(e,t)=>-1!==e.text.toLowerCase().indexOf(t.toLowerCase()),addable:void 0,beforeChange:void 0,afterChange:void 0,beforeOpen:void 0,afterOpen:void 0,beforeClose:void 0,afterClose:void 0},this.windowResize=s((()=>{(this.settings.isOpen||this.settings.isFullOpen)&&this.render.moveContent()})),this.windowScroll=s((()=>{(this.settings.isOpen||this.settings.isFullOpen)&&this.render.moveContent()})),this.documentClick=e=>{this.settings.isOpen&&e.target&&!function(e,t){function s(e,s){return s&&e&&e.classList&&e.classList.contains(s)||s&&e&&e.dataset&&e.dataset.id&&e.dataset.id===t?e:null}return s(e,t)||function e(t,i){return t&&t!==document?s(t,i)?t:e(t.parentNode,i):null}(e,t)}(e.target,this.settings.id)&&this.close(e.type)},this.windowVisibilityChange=()=>{document.hidden&&this.close()},this.selectEl="string"==typeof t.select?document.querySelector(t.select):t.select,!this.selectEl)return void(t.events&&t.events.error&&t.events.error(new Error("Could not find select element")));if("SELECT"!==this.selectEl.tagName)return void(t.events&&t.events.error&&t.events.error(new Error("Element isnt of type select")));this.selectEl.dataset.ssid&&this.destroy(),this.settings=new c(t.settings),this.cssClasses=new e(t.cssClasses);const n=["afterChange","beforeOpen","afterOpen","beforeClose","afterClose"];for(const e in t.events)t.events.hasOwnProperty(e)&&(-1!==n.indexOf(e)?this.events[e]=s(t.events[e],100):this.events[e]=t.events[e]);this.settings.disabled=(null===(i=t.settings)||void 0===i?void 0:i.disabled)?t.settings.disabled:this.selectEl.disabled,this.settings.isMultiple=this.selectEl.multiple,this.settings.style=this.selectEl.style.cssText,this.settings.class=this.selectEl.className.split(" "),this.select=new r(this.selectEl),this.select.updateSelect(this.settings.id,this.settings.style,this.settings.class),this.select.hideUI(),this.select.onValueChange=e=>{this.setSelected(e.map((e=>e.id)))},this.select.onClassChange=e=>{this.settings.class=e,this.render.updateClassStyles()},this.select.onDisabledChange=e=>{e?this.disable():this.enable()},this.select.onOptionsChange=e=>{this.setData(e)},this.store=new o(this.settings.isMultiple?"multiple":"single",t.data?t.data:this.select.getData()),t.data&&this.select.updateOptions(this.store.getData());const a={open:this.open.bind(this),close:this.close.bind(this),addable:this.events.addable?this.events.addable:void 0,setSelected:this.setSelected.bind(this),addOption:this.addOption.bind(this),search:this.search.bind(this),beforeChange:this.events.beforeChange,afterChange:this.events.afterChange};this.render=new l(this.settings,this.cssClasses,this.store,a),this.render.renderValues(),this.render.renderOptions(this.store.getData());const h=this.selectEl.getAttribute("aria-label"),d=this.selectEl.getAttribute("aria-labelledby");h?this.render.main.main.setAttribute("aria-label",h):d&&this.render.main.main.setAttribute("aria-labelledby",d),this.selectEl.parentNode&&this.selectEl.parentNode.insertBefore(this.render.main.main,this.selectEl.nextSibling),window.addEventListener("resize",this.windowResize,!1),"auto"===this.settings.openPosition&&window.addEventListener("scroll",this.windowScroll,!1),document.addEventListener("visibilitychange",this.windowVisibilityChange),this.settings.disabled&&this.disable(),this.settings.alwaysOpen&&this.open(),this.selectEl.slim=this}enable(){this.settings.disabled=!1,this.select.enable(),this.render.enable()}disable(){this.settings.disabled=!0,this.select.disable(),this.render.disable()}getData(){return this.store.getData()}setData(e){const t=this.store.getSelected(),s=this.store.validateDataArray(e);if(s)return void(this.events.error&&this.events.error(s));this.store.setData(e);const n=this.store.getData();this.select.updateOptions(n),this.render.renderValues(),this.render.renderOptions(n),this.events.afterChange&&!i(t,this.store.getSelected())&&this.events.afterChange(this.store.getSelectedOptions())}getSelected(){let e=this.store.getSelectedOptions();return this.settings.keepOrder&&(e=this.store.selectedOrderOptions(e)),e.map((e=>e.value))}setSelected(e,t=!0){const s=this.store.getSelected(),n=this.store.getDataOptions();e=Array.isArray(e)?e:[e];const a=[];for(const t of e)if(n.find((e=>e.id==t)))a.push(t);else for(const e of n.filter((e=>e.value==t)))a.push(e.id);this.store.setSelectedBy("id",a);const o=this.store.getData();this.select.updateOptions(o),this.render.renderValues(),""!==this.render.content.search.input.value?this.search(this.render.content.search.input.value):this.render.renderOptions(o),t&&this.events.afterChange&&!i(s,this.store.getSelected())&&this.events.afterChange(this.store.getSelectedOptions())}addOption(e){const t=this.store.getSelected();this.store.getDataOptions().some((t=>{var s;return t.value===(null!==(s=e.value)&&void 0!==s?s:e.text)}))||this.store.addOption(e);const s=this.store.getData();this.select.updateOptions(s),this.render.renderValues(),this.render.renderOptions(s),this.events.afterChange&&!i(t,this.store.getSelected())&&this.events.afterChange(this.store.getSelectedOptions())}open(){this.settings.disabled||this.settings.isOpen||(this.events.beforeOpen&&this.events.beforeOpen(),this.render.open(),this.settings.showSearch&&this.settings.focusSearch&&this.render.searchFocus(),this.settings.isOpen=!0,setTimeout((()=>{this.events.afterOpen&&this.events.afterOpen(),this.settings.isOpen&&(this.settings.isFullOpen=!0),document.addEventListener("click",this.documentClick)}),this.settings.timeoutDelay),"absolute"===this.settings.contentPosition&&(this.settings.intervalMove&&clearInterval(this.settings.intervalMove),this.settings.intervalMove=setInterval(this.render.moveContent.bind(this.render),500)))}close(e=null){this.settings.isOpen&&!this.settings.alwaysOpen&&(this.events.beforeClose&&this.events.beforeClose(),this.render.close(),""!==this.render.content.search.input.value&&this.search(""),this.render.mainFocus(e),this.settings.isOpen=!1,this.settings.isFullOpen=!1,setTimeout((()=>{this.events.afterClose&&this.events.afterClose(),document.removeEventListener("click",this.documentClick)}),this.settings.timeoutDelay),this.settings.intervalMove&&clearInterval(this.settings.intervalMove))}search(e){if(this.render.content.search.input.value!==e&&(this.render.content.search.input.value=e),!this.events.search)return void this.render.renderOptions(""===e?this.store.getData():this.store.search(e,this.events.searchFilter));this.render.renderSearching();const t=this.events.search(e,this.store.getSelectedOptions());t instanceof Promise?t.then((e=>{this.render.renderOptions(this.store.partialToFullData(e))})).catch((e=>{this.render.renderError("string"==typeof e?e:e.message)})):Array.isArray(t)?this.render.renderOptions(this.store.partialToFullData(t)):this.render.renderError("Search event must return a promise or an array of data")}destroy(){document.removeEventListener("click",this.documentClick),window.removeEventListener("resize",this.windowResize,!1),"auto"===this.settings.openPosition&&window.removeEventListener("scroll",this.windowScroll,!1),document.removeEventListener("visibilitychange",this.windowVisibilityChange),this.store.setData([]),this.render.destroy(),this.select.destroy()}}}()},3379:e=>{"use strict";var t=[];function s(e){for(var s=-1,i=0;i{"use strict";var t={};e.exports=function(e,s){var i=function(e){if(void 0===t[e]){var s=document.querySelector(e);if(window.HTMLIFrameElement&&s instanceof window.HTMLIFrameElement)try{s=s.contentDocument.head}catch(e){s=null}t[e]=s}return t[e]}(e);if(!i)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");i.appendChild(s)}},9216:e=>{"use strict";e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},3565:(e,t,s)=>{"use strict";e.exports=function(e){var t=s.nc;t&&e.setAttribute("nonce",t)}},7795:e=>{"use strict";e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(s){!function(e,t,s){var i="";s.supports&&(i+="@supports (".concat(s.supports,") {")),s.media&&(i+="@media ".concat(s.media," {"));var n=void 0!==s.layer;n&&(i+="@layer".concat(s.layer.length>0?" ".concat(s.layer):""," {")),i+=s.css,n&&(i+="}"),s.media&&(i+="}"),s.supports&&(i+="}");var a=s.sourceMap;a&&"undefined"!=typeof btoa&&(i+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),t.styleTagTransform(i,e,t.options)}(t,e,s)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},4589:e=>{"use strict";e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}}},t={};function s(i){var n=t[i];if(void 0!==n)return n.exports;var a=t[i]={id:i,exports:{}};return e[i].call(a.exports,a,a.exports,s),a.exports}s.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return s.d(t,{a:t}),t},s.d=(e,t)=>{for(var i in t)s.o(t,i)&&!s.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:t[i]})},s.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),s.nc=void 0,(()=>{"use strict";const e=jQuery;var t=s.n(e);Shiny;var i=s(4487),n=s.n(i),a=s(3379),o=s.n(a),l=s(7795),r=s.n(l),c=s(569),h=s.n(c),d=s(3565),p=s.n(d),u=s(9216),g=s.n(u),m=s(4589),v=s.n(m),f=s(7647),b={};b.styleTagTransform=v(),b.setAttributes=p(),b.insert=h().bind(null,"head"),b.domAPI=r(),b.insertStyleElement=g(),o()(f.Z,b),f.Z&&f.Z.locals&&f.Z.locals;var w=new Shiny.InputBinding;t().extend(w,{store:[],updateStore:(e,t)=>{w.store[e.id]=t},find:e=>t()(e).find(".slim-select"),getValue:e=>w.store[e.id].getSelected(),setValue:(e,t)=>{w.store[e.id].setSelected(t)},subscribe:(e,s)=>{t()(e).on("change.slimSelectBinding",(function(e){s()}))},unsubscribe:e=>{t()(e).off(".slimSelectBinding")},receiveMessage:(e,s)=>{if(s.hasOwnProperty("label")){var i=t()("#"+e.id+"-label");!function(e,t){if(void 0!==e){if(1!==t.length)throw new Error("labelNode must be of length 1");Array.isArray(e)&&0===e.length?t.addClass("shiny-label-null"):(t.html(e),t.removeClass("shiny-label-null"))}}(s.label,i)}s.hasOwnProperty("multiple")&&s.multiple&&e.setAttribute("multiple","");var n=w.store[e.id];s.hasOwnProperty("data")&&n.setData(s.data),s.hasOwnProperty("selected")&&n.setSelected(s.selected),s.hasOwnProperty("disable")&&(s.disable?n.disable():n.enable()),s.hasOwnProperty("open")&&(s.open?n.open():n.close())},initialize:e=>{var t=e.querySelector('script[data-for="'+e.id+'"]');(t=JSON.parse(t.text)).select=e,t.settings.hasOwnProperty("contentLocation")&&(t.settings.contentLocation=document.getElementById(t.settings.contentLocation));var s=new(n())(t);w.updateStore(e,s),t.hasOwnProperty("selected")&&s.setSelected(t.selected),t.settings.hasOwnProperty("contentLocation")&&s.open()}}),Shiny.inputBindings.register(w,"shinyWidgets.slimSelectBinding")})()})(); \ No newline at end of file diff --git a/man/prepare_slim_choices.Rd b/man/prepare_slim_choices.Rd new file mode 100644 index 00000000..0ecfef4b --- /dev/null +++ b/man/prepare_slim_choices.Rd @@ -0,0 +1,139 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slim-select.R +\name{prepare_slim_choices} +\alias{prepare_slim_choices} +\title{Prepare choices for \code{\link[=slimSelectInput]{slimSelectInput()}}} +\usage{ +prepare_slim_choices( + .data, + label, + value, + html = NULL, + selected = NULL, + display = NULL, + disabled = NULL, + mandatory = NULL, + class = NULL, + style = NULL, + .by = NULL, + selectAll = NULL, + closable = NULL +) +} +\arguments{ +\item{.data}{An object of type \code{\link[=data.frame]{data.frame()}}.} + +\item{label}{Variable to use as labels (displayed to user).} + +\item{value}{Variable to use as values (retrieved server-side).} + +\item{html}{Alternative HTML to be displayed instaed of label.} + +\item{selected}{Is the option must be selected ?} + +\item{display}{Allows to hide elements of selected values.} + +\item{disabled}{Allows the ability to disable the select dropdown as well as individual options.} + +\item{mandatory}{When using multi select you can set a mandatory on the option to prevent capability +to deselect particular option. Note options with mandatory flag is not selected by default, you need select them yourselfs.} + +\item{class}{Add CSS classes.} + +\item{style}{Add custom styles to options.} + +\item{.by}{Variable identifying groups to use option group feature.} + +\item{selectAll}{Enable select all feature for options groups.} + +\item{closable}{Allow to close options groups, one of: 'off', 'open', 'close'.} +} +\value{ +A \code{list} to use as \code{choices} argument of \code{\link[=slimSelectInput]{slimSelectInput()}}. +} +\description{ +Prepare choices for \code{\link[=slimSelectInput]{slimSelectInput()}} +} +\examples{ + +library(shiny) +library(shinyWidgets) + +state_data <- data.frame( + name = state.name, + abb = state.abb, + region = state.region, + division = state.division +) + +ui <- fluidPage( + tags$h2("Slim Select examples"), + fluidRow( + column( + width = 3, + slimSelectInput( + inputId = "slim1", + label = "Disable some choices:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + disabled = division == "Mountain" + ), + width = "100\%" + ), + verbatimTextOutput("res1") + ), + column( + width = 3, + slimSelectInput( + inputId = "slim2", + label = "Custom styles:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + style = ifelse( + division == "Mountain", + "color: blue;", + "color: red;" + ) + ), + multiple = TRUE, + placeholder = "Select a state", + width = "100\%" + ), + verbatimTextOutput("res2") + ), + column( + width = 3, + slimSelectInput( + inputId = "slim3", + label = "Options groups with options:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + .by = region, + selectAll = TRUE, + closable = "close" + ), + multiple = TRUE, + width = "100\%" + ), + verbatimTextOutput("res3") + ) + ) +) + +server <- function(input, output, session) { + output$res1 <- renderPrint(input$slim1) + + output$res2 <- renderPrint(input$slim2) + + output$res3 <- renderPrint(input$slim3) +} + +if (interactive()) + shinyApp(ui, server) +} diff --git a/man/slimSelectInput.Rd b/man/slimSelectInput.Rd new file mode 100644 index 00000000..c2d8aaba --- /dev/null +++ b/man/slimSelectInput.Rd @@ -0,0 +1,186 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slim-select.R +\name{slimSelectInput} +\alias{slimSelectInput} +\title{Slim Select Input} +\usage{ +slimSelectInput( + inputId, + label, + choices, + selected = NULL, + multiple = FALSE, + search = TRUE, + placeholder = NULL, + allowDeselect = NULL, + closeOnSelect = !multiple, + keepOrder = NULL, + alwaysOpen = NULL, + contentPosition = NULL, + ..., + inline = FALSE, + width = NULL +) +} +\arguments{ +\item{inputId}{The \code{input} slot that will be used to access the value.} + +\item{label}{Display label for the control, or \code{NULL} for no label.} + +\item{choices}{List of values to select from. +You can use: +\itemize{ +\item \code{vector} a simple vector. +\item \verb{named list} / \verb{named vector} in the same way as with \code{\link[shiny:selectInput]{shiny::selectInput()}} +\item cuxtom choices prepared with \code{\link[=prepare_slim_choices]{prepare_slim_choices()}}. +}} + +\item{selected}{The initially selected value (or multiple values if \code{multiple = TRUE}). If not specified then defaults to the first value for +single-select lists and no values for multiple select lists.} + +\item{multiple}{Is selection of multiple items allowed?} + +\item{search}{Enable search feature.} + +\item{placeholder}{Placeholder text.} + +\item{allowDeselect}{This will allow you to deselect a value on a single/multiple select dropdown.} + +\item{closeOnSelect}{A boolean value in which determines whether or not to close the content area upon selecting a value.} + +\item{keepOrder}{If \code{TRUE} will maintain the order in which options are selected.} + +\item{alwaysOpen}{If \code{TRUE} keep the select open at all times.} + +\item{contentPosition}{Will set the css position to either relative or absolute.} + +\item{...}{Other settings passed to Slim Select JAvaScript method.} + +\item{inline}{Display the widget inline.} + +\item{width}{The width of the input, e.g. \code{'400px'}, or \code{'100\%'}; +see \code{\link[shiny:validateCssUnit]{validateCssUnit()}}.} +} +\value{ +A \code{shiny.tag} object that can be used in a UI definition. +} +\description{ +An advanced select dropdown, +based on \href{https://github.com/brianvoe/slim-select}{slim-select} JavaScript library. +} +\examples{ + +library(shiny) +library(shinyWidgets) +library(htmltools) + +state_data <- data.frame( + name = state.name, + abb = state.abb, + region = state.region, + division = state.division +) + +ui <- fluidPage( + tags$h2("Slim Select examples"), + fluidRow( + column( + width = 4, + + slimSelectInput( + inputId = "slim1", + label = "Single slim select:", + choices = month.name, + width = "100\%" + ), + verbatimTextOutput("res1"), + + slimSelectInput( + inputId = "slim4", + label = "Allow deselect in single select:", + choices = month.name, + placeholder = "Select something:", + allowDeselect = TRUE, + width = "100\%" + ), + verbatimTextOutput("res4") + + ), + column( + width = 4, + + slimSelectInput( + inputId = "slim2", + label = "Multiple slim select:", + choices = month.name, + multiple = TRUE, + placeholder = "Select a month", + width = "100\%" + ), + verbatimTextOutput("res2"), + + slimSelectInput( + inputId = "slim5", + label = "Keep order:", + choices = month.name, + multiple = TRUE, + keepOrder = TRUE, + width = "100\%" + ), + verbatimTextOutput("res5") + + ), + column( + width = 4, + + slimSelectInput( + inputId = "slim3", + label = "Use prepare_slim_choices:", + choices = prepare_slim_choices( + state_data, + label = name, + value = abb, + .by = region, + selectAll = TRUE, + closable = "close" + ), + multiple = TRUE, + width = "100\%" + ), + verbatimTextOutput("res3"), + + slimSelectInput( + inputId = "slim6", + label = "Always open:", + choices = month.name, + multiple = TRUE, + alwaysOpen = TRUE, + # contentPosition = "relative", + # contentLocation = "slim6-placeholder", + width = "100\%" + ) |> htmltools::tagAppendAttributes(style = css(height = "350px")), + verbatimTextOutput("res6") + + ) + ) +) + +server <- function(input, output, session) { + + output$res1 <- renderPrint(input$slim1) + + output$res2 <- renderPrint(input$slim2) + + output$res3 <- renderPrint(input$slim3) + + output$res4 <- renderPrint(input$slim4) + + output$res5 <- renderPrint(input$slim5) + + output$res6 <- renderPrint(input$slim6) + +} + +if (interactive()) + shinyApp(ui, server) +} diff --git a/man/updateSlimSelect.Rd b/man/updateSlimSelect.Rd new file mode 100644 index 00000000..875ff1c5 --- /dev/null +++ b/man/updateSlimSelect.Rd @@ -0,0 +1,159 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/slim-select.R +\name{updateSlimSelect} +\alias{updateSlimSelect} +\title{Update slim select from server} +\usage{ +updateSlimSelect( + inputId, + label = NULL, + choices = NULL, + selected = NULL, + disable = NULL, + open = NULL, + session = shiny::getDefaultReactiveDomain() +) +} +\arguments{ +\item{inputId}{The \code{input} slot that will be used to access the value.} + +\item{label}{Display label for the control, or \code{NULL} for no label.} + +\item{choices}{List of values to select from. +You can use: +\itemize{ +\item \code{vector} a simple vector. +\item \verb{named list} / \verb{named vector} in the same way as with \code{\link[shiny:selectInput]{shiny::selectInput()}} +\item cuxtom choices prepared with \code{\link[=prepare_slim_choices]{prepare_slim_choices()}}. +}} + +\item{selected}{The initially selected value (or multiple values if \code{multiple = TRUE}). If not specified then defaults to the first value for +single-select lists and no values for multiple select lists.} + +\item{disable}{Disable (\code{TRUE}) or enable (\code{FALSE}) the select menu.} + +\item{open}{Open (\code{TRUE}) or close (\code{FALSE}) the dropdown.} + +\item{session}{The \code{session} object passed to function given to +\code{shinyServer}. Default is \code{getDefaultReactiveDomain()}.} +} +\value{ +No value. +} +\description{ +Update a \code{\link[=slimSelectInput]{slimSelectInput()}} from the server. +} +\examples{ +library(shiny) +library(shinyWidgets) + +ui <- fluidPage( + tags$h2("Slim Select (update)"), + + slimSelectInput( + inputId = "sel1", + label = "Update label:", + choices = month.name + ), + verbatimTextOutput("res1"), + textInput("label_text", label = "With text:"), + textInput("label_html", label = "With HTML:"), + + slimSelectInput( + inputId = "sel2", + label = "Update selected value:", + choices = month.name + ), + verbatimTextOutput("res2"), + radioButtons("selected", "Selected value:", month.name, inline = TRUE), + + slimSelectInput( + inputId = "sel3", + label = "Update choices:", + choices = tolower(month.name) + ), + verbatimTextOutput("res3"), + radioButtons("choices", "Choices:", c("lowercase", "UPPERCASE"), inline = TRUE), + + slimSelectInput( + inputId = "sel4", + label = "Update choices + selected:", + choices = tolower(month.name) + ), + verbatimTextOutput("res4"), + radioButtons("choices_select", "Choices:", c("lowercase", "UPPERCASE"), inline = TRUE), + + slimSelectInput( + inputId = "sel5", + label = "Disable / enable:", + choices = tolower(month.name) + ), + verbatimTextOutput("res5"), + checkboxInput("disable", "Disable", value = FALSE), + + slimSelectInput( + inputId = "sel6", + label = "Open / close:", + choices = tolower(month.name) + ), + verbatimTextOutput("res6"), + checkboxInput("open", "Open?", value = FALSE) + +) + +server <- function(input, output, session) { + output$res1 <- renderPrint(input$sel1) + observe({ + req(input$label_text) + updateSlimSelect(inputId = "sel1", label = input$label_text) + }) + observe({ + req(input$label_html) + updateSlimSelect( + inputId = "sel1", + label = tags$span(input$label_html, style = "color: red;") + ) + }) + + output$res2 <- renderPrint(input$sel2) + observe({ + updateSlimSelect(inputId = "sel2", selected = input$selected) + }) + + output$res3 <- renderPrint(input$sel3) + observe({ + if (identical(input$choices, "lowercase")) { + updateSlimSelect(inputId = "sel3", choices = tolower(month.name)) + } else { + updateSlimSelect(inputId = "sel3", choices = toupper(month.name)) + } + }) + + output$res4 <- renderPrint(input$sel4) + observe({ + if (identical(input$choices_select, "lowercase")) { + choices <- tolower(month.name) + } else { + choices <- toupper(month.name) + } + selected <- sample(choices, 1) + updateSlimSelect(inputId = "sel4", choices = choices, selected = selected) + }) + + output$res5 <- renderPrint(input$sel5) + observe({ + updateSlimSelect(inputId = "sel5", disable = isTRUE(input$disable)) + }) + + observeEvent(input$open, { + updateSlimSelect(inputId = "sel6", open = input$open) + }, ignoreInit = TRUE) + +} + +if (interactive()) + shinyApp(ui, server) +} +\seealso{ +\code{\link[=slimSelectInput]{slimSelectInput()}} for creating a widget in the UI. +} diff --git a/package-lock.json b/package-lock.json index 1da15def..3dd39419 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "dayjs": "^1.11.12", "multi.js": "0.5.0", "nouislider": "^15.7.1", + "slim-select": "^2.9.0", "style-loader": "^3.3.1", "virtual-select-plugin": "^1.0.45", "webpack": "^5.76.0", @@ -1380,6 +1381,12 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/slim-select": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/slim-select/-/slim-select-2.9.0.tgz", + "integrity": "sha512-AwAm4kliM1utztdXfKyiidgnQanAKQVJ1+61rJYHwDfzu3LAn/spFKb+xBiSqr3E/dlZu0MrBxflBL2sN5q2xA==", + "dev": true + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -2750,6 +2757,12 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "slim-select": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/slim-select/-/slim-select-2.9.0.tgz", + "integrity": "sha512-AwAm4kliM1utztdXfKyiidgnQanAKQVJ1+61rJYHwDfzu3LAn/spFKb+xBiSqr3E/dlZu0MrBxflBL2sN5q2xA==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index d3419ec0..b468fab3 100644 --- a/package.json +++ b/package.json @@ -30,12 +30,13 @@ "dayjs": "^1.11.12", "multi.js": "0.5.0", "nouislider": "^15.7.1", + "slim-select": "^2.9.0", "style-loader": "^3.3.1", "virtual-select-plugin": "^1.0.45", "webpack": "^5.76.0", "webpack-cli": "^4.9.1", "webpack-merge": "^5.8.0", - "wnumb": "^1.2.0", - "winbox": "^0.2.82" + "winbox": "^0.2.82", + "wnumb": "^1.2.0" } } diff --git a/srcjs/config/entry_points.json b/srcjs/config/entry_points.json index 47513a38..fc101951 100644 --- a/srcjs/config/entry_points.json +++ b/srcjs/config/entry_points.json @@ -9,5 +9,6 @@ "buttons-group": "./srcjs/inputs/buttons-group.js", "input-icons": "./srcjs/inputs/input-icons.js", "input-time": "./srcjs/inputs/input-time.js", - "WinBox": "./srcjs/exts/WinBox.js" + "WinBox": "./srcjs/exts/WinBox.js", + "slim-select": "./srcjs/inputs/slim-select.js" } diff --git a/srcjs/inputs/slim-select.js b/srcjs/inputs/slim-select.js new file mode 100644 index 00000000..96c66a2b --- /dev/null +++ b/srcjs/inputs/slim-select.js @@ -0,0 +1,81 @@ +import $ from "jquery"; +import "shiny"; +import { updateLabel } from "../modules/utils"; +import SlimSelect from "slim-select"; +import "slim-select/styles"; + +var slimSelectBinding = new Shiny.InputBinding(); +$.extend(slimSelectBinding, { + store: [], + updateStore: (el, instance) => { + slimSelectBinding.store[el.id] = instance; + }, + find: scope => { + return $(scope).find(".slim-select"); + }, + getValue: el => { + var select = slimSelectBinding.store[el.id]; + return select.getSelected(); + }, + setValue: (el, value) => { + var select = slimSelectBinding.store[el.id]; + select.setSelected(value); + }, + subscribe: (el, callback) => { + $(el).on("change.slimSelectBinding", function(e) { + callback(); + }); + }, + unsubscribe: el => { + $(el).off(".slimSelectBinding"); + }, + receiveMessage: (el, data) => { + if (data.hasOwnProperty("label")) { + var label = $("#" + el.id + "-label"); + updateLabel(data.label, label); + } + var select = slimSelectBinding.store[el.id]; + if (data.hasOwnProperty("data")) { + select.setData(data.data); + } + if (data.hasOwnProperty("selected")) { + select.setSelected(data.selected); + } + if (data.hasOwnProperty("disable")) { + if (data.disable) { + select.disable(); + } else { + select.enable(); + } + } + if (data.hasOwnProperty("open")) { + if (data.open) { + select.open(); + } else { + select.close(); + } + } + }, + initialize: el => { + var config = el.querySelector('script[data-for="' + el.id + '"]'); + config = JSON.parse(config.text); + config.select = el; + if (config.settings.hasOwnProperty("contentLocation")) { + config.settings.contentLocation = document.getElementById(config.settings.contentLocation); + } + var select = new SlimSelect(config); + slimSelectBinding.updateStore(el, select); + if (config.hasOwnProperty("selected")) { + select.setSelected(config.selected); + } + if (config.settings.hasOwnProperty("contentLocation")) { + select.open(); + } + } +}); + +Shiny.inputBindings.register( + slimSelectBinding, + "shinyWidgets.slimSelectBinding" +); +