render = async (fn, defaultValue) => {
const config = {}
let {
} = config
const settings = {
onBeforeRender: () => {}
}
const rid = Math.floor(Math.random() * 1000 * 1000).toString(36)
const container = html`<div />`
const wrapper = html`<div id="render-${rid}" />`
const meta = {
mounted: false,
listeners: []
}
const props = {
isDestroyed: () => {
if (!meta.mounted) return false
const exists = document.getElementById(`render-${rid}`)
return !exists
},
currentValue: defaultValue,
setValue: (value, harshRefresh = false) => {
container.value = value
container.dispatchEvent(new CustomEvent("input", { bubbles: true }));
props.currentValue = value
render(harshRefresh)
},
onBeforeRender: fn => {
settings.onBeforeRender = fn
},
addEventListener: (name, fn) => {
const listener = (event) => fn(event)
document.addEventListener(name, listener)
const unsub = () => {
document.removeEventListener(name, listener)
meta.listeners = [ ...(meta.listeners || []).filter(([lname, lfn]) => lfn !== listener)]
document.render_listeners[rid] = (document.render_listeners[rid] || []).filter(u => u !== unsub)
if (!document.render_listeners[rid].length)
delete document.render_listeners[rid]
}
meta.listeners.push([name, listener, unsub])
if (!document.render_listeners) {
document.render_listeners = {}
}
if (!document.render_listeners[rid]) {
document.render_listeners[rid] = []
}
document.render_listeners[rid].push(unsub)
return unsub
}
}
const clearListeners = () => {
if (document.render_listeners) {
Object.keys(document.render_listeners).map((id) => {
const listeners = document.render_listeners[id]
const re = document.querySelector(`#render-${id}`)
if (!re) {
listeners.map(unsub => {
if (unsub && typeof unsub === 'function') unsub()
})
}
})
}
}
const render = async (harsh = false) => {
if (typeof settings.onBeforeRender === 'function') {
settings.onBeforeRender()
}
(meta.listeners || []).map(([name, fn, unsub]) => unsub())
if (props.isDestroyed()) return;
const result = await fn(props)
if (wrapper.children.length && !harsh) {
const dd = new diffDOM.DiffDOM()
const diff = dd.diff(wrapper.children[0], result);
dd.apply(wrapper.children[0], diff);
} else {
while (wrapper.childNodes.length) {
wrapper.removeChild(wrapper.lastChild)
}
wrapper.append(...(Array.isArray(result) ? result : [result]))
}
}
clearListeners()
render()
container.append(wrapper)
if (defaultValue) {
container.value = defaultValue
}
meta.mounted = true
return container;
}