Bladeren bron

Move history and navigate plugins into livewire/livewire untill they're stable

Caleb Porzio 1 jaar geleden
bovenliggende
commit
1e03013623

+ 0 - 1
index.html

@@ -5,7 +5,6 @@
     <script src="./packages/focus/dist/cdn.js"></script>
     <script src="./packages/mask/dist/cdn.js"></script>
     <script src="./packages/ui/dist/cdn.js" defer></script> -->
-    <script src="./packages/history/dist/cdn.js"></script>
     <script src="./packages/alpinejs/dist/cdn.js" defer></script>
     <!-- <script src="//cdn.tailwindcss.com"></script> -->
     <!-- <script src="//cdn.tailwindcss.com"></script> -->

+ 1 - 237
packages/history/src/index.js

@@ -1,237 +1 @@
-
-export default function history(Alpine) {
-    Alpine.magic('queryString', (el, { interceptor }) =>  {
-        let alias
-        let alwaysShow = false
-        let usePush = false
-
-        return interceptor((initialSeedValue, getter, setter, path, key) => {
-            let queryKey = alias || path
-
-            let { initial, replace, push, pop } = track(queryKey, initialSeedValue, alwaysShow)
-
-            setter(initial)
-
-            if (! usePush) {
-                console.log(getter())
-                Alpine.effect(() => replace(getter()))
-            } else {
-                Alpine.effect(() => push(getter()))
-
-                pop(async newValue => {
-                    setter(newValue)
-
-                    let tillTheEndOfTheMicrotaskQueue = () => Promise.resolve()
-
-                    await tillTheEndOfTheMicrotaskQueue() // ...so that we preserve the internal lock...
-                })
-            }
-
-            return initial
-        }, func => {
-            func.alwaysShow = () => { alwaysShow = true; return func }
-            func.usePush = () => { usePush = true; return func }
-            func.as = key => { alias = key; return func }
-        })
-    })
-
-    Alpine.history = { track }
-}
-
-export function track(name, initialSeedValue, alwaysShow = false) {
-    let { has, get, set, remove } = queryStringUtils()
-
-    let url = new URL(window.location.href)
-    let isInitiallyPresentInUrl = has(url, name)
-    let initialValue = isInitiallyPresentInUrl ? get(url, name) : initialSeedValue
-    let initialValueMemo = JSON.stringify(initialValue)
-    let hasReturnedToInitialValue = (newValue) => JSON.stringify(newValue) === initialValueMemo
-
-    if (alwaysShow) url = set(url, name, initialValue)
-
-    replace(url, name, { value: initialValue })
-
-    let lock = false
-
-    let update = (strategy, newValue) => {
-        if (lock) return
-
-        let url = new URL(window.location.href)
-
-        if (! alwaysShow && ! isInitiallyPresentInUrl && hasReturnedToInitialValue(newValue)) {
-            url = remove(url, name)
-        } else {
-            url = set(url, name, newValue)
-        }
-
-        strategy(url, name, { value: newValue})
-    }
-
-    return {
-        initial: initialValue,
-
-        replace(newValue) { // Update via replaceState...
-            update(replace, newValue)
-        },
-
-        push(newValue) { // Update via pushState...
-            update(push, newValue)
-        },
-
-        pop(receiver) { // "popstate" handler...
-            window.addEventListener('popstate', (e) => {
-                if (! e.state || ! e.state.alpine) return
-
-                Object.entries(e.state.alpine).forEach(([iName, { value: newValue }]) => {
-                    if (iName !== name) return
-
-                    lock = true
-
-                    // Allow the "receiver" to be an async function in case a non-syncronous
-                    // operation (like an ajax) requests needs to happen while preserving
-                    // the "locking" mechanism ("lock = true" in this case)...
-                    let result = receiver(newValue)
-
-                    if (result instanceof Promise) {
-                        result.finally(() => lock = false)
-                    } else {
-                        lock = false
-                    }
-                })
-            })
-        }
-    }
-}
-
-function replace(url, key, object) {
-    let state = window.history.state || {}
-
-    if (! state.alpine) state.alpine = {}
-
-    state.alpine[key] = unwrap(object)
-
-    window.history.replaceState(state, '', url.toString())
-}
-
-function push(url, key, object) {
-    let state = { alpine: {...window.history.state.alpine, ...{[key]: unwrap(object)}} }
-
-    window.history.pushState(state, '', url.toString())
-}
-
-function unwrap(object) {
-    return JSON.parse(JSON.stringify(object))
-}
-
-function queryStringUtils() {
-    return {
-        has(url, key) {
-            let search = url.search
-
-            if (! search) return false
-
-            let data = fromQueryString(search)
-
-            return Object.keys(data).includes(key)
-        },
-        get(url, key) {
-            let search = url.search
-
-            if (! search) return false
-
-            let data = fromQueryString(search)
-
-            return data[key]
-        },
-        set(url, key, value) {
-            let data = fromQueryString(url.search)
-
-            data[key] = value
-
-            url.search = toQueryString(data)
-
-            return url
-        },
-        remove(url, key) {
-            let data = fromQueryString(url.search)
-
-            delete data[key]
-
-            url.search = toQueryString(data)
-
-            return url
-        },
-    }
-}
-
-// This function converts JavaScript data to bracketed query string notation...
-// { items: [['foo']] } -> "items[0][0]=foo"
-function toQueryString(data) {
-    let isObjecty = (subject) => typeof subject === 'object' && subject !== null
-
-    let buildQueryStringEntries = (data, entries = {}, baseKey = '') => {
-        Object.entries(data).forEach(([iKey, iValue]) => {
-            let key = baseKey === '' ? iKey : `${baseKey}[${iKey}]`
-
-            if (! isObjecty(iValue)) {
-                entries[key] = encodeURIComponent(iValue)
-                    .replaceAll('%20', '+') // Conform to RFC1738
-            } else {
-                entries = {...entries, ...buildQueryStringEntries(iValue, entries, key)}
-            }
-        })
-
-        return entries
-    }
-
-    let entries = buildQueryStringEntries(data)
-
-
-    return Object.entries(entries).map(([key, value]) => `${key}=${value}`).join('&')
-}
-
-// This function converts bracketed query string notation back to JS data...
-// "items[0][0]=foo" -> { items: [['foo']] }
-function fromQueryString(search) {
-    search = search.replace('?', '')
-
-    if (search === '') return {}
-
-    let insertDotNotatedValueIntoData = (key, value, data) => {
-        let [first, second, ...rest] = key.split('.')
-
-        // We're at a leaf node, let's make the assigment...
-        if (! second) return data[key] = value
-
-        // This is where we fill in empty arrays/objects allong the way to the assigment...
-        if (data[first] === undefined) {
-            data[first] = isNaN(second) ? {} : []
-        }
-
-        // Keep deferring assignment until the full key is built up...
-        insertDotNotatedValueIntoData([second, ...rest].join('.'), value, data[first])
-    }
-
-    let entries = search.split('&').map(i => i.split('='))
-
-    let data = {}
-
-    entries.forEach(([key, value]) => {
-        // Query string params don't always have values... (`?foo=`)
-        if (! value) return
-
-        value = decodeURIComponent(value.replaceAll('+', '%20'))
-
-        if (! key.includes('[')) {
-            data[key] = value
-        } else {
-            // Convert to dot notation because it's easier...
-            let dotNotatedKey = key.replaceAll('[', '.').replaceAll(']', '')
-
-            insertDotNotatedValueIntoData(dotNotatedKey, value, data)
-        }
-    })
-
-    return data
-}
-
+// This plugin has been moved into the livewire/livewire repository until it's more stable and ready to tag.

