pinafore/src/routes/_components/dialog/components/EmojiDialog.html

153 wiersze
5.1 KiB
HTML

<ModalDialog
{id}
{label}
{title}
shrinkWidthToFit={true}
background="var(--main-bg)"
className="emoji-dialog"
>
<div class="emoji-container" ref:container ></div>
</ModalDialog>
<style>
:global(emoji-picker) {
--indicator-color: var(--main-theme-color);
--outline-color: var(--focus-outline);
}
@media (max-width: 479px) {
:global(emoji-picker) {
--emoji-padding: 0.25rem;
--input-padding: 0.125rem;
}
.emoji-container, :global(emoji-picker) {
width: 100%;
}
}
@media (max-width: 320px) {
:global(emoji-picker) {
--num-columns: 6;
}
}
@media (max-width: 240px) {
:global(emoji-picker) {
--num-columns: 6;
--emoji-size: 1.125rem;
--emoji-padding: 0.125rem;
height: 240px;
}
}
</style>
<script>
/* global applyFocusVisiblePolyfill */
import ModalDialog from './ModalDialog.html'
import { store } from '../../../_store/store'
import { insertEmoji } from '../../../_actions/emoji'
import { show } from '../helpers/showDialog'
import { close } from '../helpers/closeDialog'
import { oncreate as onCreateDialog } from '../helpers/onCreateDialog'
import { isDarkTheme } from '../../../_utils/isDarkTheme'
import Picker from 'emoji-picker-element/picker'
import 'focus-visible'
import { registerShadowRoot, unregisterShadowRoot } from '../../../_thirdparty/a11y-dialog/a11y-dialog'
import { doubleRAF } from '../../../_utils/doubleRAF'
import { convertCustomEmojiToEmojiPickerFormat } from '../../../_utils/convertCustomEmojiToEmojiPickerFormat'
function applyShadowDomPolyfill (picker) {
// polyfill for :host, plus other fixes mostly targeted at KaiOS.
// We could use shadycss, but it doesn't really work for our use case (has to be injected
// into the web component's connectedCallback directly).
const style = picker.shadowRoot.querySelector('style')
style.remove()
if (!document.getElementById('emoji-picker-style')) {
let css = style.textContent
css = css.replace(/:host\(([.*?])\)/g, 'emoji-picker$1')
css = css.replace(/:host/g, 'emoji-picker')
css = css.replace(/\*/g, 'emoji-picker *')
css = css.replace(/\b(button|input|input\[type=search\])\s*\{/, 'emoji-picker $1{')
// fixes for KaiOS style bugs
css += `
emoji-picker .emoji-menu {
grid-template-columns: repeat(8, 1fr);
}
@media screen and (max-width: 320px) {
emoji-picker .emoji-menu {
grid-template-columns: repeat(6, 1fr);
}
.emoji-container {
width: calc(100% - 20px);
}
}
`
const newStyle = document.createElement('style')
newStyle.id = 'emoji-picker-style'
newStyle.textContent = css
document.head.appendChild(newStyle)
}
}
export default {
async oncreate () {
onCreateDialog.call(this)
const { customEmoji, darkMode } = this.get()
const { enableGrayscale, isUserTouching } = this.store.get()
const picker = new Picker({
dataSource: '/emoji-all-en.json',
customEmoji
})
picker.classList.add(darkMode ? 'dark' : 'light')
picker.addEventListener('emoji-click', this.onEmojiSelected.bind(this))
// workaround for shortcuts -- see acceptShortcutEvent() in shortcuts.js
picker.addEventListener('keydown', event => {
if (event.key === 'Backspace' &&
picker.shadowRoot.activeElement &&
picker.shadowRoot.activeElement.tagName === 'INPUT') {
event.stopPropagation() // prevent our hotkeys from activating when pressing backspace in the input
}
})
// break into shadow DOM to fix grayscale in Welness grayscale mode
if (enableGrayscale) {
const style = document.createElement('style')
style.textContent = '.emoji { filter: grayscale(100%); }'
picker.shadowRoot.appendChild(style)
}
applyFocusVisiblePolyfill(picker.shadowRoot)
registerShadowRoot(picker.shadowRoot)
if (process.env.LEGACY && !HTMLElement.prototype.attachShadow.toString().includes('[native code]')) {
applyShadowDomPolyfill(picker)
}
this.refs.container.appendChild(picker)
this.on('destroy', () => unregisterShadowRoot(picker.shadowRoot))
if (!isUserTouching) { // auto focus the input on desktop
doubleRAF(() => { // triple rAF because a11y tries to focus as well
requestAnimationFrame(() => {
picker.shadowRoot.querySelector('input').focus()
})
})
}
},
components: {
ModalDialog
},
store: () => store,
computed: {
darkMode: ({ $currentTheme }) => isDarkTheme($currentTheme),
customEmoji: ({ $currentCustomEmoji, $autoplayGifs }) => (
convertCustomEmojiToEmojiPickerFormat($currentCustomEmoji, $autoplayGifs)
)
},
methods: {
show,
close,
onEmojiSelected (event) {
const { realm } = this.get()
insertEmoji(realm, event.detail.emoji)
this.close()
}
}
}
</script>