import type { Twind, BaseTheme, TwindConfig, Sheet, TwindUserConfig, ExtractThemes, Preset, } from './types' import { twind } from './twind' import { observe } from './observe' import { getSheet } from './sheets' import { noop } from './utils' import { DEV } from 'distilt/env' /** * @group Runtime * @param install * @returns */ export function auto(install: () => void): () => void { // If we run in the browser we call install at latest when the body is inserted // This algorith works well for _normal_ scripts (``) // but not for modules because those are executed __after__ the DOM is ready // and we would have FOUC if (typeof document != 'undefined' && document.currentScript) { const cancelAutoInstall = () => observer.disconnect() const observer: MutationObserver = new MutationObserver((mutationsList) => { for (const { target } of mutationsList) { // If we reach the body we immediately run the install to prevent FOUC if (target === document.body) { install() return cancelAutoInstall() } } }) observer.observe(document.documentElement, { childList: true, subtree: true, }) return cancelAutoInstall } return noop } let active: Twind function assertActive() { if (DEV && !active) { throw new Error( `No active twind instance found. Make sure to call setup or install before accessing tw.`, ) } } /** * A proxy to the currently active Twind instance. * @group Style Injectors */ export const tw: Twind = /* #__PURE__ */ new Proxy( // just exposing the active as tw should work with most bundlers // as ES module export can be re-assigned BUT some bundlers to not honor this // -> using a delegation proxy here noop as unknown as Twind, { apply(_target, _thisArg, args) { if (DEV) assertActive() return active(args[0]) }, get(_target, property) { if (DEV) assertActive() const value = active[property as keyof Twind] if (typeof value === 'function') { return function () { if (DEV) assertActive() // eslint-disable-next-line prefer-rest-params return value.apply(active, arguments) } } return value }, }, ) export type SheetFactory = () => Sheet /** * Manages a single Twind instance — works in browser, Node.js, Deno, workers... * * @group Runtime * @param config * @param sheet * @param target * @returns */ export function setup( config?: TwindConfig, sheet?: Sheet | SheetFactory, target?: HTMLElement, ): Twind export function setup< Theme = BaseTheme, Presets extends Preset[] = Preset[], SheetTarget = unknown, >( config?: TwindUserConfig, sheet?: Sheet | SheetFactory, target?: HTMLElement, ): Twind, SheetTarget> export function setup( config: TwindConfig | TwindUserConfig = {}, sheet: Sheet | SheetFactory = getSheet as SheetFactory, target?: HTMLElement, ): Twind { active?.destroy() active = observe( twind(config as TwindUserConfig, typeof sheet == 'function' ? sheet() : sheet), target, ) return active as unknown as Twind }