A step that waits for a URL
Two links with no handler written for the tour, one through a small router and one a plain hash link, and each step moves because the URL came to match.
// A query rather than a path, so a reload at the checkout URL is still this// page on a host that serves one file per path, as the site does. Both look// only before the `#`, which is this case's own and never holds `view`.const VIEW_CHECKOUT = /^[^#]*[?&]view=checkout(?:[&#]|$)/const VIEW_HOME = /^(?![^#]*[?&]view=checkout(?:[&#]|$))/
// Home is "not at the checkout hash", because a host that does not route by// hash shows this case with no hash at all.const HASH_CHECKOUT = new RegExp(`#${CASE_ID}/checkout(?:[/?]|$)`)const HASH_HOME = new RegExp(`^(?!.*#${CASE_ID}/checkout(?:[/?]|$))`)
const queryRouter = { id: 'query-router', steps: [ { id: 'go-to-checkout', target: { elements: '[data-route-link]', interactive: true }, message: 'Press this. The router pushes a URL with ?view=checkout in it, and that is what this step is waiting for.', awaits: { url: VIEW_CHECKOUT }, }, { id: 'arrived-by-query', target: '[data-confirm]', message: 'The URL with ?view=checkout in it moved this step, not the click.', }, { id: 'go-back', target: { elements: '[data-back]', interactive: true }, message: 'Press Back. Leaving ?view=checkout is a URL change too, and a step can wait for that one just the same.', awaits: { url: VIEW_HOME }, }, { id: 'arrived-by-back', target: '[data-current-path]', message: 'history.back() moved this step. Nothing here told the tour a button was pressed.', }, ],} satisfies LekoStory
const hashRouter = { id: 'hash-router', steps: [ { id: 'go-to-checkout-hash', target: { elements: '[data-hash-link]', interactive: true }, message: 'Press this plain link. There is no click handler on it — the browser changes the hash by itself.', awaits: { url: HASH_CHECKOUT }, }, { id: 'arrived-by-hash', target: '[data-confirm]', message: 'The hash ending in /checkout moved this step. No router was needed to write it.', }, { id: 'go-back-hash', target: { elements: '[data-back]', interactive: true }, message: 'Press Back. It leaves the /checkout hash the same way traversal does anywhere else.', awaits: { url: HASH_HOME }, }, { id: 'arrived-by-back-hash', target: '[data-confirm]', message: 'Traversal moved this step too — forward or back, only the URL matters.', }, ],} satisfies LekoStoryconst goToCheckout = (event: MouseEvent): void => { event.preventDefault() const url = new URL(location.href) url.searchParams.set('view', 'checkout') history.pushState(null, '', url) render()}
routeLink.addEventListener('click', goToCheckout)backButton.addEventListener('click', () => history.back())