UNPKG

phx-react

Version:

PHX REACT

142 lines 5.87 kB
"use strict"; 'use client'; Object.defineProperty(exports, "__esModule", { value: true }); exports.PageTracker = exports.usePageTrackerHandler = void 0; const react_1 = require("react"); const page_tracker_store_1 = require("./page-tracker-store"); const DEBUG = false; const useStrictModeDetector = () => { const counterRef = (0, react_1.useRef)(0); const isStrictMode = (0, react_1.useRef)(false); const detectorHandler = () => { counterRef.current++; if (isStrictMode.current) { return counterRef.current % 2 === 0; } return false; }; return { initStrictModeDetector: () => { counterRef.current++; if (counterRef.current === 2) { isStrictMode.current = true; } }, strictModeDetector: () => { return detectorHandler(); }, }; }; const debugLog = (message) => { if (DEBUG) { console.debug(`[DEBUG PAGE CHANGE] ${message}`); } }; const initHistoryState = () => { const defaultData = { __REACT_PAGE_TRACKER_INTERNAL__: { pageIndex: 0, referrer: document.referrer, pageHistory: [location.href.replace(location.origin, '')], pageHistoryLength: 1, }, }; if (typeof history.state === 'object' && history.state !== null) { history.replaceState({ ...history.state, ...defaultData, }, location.href); } else { history.replaceState(defaultData, ''); } page_tracker_store_1.pageTrackerStore.setState(defaultData.__REACT_PAGE_TRACKER_INTERNAL__); }; const usePageTrackerHandler = () => { const { initStrictModeDetector } = useStrictModeDetector(); const pageIndex = (0, react_1.useRef)(0); // for isLastPage usage const visitedTotalLength = (0, react_1.useRef)(1); (0, react_1.useEffect)(() => { initHistoryState(); initStrictModeDetector(); /** Handle user operate original back/forward button or history.go()/back()/forward() or framework routing. **/ const handlePopState = (event) => { var _a, _b; const state = event.state; const internal = state === null || state === void 0 ? void 0 : state.__REACT_PAGE_TRACKER_INTERNAL__; if (!internal) { // If the state isn't ours, ignore to avoid corrupting indices return; } const statePageIndex = (_a = internal.pageIndex) !== null && _a !== void 0 ? _a : 0; const pageEvent = pageIndex.current > statePageIndex ? 'back' : 'forward'; if (pageEvent === 'forward') { pageIndex.current = statePageIndex; // moving forward to the state's index } else { pageIndex.current = statePageIndex; } const pageHistory = [...(internal.pageHistory || [])]; page_tracker_store_1.pageTrackerStore.setState({ pageIndex: pageIndex.current, isFirstPage: pageIndex.current === 0, isLastPage: pageHistory.length === visitedTotalLength.current, referrer: (_b = internal.referrer) !== null && _b !== void 0 ? _b : '', pageHistory, pageHistoryLength: visitedTotalLength.current, pageEvent, }); }; // save original pushState const originalPushState = history.pushState.bind(history); const normalize = (raw) => raw.replace(location.origin, ''); // override popstate using addEventListener window.addEventListener('popstate', handlePopState); history.pushState = (state, title, url) => { const baseHistory = page_tracker_store_1.pageTrackerStore.getImmutablePageHistory(); // trim forward if navigating mid-stack if (pageIndex.current < baseHistory.length - 1) { baseHistory.splice(pageIndex.current + 1); } const nextUrl = url ? normalize(url) : normalize(location.href); const newPageHistory = [...baseHistory, nextUrl]; const newPageIndex = newPageHistory.length - 1; pageIndex.current = newPageIndex; visitedTotalLength.current = newPageHistory.length; const newState = { pageIndex: newPageIndex, referrer: normalize(window.location.href), pageHistory: newPageHistory, pageHistoryLength: visitedTotalLength.current, }; const stateWithPageInfo = { ...state, __REACT_PAGE_TRACKER_INTERNAL__: { ...newState, }, }; page_tracker_store_1.pageTrackerStore.setState({ ...newState, isFirstPage: newPageIndex === 0, isLastPage: true, pageEvent: 'push', }); debugLog(`pushState: stateWithPageInfo.pageIndex -->${stateWithPageInfo.__REACT_PAGE_TRACKER_INTERNAL__.pageIndex} ,pageIndex.current --> ${pageIndex.current} referrer -->${stateWithPageInfo.__REACT_PAGE_TRACKER_INTERNAL__.referrer}`); return originalPushState(stateWithPageInfo, title || '', url || ''); }; return () => { window.removeEventListener('popstate', handlePopState); history.pushState = originalPushState; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); }; exports.usePageTrackerHandler = usePageTrackerHandler; const PageTracker = () => { // eslint-disable-next-line no-use-before-define (0, exports.usePageTrackerHandler)(); return null; }; exports.PageTracker = PageTracker; //# sourceMappingURL=page-tracker.js.map