Spaces:
Running on Zero
Running on Zero
File size: 6,008 Bytes
fdcef0f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | from __future__ import annotations
from dataclasses import dataclass
from html import escape
import gradio as gr
@dataclass(frozen=True)
class EmojiPaletteItem:
emoji: str
label: str
description: str
EMOJI_PALETTE_CSS = """
.emoji-palette {
max-width: 100%;
}
.emoji-palette-grid {
display: flex;
gap: 3px;
flex-wrap: wrap;
align-items: flex-start;
max-height: 124px;
overflow-y: auto;
}
.emoji-palette-button {
flex: 0 0 28px !important;
min-width: 28px !important;
max-width: 28px !important;
}
.emoji-palette-button button {
width: 28px !important;
min-width: 28px !important;
height: 28px !important;
min-height: 28px !important;
border-radius: 4px;
font-size: 17px;
line-height: 1;
padding: 0 !important;
}
button.emoji-palette-button {
width: 28px;
min-width: 28px;
height: 28px;
min-height: 28px;
border-radius: 4px;
font-size: 17px;
line-height: 1;
padding: 0;
cursor: pointer;
}
"""
EMOJI_PALETTE_ITEMS: tuple[EmojiPaletteItem, ...] = (
EmojiPaletteItem("๐", "ๅใ", "่ณๅ
ใฎ้ณ"),
EmojiPaletteItem("๐ฎโ๐จ", "ๅๆฏ", "ๆบๆฏใๅฏๆฏ"),
EmojiPaletteItem("โธ๏ธ", "้", "ๆฒ้ป"),
EmojiPaletteItem("๐คญ", "็ฌใ", "ใใใใใๅซใฟ็ฌใ"),
EmojiPaletteItem("๐ฅต", "ๅใ", "ใใใๅฃฐใๅธใๅฃฐ"),
EmojiPaletteItem("๐ข", "ใจใณใผ", "ใชใใผใ"),
EmojiPaletteItem("๐", "ใใใใ", "็ใใใใใซ"),
EmojiPaletteItem("๐ฅบ", "้ใๅฃฐ", "่ชไฟกใชใใใซ"),
EmojiPaletteItem("๐ฌ๏ธ", "ๆฏๅใ", "่ใๆฏ้ฃใใๅผๅธ้ณ"),
EmojiPaletteItem("๐ฎ", "ๆฏใใฎใ", "Gasp"),
EmojiPaletteItem("๐
", "่ใใ้ณ", "ๅๅผ้ณใๆฐด้ณ"),
EmojiPaletteItem("๐", "ใชใใใใคใบ", "Lip smack"),
EmojiPaletteItem("๐ซถ", "ๅชใใ", "Tenderly"),
EmojiPaletteItem("๐ญ", "ๆณฃใๅฃฐ", "ๅๅฝใๆฒใใฟ"),
EmojiPaletteItem("๐ฑ", "ๆฒ้ณด", "ๅซใณใ็ตถๅซ"),
EmojiPaletteItem("๐ช", "็ ใใ", "ๆฐใ ใใใซ"),
EmojiPaletteItem("๐ด", "ๅฏ่จ", "ใใณใ"),
EmojiPaletteItem("โฉ", "ๆฉๅฃ", "ไธๆฐใซใๆฅใใง"),
EmojiPaletteItem("๐", "้ป่ฉฑ่ถใ", "ในใใผใซใผ่ถใ"),
EmojiPaletteItem("๐ข", "ใใฃใใ", "Slowly"),
EmojiPaletteItem("๐ฅค", "้ฃฒใฟ่พผใ", "ๅพใ้ฃฒใ้ณ"),
EmojiPaletteItem("๐คง", "ๅณใป้ผป", "ๅณใ่พผใฟใ้ผปใใใ"),
EmojiPaletteItem("๐", "่ๆใก", "Tutting"),
EmojiPaletteItem("๐ฐ", "ๆ
ใฆใ", "ๅๆบใ็ทๅผตใใฉใใ"),
EmojiPaletteItem("๐", "ๅใณ", "ๅฌใใใใซ"),
EmojiPaletteItem("๐ฅ", "ๅขใใใ", "ๅๅผทใๅขใ"),
EmojiPaletteItem("๐ ", "ๆใ", "ไธๆบใใๆใญใ"),
EmojiPaletteItem("๐ฒ", "้ฉใ", "ๆๅ"),
EmojiPaletteItem("๐ฅฑ", "ใใใณ", "Yawn"),
EmojiPaletteItem("๐", "่ฆใใ", "Agonizingly"),
EmojiPaletteItem("๐", "ๅฟ้
", "ไธๅฎใใใซ"),
EmojiPaletteItem("๐ซฃ", "็
งใ", "ๆฅใใใใใใซ"),
EmojiPaletteItem("๐", "ๅใ", "Exasperatedly"),
EmojiPaletteItem("๐", "ๆฅฝใใ", "ๅฌใใใใซ"),
EmojiPaletteItem("๐", "ๅพๆใ", "่ชไฟกใใใใซ"),
EmojiPaletteItem("๐", "็ธๆง", "้ ทใ้ณ"),
EmojiPaletteItem("๐", "ๆ้ก", "ใ้กใใใใใใซ"),
EmojiPaletteItem("๐ฅด", "้
ใ", "Drunkenly"),
EmojiPaletteItem("๐ต", "้ผปๆญ", "Humming"),
EmojiPaletteItem("๐ค", "ๅฃใๅกใ", "Muffled"),
EmojiPaletteItem("๐", "ๅฎๅ ต", "ๆบ่ถณใใซ"),
EmojiPaletteItem("๐ค", "็ๅ", "Questioning"),
EmojiPaletteItem("๐ช", "ๅๅผทใ", "ๅใ่พผใใฆ"),
EmojiPaletteItem("๐", "ๅ
ใ้ณ", "ๅใใๅ
ใ้ณ"),
EmojiPaletteItem("๐", "ๆ่ชญ", "ใใฌใผใทใงใณ"),
)
_INSERT_EMOJI_ON_POINTER_DOWN = (
"event.preventDefault();"
"const root=this.closest('[data-irodori-emoji-palette]');"
"const input=root?document.querySelector(root.dataset.target):null;"
"if(!input)return;"
"const emoji=this.dataset.emoji;"
"const text=input.value||'';"
"const focused=document.activeElement===input;"
"const start=focused&&typeof input.selectionStart==='number'?input.selectionStart:text.length;"
"const end=focused&&typeof input.selectionEnd==='number'?input.selectionEnd:text.length;"
"const next=text.slice(0,start)+emoji+text.slice(end);"
"const caret=start+emoji.length;"
"input.value=next;"
"input.focus({preventScroll:true});"
"input.setSelectionRange(caret,caret);"
"input.dispatchEvent(new Event('input',{bubbles:true}));"
"input.dispatchEvent(new Event('change',{bubbles:true}));"
)
def _textbox_selector(textbox: gr.Textbox) -> str:
elem_id = getattr(textbox, "elem_id", None)
root_selector = f"#{elem_id}" if elem_id else f"#component-{textbox._id}"
return f"{root_selector} textarea, {root_selector} input:not([type='hidden'])"
def _emoji_palette_html(textbox: gr.Textbox) -> str:
target = escape(_textbox_selector(textbox), quote=True)
handler = escape(_INSERT_EMOJI_ON_POINTER_DOWN, quote=True)
buttons = []
for item in EMOJI_PALETTE_ITEMS:
emoji = escape(item.emoji, quote=True)
title = escape(f"{item.label}: {item.description}", quote=True)
buttons.append(
'<button type="button" '
'class="emoji-palette-button" '
f'data-emoji="{emoji}" '
f'title="{title}" '
f'aria-label="{title}" '
f'onpointerdown="{handler}">'
f"{emoji}</button>"
)
return (
'<div class="emoji-palette-grid" '
'data-irodori-emoji-palette="true" '
f'data-target="{target}">'
f"{''.join(buttons)}</div>"
)
def build_emoji_palette(textbox: gr.Textbox, *, open: bool = True) -> None:
with gr.Accordion("Emoji Palette", open=open, elem_classes=["emoji-palette"]):
gr.HTML(_emoji_palette_html(textbox))
|