module-lazy.ts ts

import {
	type Component,
	component,
	computed,
	dangerouslySetInnerHTML,
	setText,
	show,
	state,
	toggleClass,
	UNSET,
} from '../../..'
import { asURL } from '../../functions/attribute-parser/as-url'
import { fetchWithCache } from '../../functions/shared/fetch-with-cache'

export type ModuleLazyProps = {
	src: string
}

export default component('module-lazy', { src: asURL }, (el, { first }) => {
	const error = state('')
	const content = computed(async abort => {
		const url = el.src.value
		if (el.src.error || !url) {
			error.set(el.src.error ?? 'No URL provided')
			return ''
		}

		try {
			error.set('')
			el.querySelector('.loading')?.remove()
			const { content } = await fetchWithCache(url, abort)
			return content
		} catch (err) {
			error.set(err instanceof Error ? err.message : String(err))
			return ''
		}
	})

	return [
		dangerouslySetInnerHTML(content),
		first(
			'card-callout',
			[
				show(() => !!error.get() || content.get() === UNSET),
				toggleClass('danger', () => !error.get()),
			],
			'Needed to display loading state and error messages.',
		),
		first('.error', setText(error), 'Needed to display error messages.'),
	]
})

declare global {
	interface HTMLElementTagNameMap {
		'module-lazy': Component<ModuleLazyProps>
	}
}