Files
once-campfire/app/javascript/lib/autocomplete/selection.js
Kevin McConnell df76a227dc Hello world
First open source release of Campfire 🎉
2025-08-21 09:31:59 +01:00

83 lines
2.1 KiB
JavaScript

import { memoize } from "lib/autocomplete/utils"
export default class Selection {
#elements = []
#element
#observer
constructor(element) {
this.#element = element
this.#observeMutations()
this.#render()
}
disconnect() {
this.#observer.disconnect()
this.#render()
}
add(value, label, options = {}) {
this.#element.append(this.#findOption(value) || this.#createOption(value, label, options))
}
remove(value) {
this.#findOption(value)?.remove()
}
removeLast() {
this.#lastOption?.remove()
}
get values() {
return this.#options.map(option => parseInt(option.value))
}
#createOption(value, label, { avatarUrl }) {
const option = new Option(label, value, true, true)
option.dataset.avatarUrl = avatarUrl
return option
}
#findOption(value) {
return this.#options.find(option => option.value == value)
}
get #lastOption() {
return this.#options.slice(-1)[0]
}
#observeMutations() {
this.#observer = new MutationObserver(this.#optionsChanged)
this.#observer.observe(this.#element, { childList: true })
}
#optionsChanged = () => {
this.#render()
}
get #options() {
return Array.from(this.#element.options)
}
#render() {
for (const element of this.#elements) element.remove()
this.#elements = this.#element.isConnected ? this.#options.map(this.#renderElementForOption) : []
}
#renderElementForOption = (option) => {
const { value, label } = option
const content = this.#template.content.cloneNode(true)
content.querySelectorAll("[data-value]").forEach(element => element.dataset.value = value)
content.querySelector("[data-content=label]").textContent = label
content.querySelector("[data-content=label]").title = value
content.querySelector("[data-content=screenReaderLabel]").textContent = label
content.querySelector("[data-content=avatar]").src = option.dataset.avatarUrl
return this.#template.insertAdjacentElement("beforebegin", content.firstElementChild)
}
get #template() {
const id = this.#element.getAttribute("data-template-id")
return memoize(this, "template", document.getElementById(id))
}
}