+ 0 - 36
packages/history/src/url.js

@@ -1,36 +0,0 @@
-
-export function hasQueryParam(param) {
-    let queryParams = new URLSearchParams(window.location.search);
-
-    return queryParams.has(param)
-}
-
-export function getQueryParam(param) {
-    let queryParams = new URLSearchParams(window.location.search);
-
-    return queryParams.get(param)
-}
-
-export function setQueryParam(param, value) {
-    let queryParams = new URLSearchParams(window.location.search);
-
-    queryParams.set(param, value)
-
-    let url = urlFromQueryParams(queryParams)
-
-    history.replaceState(history.state, '', url)
-}
-
-function urlFromParams(params = {}) {
-    let queryParams = new URLSearchParams(window.location.search);
-
-    Object.entries(params).forEach(([key, value]) => {
-        queryParams.set(key, value)
-    })
-
-    let queryString = Array.from(queryParams.entries()).length > 0
-        ? '?'+params.toString()
-        : ''
-
-    return window.location.origin + window.location.pathname + '?'+queryString + window.location.hash
-}

+ 0 - 156
packages/navigate/src/bar.js

@@ -1,156 +0,0 @@
-import NProgress from 'nprogress'
-
-NProgress.configure({ minimum: 0.1 });
-NProgress.configure({ trickleSpeed: 200 });
-
-injectStyles()
-
-let inProgress = false
-export function showAndStartProgressBar() {
-    inProgress = true
-    // Only show progress bar if it's been a little bit...
-    setTimeout(() => {
-        if (! inProgress) return
-        NProgress.start()
-    }, 150)
-
-    // createBar()
-
-    // incrementBar()
-}
-
-export function finishAndHideProgressBar() {
-    inProgress = false
-    NProgress.done()
-    NProgress.remove()
-
-    // finishProgressBar(); destroyBar()
-}
-
-function createBar() {
-    let bar = document.createElement('div')
-
-    bar.setAttribute('id', 'alpine-progress-bar')
-    bar.setAttribute('x-navigate:persist', 'alpine-progress-bar')
-    bar.setAttribute('style', `
-        width: 100%;
-        height: 5px;
-        background: black;
-        position: absolute;
-        top: 0;
-        left: 0;
-        right: 0;
-        transition: all 0.5s ease;
-        transform: scaleX(0);
-        transform-origin: left;
-    `)
-
-    document.body.appendChild(bar)
-
-    return bar
-}
-
-function incrementBar(goal = .1) {
-    let bar = document.getElementById('alpine-progress-bar')
-
-    if (! bar) return
-
-    let percentage = Number(bar.style.transform.match(/scaleX\((.+)\)/)[1])
-
-    if (percentage > 1) return
-
-    bar.style.transform = 'scaleX(' + goal + ')'
-
-    setTimeout(() => {
-        incrementBar(percentage + .1)
-    }, 50)
-}
-
-function finishProgressBar(callback) {
-    let bar = document.getElementById('alpine-progress-bar')
-    bar.style.transform = 'scaleX(1)'
-}
-
-function destroyBar() {
-    document.getElementById('alpine-progress-bar').remove()
-}
-
-function injectStyles() {
-    let style = document.createElement('style')
-    style.innerHTML = `/* Make clicks pass-through */
-    #nprogress {
-      pointer-events: none;
-    }
-
-    #nprogress .bar {
-    //   background: #FC70A9;
-      background: #29d;
-
-      position: fixed;
-      z-index: 1031;
-      top: 0;
-      left: 0;
-
-      width: 100%;
-      height: 2px;
-    }
-
-    /* Fancy blur effect */
-    #nprogress .peg {
-      display: block;
-      position: absolute;
-      right: 0px;
-      width: 100px;
-      height: 100%;
-      box-shadow: 0 0 10px #29d, 0 0 5px #29d;
-      opacity: 1.0;
-
-      -webkit-transform: rotate(3deg) translate(0px, -4px);
-          -ms-transform: rotate(3deg) translate(0px, -4px);
-              transform: rotate(3deg) translate(0px, -4px);
-    }
-
-    /* Remove these to get rid of the spinner */
-    #nprogress .spinner {
-      display: block;
-      position: fixed;
-      z-index: 1031;
-      top: 15px;
-      right: 15px;
-    }
-
-    #nprogress .spinner-icon {
-      width: 18px;
-      height: 18px;
-      box-sizing: border-box;
-
-      border: solid 2px transparent;
-      border-top-color: #29d;
-      border-left-color: #29d;
-      border-radius: 50%;
-
-      -webkit-animation: nprogress-spinner 400ms linear infinite;
-              animation: nprogress-spinner 400ms linear infinite;
-    }
-
-    .nprogress-custom-parent {
-      overflow: hidden;
-      position: relative;
-    }
-
-    .nprogress-custom-parent #nprogress .spinner,
-    .nprogress-custom-parent #nprogress .bar {
-      position: absolute;
-    }
-
-    @-webkit-keyframes nprogress-spinner {
-      0%   { -webkit-transform: rotate(0deg); }
-      100% { -webkit-transform: rotate(360deg); }
-    }
-    @keyframes nprogress-spinner {
-      0%   { transform: rotate(0deg); }
-      100% { transform: rotate(360deg); }
-    }
-    `
-    document.head.appendChild(style)
-}

+ 0 - 9
packages/navigate/src/bus.js

@@ -1,9 +0,0 @@
-let listeners = {}
-
-export function listen(event, callback) {
-    listeners[event] = [...(listeners[event] || []), callback]
-}
-
-export function emit(event, ...props) {
-    (listeners[event] || []).forEach(handle => handle(...props))
-}

+ 0 - 8
packages/navigate/src/fetch.js

@@ -1,8 +0,0 @@
-
-export function fetchHtml(destination, callback) {
-    let uri = destination.pathname + destination.search
-
-    fetch(uri).then(i => i.text()).then(html => {
-        callback(html)
-    })
-}

+ 0 - 79
packages/navigate/src/history.js

@@ -1,79 +0,0 @@
-
-export function updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks() {
-    // Create a history state entry for the initial page load.
-    // (This is so later hitting back can restore this page).
-    let url = new URL(window.location.href, document.baseURI)
-
-    replaceUrl(url, document.documentElement.outerHTML)
-}
-
-export function whenTheBackOrForwardButtonIsClicked(callback) {
-    window.addEventListener('popstate', e => {
-        let state = e.state || {}
-
-        let alpine = state.alpine || {}
-
-        if (! alpine._html) return
-
-        let html = fromSessionStorage(alpine._html)
-
-        callback(html)
-    })
-}
-
-export function updateUrlAndStoreLatestHtmlForFutureBackButtons(html, destination) {
-    pushUrl(destination, html)
-}
-
-export function pushUrl(url, html) {
-    updateUrl('pushState', url, html)
-}
-
-export function replaceUrl(url, html) {
-    updateUrl('replaceState', url, html)
-}
-
-function updateUrl(method, url, html) {
-    let key = (new Date).getTime()
-
-    tryToStoreInSession(key, html)
-
-    let state = history.state || {}
-
-    if (! state.alpine) state.alpine = {}
-
-    state.alpine._html = key
-
-    // 640k character limit:
-    history[method](state, document.title, url)
-}
-
-export function fromSessionStorage(timestamp) {
-    let state = JSON.parse(sessionStorage.getItem('alpine:'+timestamp))
-
-    return state
-}
-
-function tryToStoreInSession(timestamp, value) {
-    // sessionStorage has a max storage limit (usally 5MB).
-    // If we meet that limit, we'll start removing entries
-    // (oldest first), until there's enough space to store
-    // the new one.
-    try {
-        sessionStorage.setItem('alpine:'+timestamp, JSON.stringify(value))
-    } catch (error) {
-        // 22 is Chrome, 1-14 is other browsers.
-        if (! [22, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].includes(error.code)) return
-
-        let oldestTimestamp = Object.keys(sessionStorage)
-            .map(key => Number(key.replace('alpine:', '')))
-            .sort()
-            .shift()
-
-        if (! oldestTimestamp) return
-
-        sessionStorage.removeItem('alpine:'+oldestTimestamp)
-
-        tryToStoreInSession(timestamp, value)
-    }
-}

