phx-react
Version:
PHX REACT
142 lines • 5.87 kB
JavaScript
;
'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