| Encoding: UTF-8 | Encoding: UTF-8 | ||||
| LazyData: true | LazyData: true | ||||
| Roxygen: list(markdown = TRUE) | Roxygen: list(markdown = TRUE) | ||||
| RoxygenNote: 7.0.2 | |||||
| RoxygenNote: 7.1.1 |
| # Generated by roxygen2: do not edit by hand | # Generated by roxygen2: do not edit by hand | ||||
| export(emoji2html) | export(emoji2html) | ||||
| export(emoji_picker) | |||||
| export(ermoji_gadget) | export(ermoji_gadget) | ||||
| export(ermoji_shiny) | export(ermoji_shiny) | ||||
| import(miniUI) | import(miniUI) |
| #' Emoji Picker | |||||
| #' | |||||
| #' An emoji picker gadget that lets you search and find emoji and insert either | |||||
| #' the unicode, HTML, or `emo::ji()` versions of the emoji. Built using the | |||||
| #' [Emoji Button](https://emoji-button.js.org/) JavaScript library. | |||||
| #' | |||||
| #' @return A list with the `emoji`, the emoji `name` and the `html` entity. | |||||
| #' | |||||
| #' @param gadget If `TRUE` the app is run as a gadget, otherwise it's run as a | |||||
| #' standalone app. | |||||
| #' | |||||
| #' @export | |||||
| emoji_picker <- function(gadget = TRUE) { | |||||
| shiny::addResourcePath("eb", system.file("picker", package = "ermoji")) | |||||
| if (gadget) { | |||||
| shiny::runGadget( | |||||
| emoji_picker_ui(), | |||||
| emoji_picker_server(quick_add = TRUE), | |||||
| viewer = shiny::dialogViewer("ermoji", width = 375, height = 463) | |||||
| ) | |||||
| } else { | |||||
| shiny::shinyApp(emoji_picker_ui(), emoji_picker_server(quick_add = FALSE)) | |||||
| } | |||||
| } | |||||
| emoji_picker_ui <- function() { | |||||
| shiny::fluidPage( | |||||
| id = "picker-gadget", | |||||
| class = paste( | |||||
| if (is_rstudio_dark()) "dark-theme", | |||||
| get_picker_type() | |||||
| ), | |||||
| shiny::div(id = "emoji-picker", style = "width: 100%; min-height: 425; position: relative;"), | |||||
| rstudio_style(), | |||||
| shiny::tags$script(src = "eb/emoji-picker.js", type = "module"), | |||||
| shiny::tags$head( | |||||
| shiny::tags$script(src = 'eb/he.js'), | |||||
| shiny::tags$style('.emoji-picker__plugin-container { justify-content: space-between; }') | |||||
| ) | |||||
| ) | |||||
| } | |||||
| is_rstudio_dark <- function() { | |||||
| if (rstudioapi::hasFun("getThemeInfo")) { | |||||
| rstudioapi::getThemeInfo()$dark | |||||
| } else { | |||||
| FALSE | |||||
| } | |||||
| } | |||||
| rstudio_style <- function() { | |||||
| if (!rstudioapi::hasFun("getThemeInfo")) { | |||||
| return(NULL) | |||||
| } | |||||
| theme <- rstudioapi::getThemeInfo() | |||||
| shiny::tags$style(shiny::HTML(paste0( | |||||
| ".emoji-picker {\n", | |||||
| " --background-color: ", theme$background, ";\n", | |||||
| " --text-color: ", theme$foreground, ";\n", | |||||
| "}\n", | |||||
| "body { background-color: ", theme$background, "; color: ", theme$foreground, ";}\n", | |||||
| "#picker_type {\n", | |||||
| " display: flex;\n", | |||||
| " justify-content: space-between;\n", | |||||
| " width: 100%;\n", | |||||
| "}" | |||||
| ))) | |||||
| } | |||||
| set_picker_type <- function(style = c("unicode", "html", "emo_ji")) { | |||||
| if (!rstudioapi::hasFun("setPersistentValue")) { | |||||
| return() | |||||
| } | |||||
| style <- match.arg(style) | |||||
| rstudioapi::setPersistentValue("ermoji.picker_type", style) | |||||
| invisible(style) | |||||
| } | |||||
| get_picker_type <- function() { | |||||
| if (!rstudioapi::hasFun("setPersistentValue")) { | |||||
| return("unicode") | |||||
| } | |||||
| style <- rstudioapi::getPersistentValue("ermoji.picker_type") | |||||
| if (is.null(style)) { | |||||
| return("unicode") | |||||
| } | |||||
| if (!style %in% c("unicode", "html", "emo_ji")) { | |||||
| return("unicode") | |||||
| } | |||||
| style | |||||
| } | |||||
| emoji_picker_server <- function(quick_add = TRUE) { | |||||
| function(input, output, session) { | |||||
| shiny::observeEvent(input$close, { | |||||
| shiny::stopApp(invisible(input$emoji)) | |||||
| }) | |||||
| shiny::observe({ | |||||
| session$sendCustomMessage('update_picker_type', get_picker_type()) | |||||
| }) | |||||
| shiny::observeEvent(input$picker_type, { | |||||
| set_picker_type(input$picker_type) | |||||
| }) | |||||
| shiny::observeEvent(input$emoji, { | |||||
| emoji <- switch( | |||||
| input$picker_type, | |||||
| "unicode" = input$emoji$emoji, | |||||
| "html" = input$emoji$html, | |||||
| "emo_ji" = { | |||||
| tryCatch({ | |||||
| emo::ji(input$emoji$name) | |||||
| paste0('emo::ji("', input$emoji$name, '")') | |||||
| }, | |||||
| error = function(e) { | |||||
| message("{emo} doesn't know the emoji ", shQuote(input$emoji$name)) | |||||
| NULL | |||||
| } | |||||
| ) | |||||
| } | |||||
| ) | |||||
| if (!is.null(emoji)) { | |||||
| rstudioapi::insertText(emoji, id = rstudioapi::documentId()) | |||||
| if (isTRUE(quick_add)) { | |||||
| shiny::stopApp(invisible(input$emoji)) | |||||
| } | |||||
| } | |||||
| }) | |||||
| } | |||||
| } |
| import { EmojiButton } from './emoji-button.js' // @joeattardi/emoji-button | |||||
| const pickerTypePlugin = { | |||||
| render(picker) { | |||||
| const choices = [ | |||||
| {value: 'unicode', label: '<span>Unicode</span>'}, | |||||
| {value: 'html', label: '<span>HTML</span>'}, | |||||
| {value: 'emo_ji', label: '<span style="font-family: monospace;">emo::ji</span>'} | |||||
| ] | |||||
| function htmlToElems(html) { | |||||
| let temp = document.createElement('template'); | |||||
| temp.innerHTML = html; | |||||
| return temp.content.childNodes; | |||||
| } | |||||
| function makeRadioElement({value, label}) { | |||||
| const div = document.createElement('div') | |||||
| const divLabel = document.createElement('label') | |||||
| divLabel.classList = 'radio-inline' | |||||
| const input = document.createElement('input') | |||||
| input.type = 'radio' | |||||
| input.name = 'picker_type' | |||||
| input.value = value | |||||
| if (document.getElementById('picker-gadget').matches('.' + value)) { | |||||
| input.checked = 'checked' | |||||
| } | |||||
| divLabel.appendChild(input) | |||||
| divLabel.appendChild(htmlToElems(label)[0]) | |||||
| div.appendChild(divLabel) | |||||
| return div | |||||
| } | |||||
| const div = document.createElement('div') | |||||
| div.id = 'picker_type' | |||||
| const label = document.createElement('label') | |||||
| label.classList = 'control-label' | |||||
| label['for'] = 'picker_type' | |||||
| label.innerText = 'Insert as...' | |||||
| div.appendChild(label) | |||||
| choices.map(makeRadioElement).forEach(el => div.appendChild(el)) | |||||
| return div; | |||||
| } | |||||
| } | |||||
| const picker = new EmojiButton({ | |||||
| position: { | |||||
| top: '0', | |||||
| right: '0', | |||||
| bottom: '0', | |||||
| left: '0' | |||||
| }, | |||||
| autoHide: false, | |||||
| theme: document.getElementById('picker-gadget').matches('.dark-theme') ? 'dark' : 'light', | |||||
| // plugins: [closePlugin, insertEmoji] | |||||
| plugins: [pickerTypePlugin] | |||||
| }) | |||||
| picker.on('emoji', function(selection) { | |||||
| selection.html = he.encode(selection.emoji) | |||||
| Shiny.setInputValue('emoji', selection, { priority: 'event' }); | |||||
| }); | |||||
| picker.togglePicker(document.getElementById('emoji-picker')) | |||||
| document.querySelector('.emoji-picker__wrapper').addEventListener('keydown', function(ev) { | |||||
| if (ev.keyCode === 27) { | |||||
| ev.stopPropagation() | |||||
| Shiny.setInputValue('close', Date.now()) | |||||
| } | |||||
| }) | |||||
| // Communicate choices of emoji type to insert ... | |||||
| const pickerInput = document.getElementById('picker_type') | |||||
| function reportPickerType() { | |||||
| const choices = [...pickerInput.querySelectorAll('input')] | |||||
| const value = choices.filter(item => item.checked).map(item => item.value) | |||||
| Shiny.setInputValue('picker_type', value[0]) | |||||
| } | |||||
| function updatePickerType(value) { | |||||
| const choices = [...pickerInput.querySelectorAll('input')] | |||||
| choices.forEach(function(choice) { | |||||
| if (choice.value === value) { | |||||
| choice.checked = 'checked' | |||||
| Shiny.setInputValue('picker_type', value) | |||||
| } else { | |||||
| choice.removeAttribute('checked') | |||||
| } | |||||
| }) | |||||
| } | |||||
| pickerInput.addEventListener('change', reportPickerType) | |||||
| $().on('shiny:sessioninitialized', reportPickerType) | |||||
| Shiny.addCustomMessageHandler('update_picker_type', updatePickerType) |
| Description: Search for emoji and copy name, unicode, or gliph. | Description: Search for emoji and copy name, unicode, or gliph. | ||||
| Binding: ermoji_gadget | Binding: ermoji_gadget | ||||
| Interactive: true | Interactive: true | ||||
| Name: Pick and Insert Emoji | |||||
| Description: Insert emoji from picker | |||||
| Binding: emoji_picker | |||||
| Interactive: true | |||||
| % Generated by roxygen2: do not edit by hand | |||||
| % Please edit documentation in R/emoji_picker.R | |||||
| \name{emoji_picker} | |||||
| \alias{emoji_picker} | |||||
| \title{Emoji Picker} | |||||
| \usage{ | |||||
| emoji_picker(gadget = TRUE) | |||||
| } | |||||
| \arguments{ | |||||
| \item{gadget}{If \code{TRUE} the app is run as a gadget, otherwise it's run as a | |||||
| standalone app.} | |||||
| } | |||||
| \value{ | |||||
| A list with the \code{emoji}, the emoji \code{name} and the \code{html} entity. | |||||
| } | |||||
| \description{ | |||||
| An emoji picker gadget that lets you search and find emoji and insert either | |||||
| the unicode, HTML, or \code{emo::ji()} versions of the emoji. Built using the | |||||
| \href{https://emoji-button.js.org/}{Emoji Button} JavaScript library. | |||||
| } |