+ 1 - 244
packages/navigate/src/index.js

@@ -1,244 +1 @@
-import { updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks, updateUrlAndStoreLatestHtmlForFutureBackButtons, whenTheBackOrForwardButtonIsClicked } from "./history"
-import { getPretchedHtmlOr, prefetchHtml, storeThePrefetchedHtmlForWhenALinkIsClicked } from "./prefetch"
-import { createUrlObjectFromString, extractDestinationFromLink, whenThisLinkIsHoveredFor, whenThisLinkIsPressed } from "./links"
-import { restoreScrollPosition, storeScrollInformationInHtmlBeforeNavigatingAway } from "./scroll"
-import { putPersistantElementsBack, storePersistantElementsForLater } from "./persist"
-import { finishAndHideProgressBar, showAndStartProgressBar } from "./bar"
-import { transition } from "alpinejs/src/directives/x-transition"
-import { swapCurrentPageWithNewHtml } from "./page"
-import { fetchHtml } from "./fetch"
-import { prefix } from "alpinejs/src/directives"
-
-let enablePersist = true
-let showProgressBar = true
-let restoreScroll = true
-let autofocus = false
-
-export default function (Alpine) {
-    Alpine.navigate = (url) => {
-        navigateTo(
-            createUrlObjectFromString(url)
-        )
-    }
-
-    Alpine.navigate.disableProgressBar = () => {
-        showProgressBar = false
-    }
-
-    Alpine.addInitSelector(() => `[${prefix('navigate')}]`)
-
-    Alpine.directive('navigate', (el, { value, expression, modifiers }, { evaluateLater, cleanup }) => {
-        let shouldPrefetchOnHover = modifiers.includes('hover')
-
-        shouldPrefetchOnHover && whenThisLinkIsHoveredFor(el, 60, () => {
-            let destination = extractDestinationFromLink(el)
-
-            prefetchHtml(destination, html => {
-                storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination)
-            })
-        })
-
-        whenThisLinkIsPressed(el, (whenItIsReleased) => {
-            let destination = extractDestinationFromLink(el)
-
-            prefetchHtml(destination, html => {
-                storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination)
-            })
-
-            whenItIsReleased(() => {
-                navigateTo(destination)
-            })
-        })
-    })
-
-    function navigateTo(destination) {
-        showProgressBar && showAndStartProgressBar()
-
-        fetchHtmlOrUsePrefetchedHtml(destination, html => {
-            fireEventForOtherLibariesToHookInto('alpine:navigating')
-
-            restoreScroll && storeScrollInformationInHtmlBeforeNavigatingAway()
-
-            showProgressBar && finishAndHideProgressBar()
-
-            updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks()
-
-            preventAlpineFromPickingUpDomChanges(Alpine, andAfterAllThis => {
-                enablePersist && storePersistantElementsForLater()
-
-                swapCurrentPageWithNewHtml(html, () => {
-                    enablePersist && putPersistantElementsBack()
-
-                    restoreScroll && restoreScrollPosition()
-
-                    fireEventForOtherLibariesToHookInto('alpine:navigated')
-
-                    updateUrlAndStoreLatestHtmlForFutureBackButtons(html, destination)
-
-                    andAfterAllThis(() => {
-                        autofocus && autofocusElementsWithTheAutofocusAttribute()
-
-                        nowInitializeAlpineOnTheNewPage(Alpine)
-                    })
-                })
-            })
-        })
-    }
-
-    whenTheBackOrForwardButtonIsClicked((html) => {
-        // @todo: see if there's a way to update the current HTML BEFORE
-        // the back button is hit, and not AFTER:
-        storeScrollInformationInHtmlBeforeNavigatingAway()
-        // updateCurrentPageHtmlInHistoryStateForLaterBackButtonClicks()
-
-        preventAlpineFromPickingUpDomChanges(Alpine, andAfterAllThis => {
-            enablePersist && storePersistantElementsForLater()
-
-            swapCurrentPageWithNewHtml(html, andThen => {
-                enablePersist && putPersistantElementsBack()
-
-                restoreScroll && restoreScrollPosition()
-
-                fireEventForOtherLibariesToHookInto('alpine:navigated')
-
-                andAfterAllThis(() => {
-                    autofocus && autofocusElementsWithTheAutofocusAttribute()
-
-                    nowInitializeAlpineOnTheNewPage(Alpine)
-                })
-            })
-
-        })
-    })
-
-    // Because DOMContentLoaded is fired on first load,
-    // we should fire alpine:navigated as a replacement as well...
-    setTimeout(() => {
-        fireEventForOtherLibariesToHookInto('alpine:navigated', true)
-    })
-}
-
-function fetchHtmlOrUsePrefetchedHtml(fromDestination, callback) {
-    getPretchedHtmlOr(fromDestination, callback, () => {
-        fetchHtml(fromDestination, callback)
-    })
-}
-
-function preventAlpineFromPickingUpDomChanges(Alpine, callback) {
-    Alpine.stopObservingMutations()
-
-    callback((afterAllThis) => {
-        Alpine.startObservingMutations()
-
-        setTimeout(() => {
-            afterAllThis()
-        })
-    })
-}
-
-function fireEventForOtherLibariesToHookInto(eventName, init = false) {
-    document.dispatchEvent(new CustomEvent(eventName, { bubbles: true, detail: { init } }))
-}
-
-function nowInitializeAlpineOnTheNewPage(Alpine) {
-    Alpine.initTree(document.body, undefined, (el, skip) => {
-        if (el._x_wasPersisted) skip()
-    })
-}
-
-function autofocusElementsWithTheAutofocusAttribute() {
-    document.querySelector('[autofocus]') && document.querySelector('[autofocus]').focus()
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-    // Alpine.magic('history', (el, { interceptor }) =>  {
-    //     let alias
-
-    //     return interceptor((initialValue, getter, setter, path, key) => {
-    //         let pause = false
-    //         let queryKey = alias || path
-
-    //         let value = initialValue
-    //         let url = new URL(window.location.href)
-
-    //         if (url.searchParams.has(queryKey)) {
-    //             value = url.searchParams.get(queryKey)
-    //         }
-
-    //         setter(value)
-
-    //         let object = { value }
-
-    //         url.searchParams.set(queryKey, value)
-
-    //         replace(url.toString(), path, object)
-
-    //         window.addEventListener('popstate', (e) => {
-    //             if (! e.state) return
-    //             if (! e.state.alpine) return
-
-    //             Object.entries(e.state.alpine).forEach(([newKey, { value }]) => {
-    //                 if (newKey !== key) return
-
-    //                 pause = true
-
-    //                 Alpine.disableEffectScheduling(() => {
-    //                     setter(value)
-    //                 })
-
-    //                 pause = false
-    //             })
-    //         })
-
-    //         Alpine.effect(() => {
-    //             let value = getter()
-
-    //             if (pause) return
-
-    //             let object = { value }
-
-    //             let url = new URL(window.location.href)
-
-    //             url.searchParams.set(queryKey, value)
-
-    //             push(url.toString(), path, object)
-    //         })
-
-    //         return value
-    //     }, func => {
-    //         func.as = key => { alias = key; return func }
-    //     })
-    // })
-// }
-
-
-
-// function replace(url, key, object) {
-//     let state = window.history.state || {}
-
-//     if (! state.alpine) state.alpine = {}
-
-//     state.alpine[key] = object
-
-//     window.history.replaceState(state, '', url)
-// }
-
-// function push(url, key, object) {
-//     let state = { alpine: {...window.history.state.alpine, ...{[key]: object}} }
-
-//     window.history.pushState(state, '', url)
-// }
+// This plugin has been moved into the livewire/livewire repository until it's more stable and ready to tag.

+ 0 - 54
packages/navigate/src/links.js

@@ -1,54 +0,0 @@
-
-export function whenThisLinkIsClicked(el, callback) {
-    el.addEventListener('click', e => {
-        e.preventDefault()
-
-        callback(el)
-    })
-}
-
-export function whenThisLinkIsPressed(el, callback) {
-    el.addEventListener('click', e => e.preventDefault())
-
-    el.addEventListener('mousedown', e => {
-        if (e.button !== 0) return; // Only on left click...
-
-        e.preventDefault()
-
-        callback((whenReleased) => {
-            let handler = e => {
-                e.preventDefault()
-
-                whenReleased()
-
-                el.removeEventListener('mouseup', handler)
-            }
-
-            el.addEventListener('mouseup', handler)
-        })
-    })
-}
-
-export function whenThisLinkIsHoveredFor(el, ms = 60, callback) {
-    el.addEventListener('mouseenter', e => {
-        let timeout = setTimeout(() => {
-
-        }, ms)
-
-        let handler = () => {
-            clear
-            el.removeEventListener('mouseleave', handler)
-        }
-
-        el.addEventListener('mouseleave', handler)
-        callback(e)
-    })
-}
-
-export function extractDestinationFromLink(linkEl) {
-    return createUrlObjectFromString(linkEl.getAttribute('href'))
-}
-
-export function createUrlObjectFromString(urlString) {
-    return new URL(urlString, document.baseURI)
-}

+ 0 - 156
packages/navigate/src/page.js

@@ -1,156 +0,0 @@
-import Alpine from "alpinejs/src/alpine"
-
-let oldBodyScriptTagHashes = []
-
-export function swapCurrentPageWithNewHtml(html, andThen) {
-    let newDocument = (new DOMParser()).parseFromString(html, "text/html")
-    let newBody = document.adoptNode(newDocument.body)
-    let newHead = document.adoptNode(newDocument.head)
-
-    oldBodyScriptTagHashes = oldBodyScriptTagHashes.concat(Array.from(document.body.querySelectorAll('script')).map(i => simpleHash(i.outerHTML)))
-
-    mergeNewHead(newHead)
-
-    prepNewBodyScriptTagsToRun(newBody, oldBodyScriptTagHashes)
-
-    transitionOut(document.body)
-
-    // @todo: only setTimeout when applying transitions
-    // setTimeout(() => {
-        let oldBody = document.body
-
-        document.body.replaceWith(newBody)
-
-        Alpine.destroyTree(oldBody)
-
-        transitionIn(newBody)
-
-        andThen()
-    // }, 0)
-}
-
-function transitionOut(body) {
-    return;
-    body.style.transition = 'all .5s ease'
-    body.style.opacity = '0'
-}
-
-function transitionIn(body) {
-    return;
-    body.style.opacity = '0'
-    body.style.transition = 'all .5s ease'
-
-    requestAnimationFrame(() => {
-        body.style.opacity = '1'
-    })
-}
-
-function prepNewBodyScriptTagsToRun(newBody, oldBodyScriptTagHashes) {
-    newBody.querySelectorAll('script').forEach(i => {
-        // We don't want to re-run script tags marked as "data-navigate-once"...
-        if (i.hasAttribute('data-navigate-once')) {
-            // However, if they didn't exist on the previous page, we do.
-            // Therefore, we'll check the "old body script hashes" to
-            // see if it was already there before skipping it...
-            let hash = simpleHash(i.outerHTML)
-
-            if (oldBodyScriptTagHashes.includes(hash)) return
-        }
-
-        i.replaceWith(cloneScriptTag(i))
-    })
-}
-
-function mergeNewHead(newHead) {
-    let children = Array.from(document.head.children)
-    let headChildrenHtmlLookup = children.map(i => i.outerHTML)
-
-    // Only add scripts and styles that aren't already loaded on the page.
-    let garbageCollector = document.createDocumentFragment()
-
-    for (let child of Array.from(newHead.children)) {
-        if (isAsset(child)) {
-            if (! headChildrenHtmlLookup.includes(child.outerHTML)) {
-                if (isTracked(child)) {
-                    if (ifTheQueryStringChangedSinceLastRequest(child, children)) {
-                        setTimeout(() => window.location.reload())
-                    }
-                }
-
-                if (isScript(child)) {
-                    document.head.appendChild(cloneScriptTag(child))
-                } else {
-                    document.head.appendChild(child)
-                }
-            } else {
-                garbageCollector.appendChild(child)
-            }
-        }
-    }
-
-    // How to free up the garbage collector?
-
-    // Remove existing non-asset elements like meta, base, title, template.
-    for (let child of Array.from(document.head.children)) {
-        if (! isAsset(child)) child.remove()
-    }
-
-    // Add new non-asset elements left over in the new head element.
-    for (let child of Array.from(newHead.children)) {
-        document.head.appendChild(child)
-    }
-}
-
-function cloneScriptTag(el) {
-    let script = document.createElement('script')
-
-    script.textContent = el.textContent
-    script.async = el.async
-
-    for (let attr of el.attributes) {
-        script.setAttribute(attr.name, attr.value)
-    }
-
-    return script
-}
-
-function isTracked(el) {
-    return el.hasAttribute('data-navigate-track')
-}
-
-function ifTheQueryStringChangedSinceLastRequest(el, currentHeadChildren) {
-    let [uri, queryString] = extractUriAndQueryString(el)
-
-    return currentHeadChildren.some(child => {
-        if (! isTracked(child)) return false
-
-        let [currentUri, currentQueryString] = extractUriAndQueryString(child)
-
-        // Only consider a data-navigate-track element changed if the query string has changed (not the URI)...
-        if (currentUri === uri && queryString !== currentQueryString) return true
-    })
-}
-
-function extractUriAndQueryString(el) {
-    let url = isScript(el) ? el.src : el.href
-
-    return url.split('?')
-}
-
-function isAsset(el) {
-    return (el.tagName.toLowerCase() === 'link' && el.getAttribute('rel').toLowerCase() === 'stylesheet')
-        || el.tagName.toLowerCase() === 'style'
-        || el.tagName.toLowerCase() === 'script'
-}
-
-function isScript(el)   {
-    return el.tagName.toLowerCase() === 'script'
-}
-
-function simpleHash(str) {
-    return str.split('').reduce((a, b) => {
-        a = ((a << 5) - a) + b.charCodeAt(0)
-
-        return a & a
-    }, 0);
-}

+ 0 - 30
packages/navigate/src/persist.js

@@ -1,30 +0,0 @@
-import Alpine from "alpinejs/src/alpine"
-
-let els = {}
-
-export function storePersistantElementsForLater() {
-    els = {}
-
-    document.querySelectorAll('[x-persist]').forEach(i => {
-        els[i.getAttribute('x-persist')] = i
-
-        Alpine.mutateDom(() => {
-            i.remove()
-        })
-    })
-}
-
-export function putPersistantElementsBack() {
-    document.querySelectorAll('[x-persist]').forEach(i => {
-        let old = els[i.getAttribute('x-persist')]
-
-        // There might be a brand new x-persist element...
-        if (! old) return
-
-        old._x_wasPersisted = true
-
-        Alpine.mutateDom(() => {
-            i.replaceWith(old)
-        })
-    })
-}

+ 0 - 45
packages/navigate/src/prefetch.js

@@ -1,45 +0,0 @@
-
-// Warning: this could cause some memory leaks
-let prefetches = {}
-
-export function prefetchHtml(destination, callback) {
-    let path = destination.pathname
-
-    if (prefetches[path]) return
-
-    prefetches[path] = { finished: false, html: null, whenFinished: () => {} }
-
-    fetch(path).then(i => i.text()).then(html => {
-        callback(html)
-    })
-}
-
-export function storeThePrefetchedHtmlForWhenALinkIsClicked(html, destination) {
-    let state = prefetches[destination.pathname]
-    state.html = html
-    state.finished = true
-    state.whenFinished()
-}
-
-export function getPretchedHtmlOr(destination, receive, ifNoPrefetchExists) {
-    let uri = destination.pathname + destination.search
-
-    if (! prefetches[uri]) return ifNoPrefetchExists()
-
-    if (prefetches[uri].finished) {
-        let html = prefetches[uri].html
-
-        delete prefetches[uri]
-
-        return receive(html)
-    } else {
-        prefetches[uri].whenFinished = () => {
-            let html = prefetches[uri].html
-
-            delete prefetches[uri]
-
-            receive(html)
-        }
-    }
-}
-

+ 0 - 24
packages/navigate/src/scroll.js

@@ -1,24 +0,0 @@
-
-export function storeScrollInformationInHtmlBeforeNavigatingAway() {
-    document.body.setAttribute('data-scroll-x', document.body.scrollLeft)
-    document.body.setAttribute('data-scroll-y', document.body.scrollTop)
-
-    document.querySelectorAll(['[x-navigate\\:scroll]', '[wire\\:scroll]']).forEach(el => {
-        el.setAttribute('data-scroll-x', el.scrollLeft)
-        el.setAttribute('data-scroll-y', el.scrollTop)
-    })
-}
-
-export function restoreScrollPosition() {
-    let scroll = el => {
-        el.scrollTo(Number(el.getAttribute('data-scroll-x')), Number(el.getAttribute('data-scroll-y')))
-        el.removeAttribute('data-scroll-x')
-        el.removeAttribute('data-scroll-y')
-    }
-
-    queueMicrotask(() => {
-        scroll(document.body)
-
-        document.querySelectorAll(['[x-navigate\\:scroll]', '[wire\\:scroll]']).forEach(scroll)
-    })
-}

+ 0 - 1
packages/ui/demo/listbox/data-driven.html

@@ -11,7 +11,6 @@
 
     <script src="/packages/intersect/dist/cdn.js" defer></script>
     <script src="/packages/morph/dist/cdn.js" defer></script>
-    <script src="/packages/history/dist/cdn.js"></script>
     <script src="/packages/persist/dist/cdn.js"></script>
     <script src="/packages/focus/dist/cdn.js"></script>
     <script src="/packages/mask/dist/cdn.js"></script>

+ 0 - 1
packages/ui/demo/listbox/index.html

@@ -11,7 +11,6 @@
 
     <script src="/packages/intersect/dist/cdn.js" defer></script>
     <script src="/packages/morph/dist/cdn.js" defer></script>
-    <script src="/packages/history/dist/cdn.js"></script>
     <script src="/packages/persist/dist/cdn.js"></script>
     <script src="/packages/focus/dist/cdn.js"></script>
     <script src="/packages/mask/dist/cdn.js"></script>

+ 0 - 1
packages/ui/demo/listbox/multiple.html

@@ -11,7 +11,6 @@
 
     <script src="/packages/intersect/dist/cdn.js" defer></script>
     <script src="/packages/morph/dist/cdn.js" defer></script>
-    <script src="/packages/history/dist/cdn.js"></script>
     <script src="/packages/persist/dist/cdn.js"></script>
     <script src="/packages/focus/dist/cdn.js"></script>
     <script src="/packages/mask/dist/cdn.js"></script>

+ 2 - 2
scripts/build.js

@@ -6,14 +6,14 @@ let zlib = require('zlib');
     // Packages:
     'alpinejs',
     'csp',
-    'history',
+    // 'history', - removed because this plugin has been moved to livewire/livewire until it's stable...
+    // 'navigate', - remove because this plugin has been moved to livewire/livewire until it's stable...
     'intersect',
     'persist',
     'collapse',
     'morph',
     'focus',
     'mask',
-    'navigate',
     'ui',
 ]).forEach(package => {
     if (! fs.existsSync(`./packages/${package}/dist`)) {

+ 219 - 215
tests/cypress/integration/plugins/history.spec.js

@@ -1,217 +1,221 @@
 import { haveText, html, test } from '../../utils'
 
-test('value is reflected in query string upon changing',
-    [html`
-        <div x-data="{ count: $queryString(1) }">
-            <button @click="count++">Inc</button>
-            <h1 @click="count--">Dec</h1>
-            <span x-text="count"></span>
-        </div>
-    `],
-    ({ get, url, go }) => {
-        get('span').should(haveText('1'))
-        url().should('not.include', '?count=1')
-        get('button').click()
-        get('span').should(haveText('2'))
-        url().should('include', '?count=2')
-        get('button').click()
-        get('span').should(haveText('3'))
-        url().should('include', '?count=3')
-        get('h1').click()
-        get('h1').click()
-        get('span').should(haveText('1'))
-        url().should('not.include', '?count=1')
-    },
-)
-
-test('can configure always making the query string value present',
-    [html`
-        <div x-data="{ count: $queryString(1).alwaysShow() }">
-            <button @click="count++">Inc</button>
-            <h1 @click="count--">Dec</h1>
-            <span x-text="count"></span>
-        </div>
-    `],
-    ({ get, url, go }) => {
-        get('span').should(haveText('1'))
-        url().should('include', '?count=1')
-        get('button').click()
-        get('span').should(haveText('2'))
-        url().should('include', '?count=2')
-        get('h1').click()
-        get('span').should(haveText('1'))
-        url().should('include', '?count=1')
-    },
-)
-
-test('value is persisted across requests',
-    [html`
-        <div x-data="{ count: $queryString(1) }">
-            <button @click="count++">Inc</button>
-            <span x-text="count"></span>
-        </div>
-    `],
-    ({ get, url, go }, reload) => {
-        get('span').should(haveText('1'))
-        url().should('not.include', '?count=1')
-        get('button').click()
-        get('span').should(haveText('2'))
-        url().should('include', '?count=2')
-
-        reload()
-
-        url().should('include', '?count=2')
-        get('span').should(haveText('2'))
-    },
-)
-
-test('can provide an alias',
-    [html`
-        <div x-data="{ count: $queryString(1).as('tnuoc') }">
-            <button @click="count++">Inc</button>
-            <span x-text="count"></span>
-        </div>
-    `],
-    ({ get, url, go }) => {
-        get('span').should(haveText('1'))
-        url().should('not.include', '?tnuoc=1')
-        get('button').click()
-        get('span').should(haveText('2'))
-        url().should('include', '?tnuoc=2')
-    },
-)
-
-test('can use pushState',
-    [html`
-        <div x-data="{ count: $queryString(1).usePush() }">
-            <button @click="count++">Inc</button>
-            <span x-text="count"></span>
-        </div>
-    `],
-    ({ get, url, go }) => {
-        get('span').should(haveText('1'))
-        url().should('not.include', '?count=1')
-        get('button').click()
-        get('span').should(haveText('2'))
-        url().should('include', '?count=2')
-        go('back')
-        get('span').should(haveText('1'))
-        url().should('not.include', '?count=1')
-        go('forward')
-        get('span').should(haveText('2'))
-        url().should('include', '?count=2')
-    },
-)
-
-test('can go back and forth with multiple components',
-    [html`
-        <div x-data="{ foo: $queryString(1).usePush() }" id="foo">
-            <button @click="foo++">Inc</button>
-            <span x-text="foo"></span>
-        </div>
-
-        <div x-data="{ bar: $queryString(1).usePush() }" id="bar">
-            <button @click="bar++">Inc</button>
-            <span x-text="bar"></span>
-        </div>
-    `],
-    ({ get, url, go }) => {
-        get('#foo span').should(haveText('1'))
-        url().should('not.include', 'foo=1')
-        get('#foo button').click()
-        get('#foo span').should(haveText('2'))
-        url().should('include', 'foo=2')
-
-        get('#bar span').should(haveText('1'))
-        url().should('not.include', 'bar=1')
-        get('#bar button').click()
-        get('#bar span').should(haveText('2'))
-        url().should('include', 'bar=2')
-
-        go('back')
-
-        get('#bar span').should(haveText('1'))
-        url().should('not.include', 'bar=1')
-        get('#foo span').should(haveText('2'))
-        url().should('include', 'foo=2')
-
-        go('back')
-
-        get('#bar span').should(haveText('1'))
-        url().should('not.include', 'bar=1')
-        get('#foo span').should(haveText('1'))
-        url().should('not.include', 'foo=1')
-    },
-)
-
-test('supports arrays',
-    [html`
-        <div x-data="{ items: $queryString(['foo']) }">
-            <button @click="items.push('bar')">Inc</button>
-            <span x-text="JSON.stringify(items)"></span>
-        </div>
-    `],
-    ({ get, url, go }, reload) => {
-        get('span').should(haveText('["foo"]'))
-        url().should('not.include', '?items')
-        get('button').click()
-        get('span').should(haveText('["foo","bar"]'))
-        url().should('include', '?items[0]=foo&items[1]=bar')
-        reload()
-        url().should('include', '?items[0]=foo&items[1]=bar')
-        get('span').should(haveText('["foo","bar"]'))
-    },
-)
-
-test('supports deep arrays',
-    [html`
-        <div x-data="{ items: $queryString(['foo', ['bar', 'baz']]) }">
-            <button @click="items[1].push('bob')">Inc</button>
-            <span x-text="JSON.stringify(items)"></span>
-        </div>
-    `],
-    ({ get, url, go }, reload) => {
-        get('span').should(haveText('["foo",["bar","baz"]]'))
-        url().should('not.include', '?items')
-        get('button').click()
-        get('span').should(haveText('["foo",["bar","baz","bob"]]'))
-        url().should('include', '?items[0]=foo&items[1][0]=bar&items[1][1]=baz&items[1][2]=bob')
-        reload()
-        url().should('include', '?items[0]=foo&items[1][0]=bar&items[1][1]=baz&items[1][2]=bob')
-        get('span').should(haveText('["foo",["bar","baz","bob"]]'))
-    },
-)
-
-test('supports objects',
-    [html`
-        <div x-data="{ items: $queryString({ foo: 'bar' }) }">
-            <button @click="items.bob = 'lob'">Inc</button>
-            <span x-text="JSON.stringify(items)"></span>
-        </div>
-    `],
-    ({ get, url, go }, reload) => {
-        get('span').should(haveText('{"foo":"bar"}'))
-        url().should('not.include', '?items')
-        get('button').click()
-        get('span').should(haveText('{"foo":"bar","bob":"lob"}'))
-        url().should('include', '?items[foo]=bar&items[bob]=lob')
-        reload()
-        url().should('include', '?items[foo]=bar&items[bob]=lob')
-        get('span').should(haveText('{"foo":"bar","bob":"lob"}'))
-    },
-)
-
-test('encodes values according to RFC 1738 (plus signs for spaces)',
-    [html`
-        <div x-data="{ foo: $queryString('hey&there').alwaysShow(), bar: $queryString('hey there').alwaysShow() }">
-            <span x-text="JSON.stringify(foo)+JSON.stringify(bar)"></span>
-        </div>
-    `],
-    ({ get, url, go }, reload) => {
-        url().should('include', '?foo=hey%26there&bar=hey+there')
-        get('span').should(haveText('"hey&there""hey there"'))
-        reload()
-        url().should('include', '?foo=hey%26there&bar=hey+there')
-        get('span').should(haveText('"hey&there""hey there"'))
-    },
-)
+// Skipping these tests because the plugin has been moved to livewire/livewire until it's stablhese tests because the plugin has been moved to livewire/livewire until it's stable...
+describe.skip('History tests', function () {
+    test('value is reflected in query string upon changing',
+        [html`
+            <div x-data="{ count: $queryString(1) }">
+                <button @click="count++">Inc</button>
+                <h1 @click="count--">Dec</h1>
+                <span x-text="count"></span>
+            </div>
+        `],
+        ({ get, url, go }) => {
+            get('span').should(haveText('1'))
+            url().should('not.include', '?count=1')
+            get('button').click()
+            get('span').should(haveText('2'))
+            url().should('include', '?count=2')
+            get('button').click()
+            get('span').should(haveText('3'))
+            url().should('include', '?count=3')
+            get('h1').click()
+            get('h1').click()
+            get('span').should(haveText('1'))
+            url().should('not.include', '?count=1')
+        },
+    )
+
+    test('can configure always making the query string value present',
+        [html`
+            <div x-data="{ count: $queryString(1).alwaysShow() }">
+                <button @click="count++">Inc</button>
+                <h1 @click="count--">Dec</h1>
+                <span x-text="count"></span>
+            </div>
+        `],
+        ({ get, url, go }) => {
+            get('span').should(haveText('1'))
+            url().should('include', '?count=1')
+            get('button').click()
+            get('span').should(haveText('2'))
+            url().should('include', '?count=2')
+            get('h1').click()
+            get('span').should(haveText('1'))
+            url().should('include', '?count=1')
+        },
+    )
+
+    test('value is persisted across requests',
+        [html`
+            <div x-data="{ count: $queryString(1) }">
+                <button @click="count++">Inc</button>
+                <span x-text="count"></span>
+            </div>
+        `],
+        ({ get, url, go }, reload) => {
+            get('span').should(haveText('1'))
+            url().should('not.include', '?count=1')
+            get('button').click()
+            get('span').should(haveText('2'))
+            url().should('include', '?count=2')
+
+            reload()
+
+            url().should('include', '?count=2')
+            get('span').should(haveText('2'))
+        },
+    )
+
+    test('can provide an alias',
+        [html`
+            <div x-data="{ count: $queryString(1).as('tnuoc') }">
+                <button @click="count++">Inc</button>
+                <span x-text="count"></span>
+            </div>
+        `],
+        ({ get, url, go }) => {
+            get('span').should(haveText('1'))
+            url().should('not.include', '?tnuoc=1')
+            get('button').click()
+            get('span').should(haveText('2'))
+            url().should('include', '?tnuoc=2')
+        },
+    )
+
+    test('can use pushState',
+        [html`
+            <div x-data="{ count: $queryString(1).usePush() }">
+                <button @click="count++">Inc</button>
+                <span x-text="count"></span>
+            </div>
+        `],
+        ({ get, url, go }) => {
+            get('span').should(haveText('1'))
+            url().should('not.include', '?count=1')
+            get('button').click()
+            get('span').should(haveText('2'))
+            url().should('include', '?count=2')
+            go('back')
+            get('span').should(haveText('1'))
+            url().should('not.include', '?count=1')
+            go('forward')
+            get('span').should(haveText('2'))
+            url().should('include', '?count=2')
+        },
+    )
+
+    test('can go back and forth with multiple components',
+        [html`
+            <div x-data="{ foo: $queryString(1).usePush() }" id="foo">
+                <button @click="foo++">Inc</button>
+                <span x-text="foo"></span>
+            </div>
+
+            <div x-data="{ bar: $queryString(1).usePush() }" id="bar">
+                <button @click="bar++">Inc</button>
+                <span x-text="bar"></span>
+            </div>
+        `],
+        ({ get, url, go }) => {
+            get('#foo span').should(haveText('1'))
+            url().should('not.include', 'foo=1')
+            get('#foo button').click()
+            get('#foo span').should(haveText('2'))
+            url().should('include', 'foo=2')
+
+            get('#bar span').should(haveText('1'))
+            url().should('not.include', 'bar=1')
+            get('#bar button').click()
+            get('#bar span').should(haveText('2'))
+            url().should('include', 'bar=2')
+
+            go('back')
+
+            get('#bar span').should(haveText('1'))
+            url().should('not.include', 'bar=1')
+            get('#foo span').should(haveText('2'))
+            url().should('include', 'foo=2')
+
+            go('back')
+
+            get('#bar span').should(haveText('1'))
+            url().should('not.include', 'bar=1')
+            get('#foo span').should(haveText('1'))
+            url().should('not.include', 'foo=1')
+        },
+    )
+
+    test('supports arrays',
+        [html`
+            <div x-data="{ items: $queryString(['foo']) }">
+                <button @click="items.push('bar')">Inc</button>
+                <span x-text="JSON.stringify(items)"></span>
+            </div>
+        `],
+        ({ get, url, go }, reload) => {
+            get('span').should(haveText('["foo"]'))
+            url().should('not.include', '?items')
+            get('button').click()
+            get('span').should(haveText('["foo","bar"]'))
+            url().should('include', '?items[0]=foo&items[1]=bar')
+            reload()
+            url().should('include', '?items[0]=foo&items[1]=bar')
+            get('span').should(haveText('["foo","bar"]'))
+        },
+    )
+
+    test('supports deep arrays',
+        [html`
+            <div x-data="{ items: $queryString(['foo', ['bar', 'baz']]) }">
+                <button @click="items[1].push('bob')">Inc</button>
+                <span x-text="JSON.stringify(items)"></span>
+            </div>
+        `],
+        ({ get, url, go }, reload) => {
+            get('span').should(haveText('["foo",["bar","baz"]]'))
+            url().should('not.include', '?items')
+            get('button').click()
+            get('span').should(haveText('["foo",["bar","baz","bob"]]'))
+            url().should('include', '?items[0]=foo&items[1][0]=bar&items[1][1]=baz&items[1][2]=bob')
+            reload()
+            url().should('include', '?items[0]=foo&items[1][0]=bar&items[1][1]=baz&items[1][2]=bob')
+            get('span').should(haveText('["foo",["bar","baz","bob"]]'))
+        },
+    )
+
+    test('supports objects',
+        [html`
+            <div x-data="{ items: $queryString({ foo: 'bar' }) }">
+                <button @click="items.bob = 'lob'">Inc</button>
+                <span x-text="JSON.stringify(items)"></span>
+            </div>
+        `],
+        ({ get, url, go }, reload) => {
+            get('span').should(haveText('{"foo":"bar"}'))
+            url().should('not.include', '?items')
+            get('button').click()
+            get('span').should(haveText('{"foo":"bar","bob":"lob"}'))
+            url().should('include', '?items[foo]=bar&items[bob]=lob')
+            reload()
+            url().should('include', '?items[foo]=bar&items[bob]=lob')
+            get('span').should(haveText('{"foo":"bar","bob":"lob"}'))
+        },
+    )
+
+    test('encodes values according to RFC 1738 (plus signs for spaces)',
+        [html`
+            <div x-data="{ foo: $queryString('hey&there').alwaysShow(), bar: $queryString('hey there').alwaysShow() }">
+                <span x-text="JSON.stringify(foo)+JSON.stringify(bar)"></span>
+            </div>
+        `],
+        ({ get, url, go }, reload) => {
+            url().should('include', '?foo=hey%26there&bar=hey+there')
+            get('span').should(haveText('"hey&there""hey there"'))
+            reload()
+            url().should('include', '?foo=hey%26there&bar=hey+there')
+            get('span').should(haveText('"hey&there""hey there"'))
+        },
+    )
+})
+

+ 157 - 161
tests/cypress/integration/plugins/navigate.spec.js

@@ -1,163 +1,159 @@
 import { beEqualTo, beVisible, haveAttribute, haveFocus, haveText, html, notBeVisible, test } from '../../utils'
 
-// Test persistent piece of layout
-// Handle non-origin links and such
-// Handle 404
-// Middle/command click link in new tab works?
-// Infinite scroll scenario, back button works
-//
-
-it.skip('navigates pages without reload',
-    () => {
-        cy.intercept('/first', {
-            headers: { 'content-type': 'text/html' },
-            body: html`
-                <html>
-                    <head>
-                        <script src="/../../packages/navigate/dist/cdn.js" defer></script>
-                        <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
-                    </head>
-                    <body>
-                        <a href="/second">Navigate</a>
-
-                        <h2>First Page</h2>
-
-                        <script>
-                            window.fromFirstPage = true
-                        </script>
-                    </body>
-                </html>
-        `})
-
-        cy.intercept('/second', {
-            headers: { 'content-type': 'text/html' },
-            body: html`
-                <html>
-                    <head>
-                        <script src="/../../packages/navigate/dist/cdn.js" defer></script>
-                        <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
-                    </head>
-                    <body>
-                        <h2>Second Page</h2>
-                    </body>
-                </html>
-        `})
-
-        cy.visit('/first')
-        cy.window().its('fromFirstPage').should(beEqualTo(true))
-        cy.get('h2').should(haveText('First Page'))
-
-        cy.get('a').click()
-
-        cy.url().should('include', '/second')
-        cy.get('h2').should(haveText('Second Page'))
-        cy.window().its('fromFirstPage').should(beEqualTo(true))
-    },
-)
-
-it.skip('autofocuses autofocus elements',
-    () => {
-        cy.intercept('/first', {
-            headers: { 'content-type': 'text/html' },
-            body: html`
-                <html>
-                    <head>
-                        <script src="/../../packages/navigate/dist/cdn.js" defer></script>
-                        <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
-                    </head>
-                    <body>
-                        <a href="/second">Navigate</a>
-                    </body>
-                </html>
-        `})
-
-        cy.intercept('/second', {
-            headers: { 'content-type': 'text/html' },
-            body: html`
-                <html>
-                    <head>
-                        <script src="/../../packages/navigate/dist/cdn.js" defer></script>
-                        <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
-                    </head>
-                    <body>
-                        <input type="text" autofocus>
-                    </body>
-                </html>
-        `})
-
-        cy.visit('/first')
-
-        cy.get('a').click()
-
-        cy.url().should('include', '/second')
-        cy.get('input').should(haveFocus())
-    },
-)
-
-it.skip('scripts and styles are properly merged/run or skipped',
-    () => {
-        cy.intercept('/first', {
-            headers: { 'content-type': 'text/html' },
-            body: html`
-                <html>
-                    <head>
-                        <title>First Page</title>
-                        <meta name="description" content="first description">
-                        <script src="/../../packages/navigate/dist/cdn.js" defer></script>
-                        <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
-                    </head>
-                    <body>
-                        <a href="/second">Navigate</a>
-                    </body>
-                </html>
-        `})
-
-        cy.intercept('/head-script.js', {
-            headers: { 'content-type': 'text/js' },
-            body: `window.fromHeadScript = true`
-        })
-
-        cy.intercept('/body-script.js', {
-            headers: { 'content-type': 'text/js' },
-            body: `window.fromBodyScript = true`
-        })
-
-        cy.intercept('/head-style.css', {
-            headers: { 'content-type': 'text/css' },
-            body: `body { background: black !important; }`
-        })
-
-        cy.intercept('/second', {
-            headers: { 'content-type': 'text/html' },
-            body: html`
-                <html>
-                    <head>
-                        <title>Second Page</title>
-                        <meta name="description" content="second description">
-                        <script src="/../../packages/navigate/dist/cdn.js" defer></script>
-                        <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
-                        <script src="head-script.js" defer></script>
-                        <script>window.fromHeadScriptInline = true</script>
-                        <link rel="stylesheet" src="head-style.css"></script>
-                    </head>
-                    <body>
-                        <script src="body-script.js" defer></script>
-                        <script>window.fromBodyScriptInline = true</script>
-                    </body>
-                </html>
-        `})
-
-        cy.visit('/first')
-
-        cy.get('a').click()
-
-        cy.url().should('include', '/second')
-        cy.title().should(beEqualTo('Second Page'))
-        cy.get('meta').should(haveAttribute('name', 'description'))
-        cy.get('meta').should(haveAttribute('content', 'second description'))
-        cy.window().its('fromHeadScript').should(beEqualTo(true))
-        cy.window().its('fromHeadScriptInline').should(beEqualTo(true))
-        cy.window().its('fromBodyScript').should(beEqualTo(true))
-        cy.window().its('fromBodyScriptInline').should(beEqualTo(true))
-    },
-)
+// Skipping these tests because the plugin has been moved to livewire/livewire until it's stablhese tests because the plugin has been moved to livewire/livewire until it's stable...
+describe.skip('Navigate tests', function () {
+    it.skip('navigates pages without reload',
+        () => {
+            cy.intercept('/first', {
+                headers: { 'content-type': 'text/html' },
+                body: html`
+                    <html>
+                        <head>
+                            <script src="/../../packages/navigate/dist/cdn.js" defer></script>
+                            <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
+                        </head>
+                        <body>
+                            <a href="/second">Navigate</a>
+
+                            <h2>First Page</h2>
+
+                            <script>
+                                window.fromFirstPage = true
+                            </script>
+                        </body>
+                    </html>
+            `})
+
+            cy.intercept('/second', {
+                headers: { 'content-type': 'text/html' },
+                body: html`
+                    <html>
+                        <head>
+                            <script src="/../../packages/navigate/dist/cdn.js" defer></script>
+                            <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
+                        </head>
+                        <body>
+                            <h2>Second Page</h2>
+                        </body>
+                    </html>
+            `})
+
+            cy.visit('/first')
+            cy.window().its('fromFirstPage').should(beEqualTo(true))
+            cy.get('h2').should(haveText('First Page'))
+
+            cy.get('a').click()
+
+            cy.url().should('include', '/second')
+            cy.get('h2').should(haveText('Second Page'))
+            cy.window().its('fromFirstPage').should(beEqualTo(true))
+        },
+    )
+
+    it.skip('autofocuses autofocus elements',
+        () => {
+            cy.intercept('/first', {
+                headers: { 'content-type': 'text/html' },
+                body: html`
+                    <html>
+                        <head>
+                            <script src="/../../packages/navigate/dist/cdn.js" defer></script>
+                            <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
+                        </head>
+                        <body>
+                            <a href="/second">Navigate</a>
+                        </body>
+                    </html>
+            `})
+
+            cy.intercept('/second', {
+                headers: { 'content-type': 'text/html' },
+                body: html`
+                    <html>
+                        <head>
+                            <script src="/../../packages/navigate/dist/cdn.js" defer></script>
+                            <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
+                        </head>
+                        <body>
+                            <input type="text" autofocus>
+                        </body>
+                    </html>
+            `})
+
+            cy.visit('/first')
+
+            cy.get('a').click()
+
+            cy.url().should('include', '/second')
+            cy.get('input').should(haveFocus())
+        },
+    )
+
+    it.skip('scripts and styles are properly merged/run or skipped',
+        () => {
+            cy.intercept('/first', {
+                headers: { 'content-type': 'text/html' },
+                body: html`
+                    <html>
+                        <head>
+                            <title>First Page</title>
+                            <meta name="description" content="first description">
+                            <script src="/../../packages/navigate/dist/cdn.js" defer></script>
+                            <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
+                        </head>
+                        <body>
+                            <a href="/second">Navigate</a>
+                        </body>
+                    </html>
+            `})
+
+            cy.intercept('/head-script.js', {
+                headers: { 'content-type': 'text/js' },
+                body: `window.fromHeadScript = true`
+            })
+
+            cy.intercept('/body-script.js', {
+                headers: { 'content-type': 'text/js' },
+                body: `window.fromBodyScript = true`
+            })
+
+            cy.intercept('/head-style.css', {
+                headers: { 'content-type': 'text/css' },
+                body: `body { background: black !important; }`
+            })
+
+            cy.intercept('/second', {
+                headers: { 'content-type': 'text/html' },
+                body: html`
+                    <html>
+                        <head>
+                            <title>Second Page</title>
+                            <meta name="description" content="second description">
+                            <script src="/../../packages/navigate/dist/cdn.js" defer></script>
+                            <script src="/../../packages/alpinejs/dist/cdn.js" defer></script>
+                            <script src="head-script.js" defer></script>
+                            <script>window.fromHeadScriptInline = true</script>
+                            <link rel="stylesheet" src="head-style.css"></script>
+                        </head>
+                        <body>
+                            <script src="body-script.js" defer></script>
+                            <script>window.fromBodyScriptInline = true</script>
+                        </body>
+                    </html>
+            `})
+
+            cy.visit('/first')
+
+            cy.get('a').click()
+
+            cy.url().should('include', '/second')
+            cy.title().should(beEqualTo('Second Page'))
+            cy.get('meta').should(haveAttribute('name', 'description'))
+            cy.get('meta').should(haveAttribute('content', 'second description'))
+            cy.window().its('fromHeadScript').should(beEqualTo(true))
+            cy.window().its('fromHeadScriptInline').should(beEqualTo(true))
+            cy.window().its('fromBodyScript').should(beEqualTo(true))
+            cy.window().its('fromBodyScriptInline').should(beEqualTo(true))
+        },
+    )
+})

+ 0 - 1
tests/cypress/spec.html

@@ -6,7 +6,6 @@
         <!-- This is where our test subjects will be injected. -->
     </blockquote>
 
-    <script src="/../../packages/history/dist/cdn.js"></script>
     <script src="/../../packages/morph/dist/cdn.js"></script>
     <script src="/../../packages/persist/dist/cdn.js"></script>
     <script src="/../../packages/focus/dist/cdn.js"></script>