{
  "version": 3,
  "sources": ["../src/index.ts", "../src/catch-links.ts", "../src/single-page.ts"],
  "sourcesContent": ["import { CatchLinks } from './catch-links.js'\nimport { type PushFunction, singlePage } from './single-page.js'\n\nexport interface Listener {\n    (href:string, data:{ scrollX:number, scrollY:number, popstate:boolean }):void;\n}\n\n/**\n * Routes\n * @param {} opts\n * @returns A function that takes a callback for route change events, and has\n * a property to set the route.\n */\nexport function Route (opts:{\n    el?:HTMLElement;\n    handleAnchor?:boolean|((href:string)=>boolean),\n    handleLink?:(href:string)=>boolean,\n    init?:boolean\n} = {}):{\n    (cb:Listener):()=>void;\n    setRoute:PushFunction;\n} {\n    let listeners:Listener[] = []\n    const init = opts.init\n    const el = opts.el || document?.body\n    if (!el) throw new Error('Not document')\n\n    const listen = function listen (cb:Listener) {\n        listeners.push(cb)\n\n        return function unlisten () {\n            listeners = listeners.filter(listener => {\n                return listener !== cb\n            })\n        }\n    }\n\n    const setRoute = singlePage((href, eventData) => {\n        listeners.forEach(function (cb) {\n            cb(href, eventData)\n        })\n    }, { init })\n\n    CatchLinks(el, setRoute, {\n        handleAnchor: opts.handleAnchor,\n        handleLink: opts.handleLink\n    })\n\n    const _setRoute:PushFunction = function (href:string) {\n        setRoute(href)\n    }\n\n    _setRoute.push = function (href:string):void {\n        setRoute.push(href)\n    }\n\n    _setRoute.show = function (href) {\n        setRoute.show(href)\n    }\n\n    _setRoute.page = setRoute.page\n\n    listen.setRoute = _setRoute\n\n    return listen\n}\n\nexport default Route\n", "/**\n * Callback on any link click that is local to the server.\n *\n * @param {HTMLElement} root The root element to listen on.\n * @param {(href:string)=>void} cb The function to call on link click.\n */\nexport function CatchLinks (\n    root:HTMLElement,\n    cb:(href:string) => void,\n    opts:{\n        handleAnchor?:boolean|((href:string)=>boolean),\n        handleLink?:(href:string)=>boolean,\n    } = {},\n):()=>void {\n    root.addEventListener('click', onClick)\n\n    function onClick (ev:MouseEvent) {\n        // if command click, do nothing\n        if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.shiftKey ||\n            ev.defaultPrevented) {\n            return true\n        }\n\n        let anchor:null|HTMLElement = null\n        for (\n            let n = (ev.target as HTMLElement|null);\n            n && n.parentNode;\n            n = n.parentElement\n        ) {\n            if (n!.nodeName === 'A') {\n                anchor = n\n                break\n            }\n        }\n\n        // if not a link click, do nothing\n        if (!anchor) return true\n\n        const url = new URL(anchor.getAttribute('href')!, location.origin)\n        const urlPath = url.pathname + url.search\n\n        // if not local, do nothing\n        if (url.host !== location.host) return true\n\n        // if we were given a function to check, call it\n        if (opts.handleLink) {\n            if (!opts.handleLink(urlPath)) return\n        }\n\n        const handleAnchor = opts.handleAnchor === undefined ? true : opts.handleAnchor\n\n        // else, handle the click\n        if (url.href.includes('#')) {\n            if (typeof handleAnchor === 'function') {\n                // do we want to handle this?\n                const handle = handleAnchor(url.href)\n                if (handle) {\n                    ev.preventDefault()\n                    cb(resolve(location.pathname, urlPath || '') +\n                        (url.hash || ''))\n                    return false\n                }\n            } else {\n                if (handleAnchor) {\n                    ev.preventDefault()\n                    cb(resolve(location.pathname, urlPath || '') +\n                        (url.hash || ''))\n                    return false\n                }\n            }\n        } else {\n            ev.preventDefault()\n            cb(resolve(location.pathname, urlPath || '') + (url.hash || ''))\n            return false\n        }\n    }\n\n    return function unlisten () {\n        root.removeEventListener('click', onClick)\n    }\n}\n\nCatchLinks.resolve = resolve\n\nexport default CatchLinks\n\n/**\n * Resolve a local link to a full local path.\n *\n * @param {string} from\n * @param {string} to\n */\nexport function resolve (from:string, to:string):string {\n    const isRelative = (to.charAt(0) !== '/')\n    if (!isRelative) return to\n\n    const fromArr = from.split('/')\n        .map(path => path.replaceAll('/', ''))\n        .filter(Boolean)\n    const toArr = to.split('/').map(path => path.replaceAll('/', ''))\n\n    const str = fromArr.concat(toArr).join('/')\n    return str.charAt(0) === '/' ? str : '/' + str\n}\n", "export interface RouteEventData {\n    scrollX:number;\n    scrollY:number;\n    popstate:boolean;\n}\n\nclass Page {\n    current:string|null = null\n    hasPushState:boolean|typeof window.history.pushState = false\n    scroll = {}\n    cb:((href:string, data:RouteEventData)=>void)|null = null\n    handleAnchor:boolean|((newPath:string)=>boolean) = true\n\n    constructor (\n        cb:(href:string, data:RouteEventData) => void,\n        opts:{\n            pushState?: typeof history.pushState\n            handleAnchor?:boolean|((newPath:string)=>boolean)\n        } = { pushState: undefined }\n    ) {\n        this.hasPushState = (opts.pushState !== undefined ?\n            opts.pushState :\n            (window.history && window.history.pushState)\n        )\n\n        if (typeof opts.handleAnchor === 'function') {\n            this.handleAnchor = opts.handleAnchor\n        }\n\n        this.cb = cb\n    }\n\n    show (href:string, opts = { popstate: false }) {\n        href = href.replace(/^\\/+/, '/')\n\n        this.saveScroll()\n        this.current = href\n\n        const scroll = this.scroll[href]\n        this.pushHref(href)\n\n        this.cb && this.cb(href, {\n            popstate: opts.popstate,\n            scrollX: (scroll && scroll[0]) || 0,\n            scrollY: (scroll && scroll[1]) || 0\n        })\n    }\n\n    saveScroll () {\n        if (this.scroll && this.current) {\n            this.scroll[this.current] = [window.scrollX, window.scrollY]\n        }\n    };\n\n    pushHref (href:string) {\n        this.current = href\n        const mismatched = getPath() !== href\n        let handleThis = true\n\n        if (href.includes('#')) {\n            handleThis = (typeof this.handleAnchor === 'function' ?\n                this.handleAnchor(href) :\n                this.handleAnchor)\n        }\n\n        if (mismatched && handleThis) {\n            window.history.pushState(null, '', href)\n        }\n    }\n\n    push (href:string) {\n        href = href.replace(/^\\/+/, '/')\n        this.saveScroll()\n        this.pushHref(href)\n    }\n}\n\nfunction getPath () {\n    return window.location.pathname\n        + (window.location.search || '')\n        + (window.location.hash || '')\n}\n\nexport default singlePage\n\nexport interface PushFunction {\n    (href:string):void;\n    push:(href:string) => void;\n    show:(href:string) => void;\n    page:InstanceType<typeof Page>;\n}\n\nexport function singlePage (\n    cb:((href:string, data:RouteEventData)=>void),\n    opts?:{\n        pushState?:typeof history.pushState;\n        handleAnchor?:boolean|((newPath:string)=>boolean);\n        init?:boolean  // default true\n    }\n):PushFunction {\n    const page = new Page(cb, opts)\n    window.addEventListener('popstate', onpopstate)\n\n    const init = opts?.init === undefined ? true : opts.init\n\n    function onpopstate () {\n        const href = getPath()\n        page.show(href, { popstate: true })\n    }\n\n    if (init) {\n        setTimeout(onpopstate, 0)  // trigger an event right away, on page load\n    }\n\n    const setRoute:PushFunction = function (href:string) {\n        return page.show(href)\n    }\n    setRoute.push = function (href:string) {\n        return page.push(href)\n    }\n    setRoute.show = function (href) { return page.show(href) }\n    setRoute.page = page\n\n    return setRoute\n}\n"],
  "mappings": "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",
  "names": ["index_exports", "__export", "Route", "index_default", "__toCommonJS", "CatchLinks", "root", "cb", "opts", "onClick", "ev", "anchor", "n", "url", "urlPath", "handleAnchor", "resolve", "__name", "resolve", "from", "to", "fromArr", "path", "toArr", "str", "__name", "Page", "__name", "cb", "opts", "href", "scroll", "mismatched", "getPath", "handleThis", "singlePage", "cb", "opts", "page", "Page", "onpopstate", "init", "href", "getPath", "__name", "setRoute", "Route", "opts", "listeners", "init", "el", "listen", "__name", "cb", "listener", "setRoute", "singlePage", "href", "eventData", "CatchLinks", "_setRoute", "index_default"]
}
