tanstack-router-cache 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/components/cached-outlet.cjs +12 -0
  2. package/dist/components/cached-outlet.js +12 -0
  3. package/dist/components/off-screen-in.cjs +130 -0
  4. package/dist/components/off-screen-in.js +130 -0
  5. package/dist/components/off-screen.cjs +8 -0
  6. package/dist/components/off-screen.js +8 -0
  7. package/dist/components/restore-cached-href.cjs +28 -0
  8. package/dist/components/restore-cached-href.d.ts +0 -1
  9. package/dist/components/restore-cached-href.js +28 -0
  10. package/dist/components/route-cache-manager.cjs +485 -0
  11. package/dist/components/route-cache-manager.js +485 -0
  12. package/dist/components/router-cache-outlet.cjs +9 -0
  13. package/dist/components/router-cache-outlet.js +9 -0
  14. package/dist/contexts/router-cache.cjs +237 -0
  15. package/dist/contexts/router-cache.d.ts +40 -0
  16. package/dist/contexts/router-cache.js +235 -0
  17. package/dist/dom/dismiss-transient-ui.cjs +230 -0
  18. package/dist/dom/dismiss-transient-ui.js +228 -0
  19. package/dist/hooks/use-event-listener.cjs +76 -0
  20. package/dist/hooks/use-event-listener.js +76 -0
  21. package/dist/hooks/use-route-cache-active.cjs +19 -0
  22. package/dist/hooks/use-route-cache-active.js +19 -0
  23. package/dist/hooks/use-route-cache-activity.cjs +12 -0
  24. package/dist/hooks/use-route-cache-activity.js +12 -0
  25. package/dist/hooks/use-route-cache-effect.cjs +38 -0
  26. package/dist/hooks/use-route-cache-effect.js +38 -0
  27. package/dist/hooks/use-route-cache-error-boundary.cjs +23 -0
  28. package/dist/hooks/use-route-cache-error-boundary.js +23 -0
  29. package/dist/hooks/use-route-cache-navigation.cjs +36 -0
  30. package/dist/hooks/use-route-cache-navigation.js +36 -0
  31. package/dist/hooks/use-router-cache-debug.cjs +85 -0
  32. package/dist/hooks/use-router-cache-debug.js +85 -0
  33. package/dist/hooks/use-router-cache.cjs +32 -0
  34. package/dist/hooks/use-router-cache.js +32 -0
  35. package/dist/hooks/use-update.cjs +8 -0
  36. package/dist/hooks/use-update.js +8 -0
  37. package/dist/index.cjs +18 -1402
  38. package/dist/index.d.ts +9 -1
  39. package/dist/index.js +10 -1395
  40. package/dist/pathname.cjs +8 -0
  41. package/dist/pathname.js +8 -0
  42. package/dist/route-cache-static-data.cjs +43 -0
  43. package/dist/route-cache-static-data.d.ts +25 -0
  44. package/dist/route-cache-static-data.js +41 -0
  45. package/dist/types.d.ts +50 -0
  46. package/docs/architecture.md +8 -5
  47. package/docs/cache-behavior.md +17 -0
  48. package/docs/components.md +1 -2
  49. package/docs/getting-started.md +38 -3
  50. package/docs/releases.md +0 -9
  51. package/docs/types.md +12 -0
  52. package/package.json +4 -6
@@ -0,0 +1,230 @@
1
+ //#region src/dom/dismiss-transient-ui.ts
2
+ const documentStates = /* @__PURE__ */ new WeakMap();
3
+ const PERSISTENT_EXTERNAL_ATTRIBUTE = "data-router-cache-persistent-external";
4
+ function isBlurTarget(element) {
5
+ return element instanceof HTMLElement;
6
+ }
7
+ function getOrCreateDocumentState(documentObject) {
8
+ const existingState = documentStates.get(documentObject);
9
+ if (existingState) return existingState;
10
+ const state = {
11
+ observer: null,
12
+ ownerByElement: /* @__PURE__ */ new WeakMap(),
13
+ routes: /* @__PURE__ */ new Map(),
14
+ visiblePathname: null
15
+ };
16
+ if (typeof MutationObserver !== "undefined") {
17
+ state.observer = new MutationObserver((mutations) => {
18
+ handleDomMutations(mutations, state);
19
+ });
20
+ state.observer.observe(documentObject.body ?? documentObject.documentElement, {
21
+ childList: true,
22
+ subtree: true
23
+ });
24
+ }
25
+ documentStates.set(documentObject, state);
26
+ return state;
27
+ }
28
+ function getOrCreateRouteState(state, pathname) {
29
+ const existingRouteState = state.routes.get(pathname);
30
+ if (existingRouteState) return existingRouteState;
31
+ const routeState = {
32
+ hiddenElements: /* @__PURE__ */ new Map(),
33
+ ownedElements: /* @__PURE__ */ new Set()
34
+ };
35
+ state.routes.set(pathname, routeState);
36
+ return routeState;
37
+ }
38
+ function getHoveredElements(documentObject) {
39
+ try {
40
+ return Array.from(documentObject.querySelectorAll(":hover")).reverse();
41
+ } catch {
42
+ return [];
43
+ }
44
+ }
45
+ function getOwnedExternalElements(documentObject, pathname) {
46
+ const routeState = getOrCreateRouteState(getOrCreateDocumentState(documentObject), pathname);
47
+ return Array.from(routeState.ownedElements).filter((element) => element.isConnected);
48
+ }
49
+ function dispatchEscapeKeyboardEvent(target, documentObject, type) {
50
+ const keyboardEventConstructor = documentObject.defaultView?.KeyboardEvent ?? KeyboardEvent;
51
+ target.dispatchEvent(new keyboardEventConstructor(type, {
52
+ bubbles: true,
53
+ cancelable: true,
54
+ code: "Escape",
55
+ key: "Escape",
56
+ keyCode: 27,
57
+ which: 27
58
+ }));
59
+ }
60
+ function dispatchHoverExitEvent(target, documentObject, type) {
61
+ const eventConstructor = type.startsWith("pointer") ? documentObject.defaultView?.PointerEvent ?? documentObject.defaultView?.MouseEvent ?? MouseEvent : documentObject.defaultView?.MouseEvent ?? MouseEvent;
62
+ target.dispatchEvent(new eventConstructor(type, {
63
+ bubbles: type.endsWith("out"),
64
+ cancelable: true,
65
+ composed: true,
66
+ relatedTarget: documentObject.body
67
+ }));
68
+ }
69
+ function dispatchHoverExitEvents(hoveredElements, documentObject) {
70
+ for (const hoveredElement of hoveredElements) {
71
+ dispatchHoverExitEvent(hoveredElement, documentObject, "pointerout");
72
+ dispatchHoverExitEvent(hoveredElement, documentObject, "pointerleave");
73
+ dispatchHoverExitEvent(hoveredElement, documentObject, "mouseout");
74
+ dispatchHoverExitEvent(hoveredElement, documentObject, "mouseleave");
75
+ }
76
+ }
77
+ function focusDocumentBody(documentObject) {
78
+ const { body } = documentObject;
79
+ const previousTabIndex = body.getAttribute("tabindex");
80
+ if (previousTabIndex === null) body.setAttribute("tabindex", "-1");
81
+ body.focus();
82
+ if (previousTabIndex === null) body.removeAttribute("tabindex");
83
+ }
84
+ function getRouterCacheContainerAncestor(element) {
85
+ const container = element?.closest("[data-router-cache-container=\"true\"]");
86
+ return container instanceof HTMLElement ? container : null;
87
+ }
88
+ function isElementInsideAnyRouterCacheContainer(element) {
89
+ return getRouterCacheContainerAncestor(element) !== null;
90
+ }
91
+ function containsRouterCacheContainer(element) {
92
+ return element.querySelector("[data-router-cache-container=\"true\"]") instanceof HTMLElement;
93
+ }
94
+ function isElementConnectedOutsideRouterCacheContainer(element) {
95
+ return element.isConnected && !isElementInsideAnyRouterCacheContainer(element);
96
+ }
97
+ function isPersistentExternalElement(element) {
98
+ return element.closest(`[${PERSISTENT_EXTERNAL_ATTRIBUTE}="true"]`) instanceof HTMLElement;
99
+ }
100
+ function getTrackableElementsFromNode(node) {
101
+ if (node instanceof HTMLElement) return [node];
102
+ if (node instanceof DocumentFragment) return Array.from(node.children).flatMap((child) => child instanceof HTMLElement ? [child] : []);
103
+ return [];
104
+ }
105
+ function forEachRemovedNode(mutations, callback) {
106
+ for (const mutation of mutations) for (const removedNode of mutation.removedNodes) callback(removedNode);
107
+ }
108
+ function forEachAddedNode(mutations, callback) {
109
+ for (const mutation of mutations) for (const addedNode of mutation.addedNodes) callback(addedNode);
110
+ }
111
+ function handleDomMutations(mutations, state) {
112
+ forEachRemovedNode(mutations, (removedNode) => {
113
+ untrackRemovedNode(removedNode, state);
114
+ });
115
+ if (!state.visiblePathname) return;
116
+ forEachAddedNode(mutations, (addedNode) => {
117
+ trackAddedNode(addedNode, state.visiblePathname, state);
118
+ });
119
+ }
120
+ function hasTrackedAncestor(element, state) {
121
+ let ancestor = element.parentElement;
122
+ while (ancestor) {
123
+ if (state.ownerByElement.get(ancestor)) return true;
124
+ ancestor = ancestor.parentElement;
125
+ }
126
+ return false;
127
+ }
128
+ function restoreOwnedExternalElement(routeState, element) {
129
+ const snapshot = routeState.hiddenElements.get(element);
130
+ if (!snapshot) return;
131
+ element.style.setProperty("display", snapshot.display, snapshot.displayPriority);
132
+ if (snapshot.ariaHidden === null) element.removeAttribute("aria-hidden");
133
+ else element.setAttribute("aria-hidden", snapshot.ariaHidden);
134
+ element.inert = snapshot.inert;
135
+ routeState.hiddenElements.delete(element);
136
+ }
137
+ function trackExternalElement(pathname, element, state) {
138
+ if (!isElementConnectedOutsideRouterCacheContainer(element) || containsRouterCacheContainer(element) || isPersistentExternalElement(element) || hasTrackedAncestor(element, state)) return;
139
+ const currentOwner = state.ownerByElement.get(element);
140
+ if (currentOwner === pathname) return;
141
+ if (currentOwner) {
142
+ const previousRouteState = state.routes.get(currentOwner);
143
+ if (previousRouteState) {
144
+ restoreOwnedExternalElement(previousRouteState, element);
145
+ previousRouteState.ownedElements.delete(element);
146
+ }
147
+ }
148
+ getOrCreateRouteState(state, pathname).ownedElements.add(element);
149
+ state.ownerByElement.set(element, pathname);
150
+ }
151
+ function trackAddedNode(node, pathname, state) {
152
+ const elements = getTrackableElementsFromNode(node);
153
+ for (const element of elements) trackExternalElement(pathname, element, state);
154
+ }
155
+ function untrackElement(routeState, state, element) {
156
+ routeState.hiddenElements.delete(element);
157
+ routeState.ownedElements.delete(element);
158
+ state.ownerByElement.delete(element);
159
+ }
160
+ function untrackRemovedNode(node, state) {
161
+ if (!(node instanceof HTMLElement)) return;
162
+ for (const routeState of state.routes.values()) for (const element of Array.from(routeState.ownedElements)) if (node === element || node.contains(element)) untrackElement(routeState, state, element);
163
+ }
164
+ function hideOwnedExternalElements(documentObject, pathname) {
165
+ const routeState = getOrCreateRouteState(getOrCreateDocumentState(documentObject), pathname);
166
+ for (const element of Array.from(routeState.ownedElements)) {
167
+ if (!isElementConnectedOutsideRouterCacheContainer(element)) {
168
+ routeState.ownedElements.delete(element);
169
+ routeState.hiddenElements.delete(element);
170
+ continue;
171
+ }
172
+ if (routeState.hiddenElements.has(element)) continue;
173
+ routeState.hiddenElements.set(element, {
174
+ ariaHidden: element.getAttribute("aria-hidden"),
175
+ display: element.style.getPropertyValue("display"),
176
+ displayPriority: element.style.getPropertyPriority("display"),
177
+ inert: element.inert
178
+ });
179
+ element.style.setProperty("display", "none", "important");
180
+ element.setAttribute("aria-hidden", "true");
181
+ element.inert = true;
182
+ }
183
+ }
184
+ function showOwnedExternalElements(documentObject, pathname) {
185
+ const routeState = getOrCreateRouteState(getOrCreateDocumentState(documentObject), pathname);
186
+ for (const [element] of Array.from(routeState.hiddenElements)) {
187
+ if (!element.isConnected) {
188
+ routeState.hiddenElements.delete(element);
189
+ routeState.ownedElements.delete(element);
190
+ continue;
191
+ }
192
+ restoreOwnedExternalElement(routeState, element);
193
+ }
194
+ }
195
+ function initializeTransientUiTracking(documentObject) {
196
+ getOrCreateDocumentState(documentObject);
197
+ }
198
+ function syncTransientUiRouteActivity(pathname, mode) {
199
+ if (typeof document === "undefined") return;
200
+ const documentState = getOrCreateDocumentState(document);
201
+ getOrCreateRouteState(documentState, pathname);
202
+ if (mode === "visible") {
203
+ documentState.visiblePathname = pathname;
204
+ showOwnedExternalElements(document, pathname);
205
+ return;
206
+ }
207
+ if (documentState.visiblePathname === pathname) documentState.visiblePathname = null;
208
+ dispatchHoverExitEvents(getOwnedExternalElements(document, pathname), document);
209
+ hideOwnedExternalElements(document, pathname);
210
+ }
211
+ function dismissTransientUi(container, pathname) {
212
+ if (typeof document === "undefined" || !container) return;
213
+ initializeTransientUiTracking(document);
214
+ const hoveredElements = getHoveredElements(document);
215
+ const hoverExitTargets = Array.from(/* @__PURE__ */ new Set([...hoveredElements, ...getOwnedExternalElements(document, pathname)]));
216
+ const activeElement = document.activeElement;
217
+ const activeElementBelongsToHoveredTree = activeElement instanceof Element && hoverExitTargets.some((hoveredElement) => hoveredElement === activeElement || hoveredElement.contains(activeElement));
218
+ if (activeElement instanceof Element && (container.contains(activeElement) || activeElementBelongsToHoveredTree) && isBlurTarget(activeElement)) activeElement.blur();
219
+ dispatchHoverExitEvents(hoverExitTargets, document);
220
+ dispatchEscapeKeyboardEvent(document, document, "keydown");
221
+ dispatchEscapeKeyboardEvent(document, document, "keyup");
222
+ hideOwnedExternalElements(document, pathname);
223
+ const nextActiveElement = document.activeElement;
224
+ const nextActiveElementBelongsToHoveredTree = nextActiveElement instanceof Element && hoverExitTargets.some((hoveredElement) => hoveredElement === nextActiveElement || hoveredElement.contains(nextActiveElement));
225
+ if (nextActiveElement instanceof Element && (container.contains(nextActiveElement) || nextActiveElementBelongsToHoveredTree)) focusDocumentBody(document);
226
+ }
227
+ //#endregion
228
+ exports.dismissTransientUi = dismissTransientUi;
229
+ exports.initializeTransientUiTracking = initializeTransientUiTracking;
230
+ exports.syncTransientUiRouteActivity = syncTransientUiRouteActivity;
@@ -0,0 +1,228 @@
1
+ //#region src/dom/dismiss-transient-ui.ts
2
+ const documentStates = /* @__PURE__ */ new WeakMap();
3
+ const PERSISTENT_EXTERNAL_ATTRIBUTE = "data-router-cache-persistent-external";
4
+ function isBlurTarget(element) {
5
+ return element instanceof HTMLElement;
6
+ }
7
+ function getOrCreateDocumentState(documentObject) {
8
+ const existingState = documentStates.get(documentObject);
9
+ if (existingState) return existingState;
10
+ const state = {
11
+ observer: null,
12
+ ownerByElement: /* @__PURE__ */ new WeakMap(),
13
+ routes: /* @__PURE__ */ new Map(),
14
+ visiblePathname: null
15
+ };
16
+ if (typeof MutationObserver !== "undefined") {
17
+ state.observer = new MutationObserver((mutations) => {
18
+ handleDomMutations(mutations, state);
19
+ });
20
+ state.observer.observe(documentObject.body ?? documentObject.documentElement, {
21
+ childList: true,
22
+ subtree: true
23
+ });
24
+ }
25
+ documentStates.set(documentObject, state);
26
+ return state;
27
+ }
28
+ function getOrCreateRouteState(state, pathname) {
29
+ const existingRouteState = state.routes.get(pathname);
30
+ if (existingRouteState) return existingRouteState;
31
+ const routeState = {
32
+ hiddenElements: /* @__PURE__ */ new Map(),
33
+ ownedElements: /* @__PURE__ */ new Set()
34
+ };
35
+ state.routes.set(pathname, routeState);
36
+ return routeState;
37
+ }
38
+ function getHoveredElements(documentObject) {
39
+ try {
40
+ return Array.from(documentObject.querySelectorAll(":hover")).reverse();
41
+ } catch {
42
+ return [];
43
+ }
44
+ }
45
+ function getOwnedExternalElements(documentObject, pathname) {
46
+ const routeState = getOrCreateRouteState(getOrCreateDocumentState(documentObject), pathname);
47
+ return Array.from(routeState.ownedElements).filter((element) => element.isConnected);
48
+ }
49
+ function dispatchEscapeKeyboardEvent(target, documentObject, type) {
50
+ const keyboardEventConstructor = documentObject.defaultView?.KeyboardEvent ?? KeyboardEvent;
51
+ target.dispatchEvent(new keyboardEventConstructor(type, {
52
+ bubbles: true,
53
+ cancelable: true,
54
+ code: "Escape",
55
+ key: "Escape",
56
+ keyCode: 27,
57
+ which: 27
58
+ }));
59
+ }
60
+ function dispatchHoverExitEvent(target, documentObject, type) {
61
+ const eventConstructor = type.startsWith("pointer") ? documentObject.defaultView?.PointerEvent ?? documentObject.defaultView?.MouseEvent ?? MouseEvent : documentObject.defaultView?.MouseEvent ?? MouseEvent;
62
+ target.dispatchEvent(new eventConstructor(type, {
63
+ bubbles: type.endsWith("out"),
64
+ cancelable: true,
65
+ composed: true,
66
+ relatedTarget: documentObject.body
67
+ }));
68
+ }
69
+ function dispatchHoverExitEvents(hoveredElements, documentObject) {
70
+ for (const hoveredElement of hoveredElements) {
71
+ dispatchHoverExitEvent(hoveredElement, documentObject, "pointerout");
72
+ dispatchHoverExitEvent(hoveredElement, documentObject, "pointerleave");
73
+ dispatchHoverExitEvent(hoveredElement, documentObject, "mouseout");
74
+ dispatchHoverExitEvent(hoveredElement, documentObject, "mouseleave");
75
+ }
76
+ }
77
+ function focusDocumentBody(documentObject) {
78
+ const { body } = documentObject;
79
+ const previousTabIndex = body.getAttribute("tabindex");
80
+ if (previousTabIndex === null) body.setAttribute("tabindex", "-1");
81
+ body.focus();
82
+ if (previousTabIndex === null) body.removeAttribute("tabindex");
83
+ }
84
+ function getRouterCacheContainerAncestor(element) {
85
+ const container = element?.closest("[data-router-cache-container=\"true\"]");
86
+ return container instanceof HTMLElement ? container : null;
87
+ }
88
+ function isElementInsideAnyRouterCacheContainer(element) {
89
+ return getRouterCacheContainerAncestor(element) !== null;
90
+ }
91
+ function containsRouterCacheContainer(element) {
92
+ return element.querySelector("[data-router-cache-container=\"true\"]") instanceof HTMLElement;
93
+ }
94
+ function isElementConnectedOutsideRouterCacheContainer(element) {
95
+ return element.isConnected && !isElementInsideAnyRouterCacheContainer(element);
96
+ }
97
+ function isPersistentExternalElement(element) {
98
+ return element.closest(`[${PERSISTENT_EXTERNAL_ATTRIBUTE}="true"]`) instanceof HTMLElement;
99
+ }
100
+ function getTrackableElementsFromNode(node) {
101
+ if (node instanceof HTMLElement) return [node];
102
+ if (node instanceof DocumentFragment) return Array.from(node.children).flatMap((child) => child instanceof HTMLElement ? [child] : []);
103
+ return [];
104
+ }
105
+ function forEachRemovedNode(mutations, callback) {
106
+ for (const mutation of mutations) for (const removedNode of mutation.removedNodes) callback(removedNode);
107
+ }
108
+ function forEachAddedNode(mutations, callback) {
109
+ for (const mutation of mutations) for (const addedNode of mutation.addedNodes) callback(addedNode);
110
+ }
111
+ function handleDomMutations(mutations, state) {
112
+ forEachRemovedNode(mutations, (removedNode) => {
113
+ untrackRemovedNode(removedNode, state);
114
+ });
115
+ if (!state.visiblePathname) return;
116
+ forEachAddedNode(mutations, (addedNode) => {
117
+ trackAddedNode(addedNode, state.visiblePathname, state);
118
+ });
119
+ }
120
+ function hasTrackedAncestor(element, state) {
121
+ let ancestor = element.parentElement;
122
+ while (ancestor) {
123
+ if (state.ownerByElement.get(ancestor)) return true;
124
+ ancestor = ancestor.parentElement;
125
+ }
126
+ return false;
127
+ }
128
+ function restoreOwnedExternalElement(routeState, element) {
129
+ const snapshot = routeState.hiddenElements.get(element);
130
+ if (!snapshot) return;
131
+ element.style.setProperty("display", snapshot.display, snapshot.displayPriority);
132
+ if (snapshot.ariaHidden === null) element.removeAttribute("aria-hidden");
133
+ else element.setAttribute("aria-hidden", snapshot.ariaHidden);
134
+ element.inert = snapshot.inert;
135
+ routeState.hiddenElements.delete(element);
136
+ }
137
+ function trackExternalElement(pathname, element, state) {
138
+ if (!isElementConnectedOutsideRouterCacheContainer(element) || containsRouterCacheContainer(element) || isPersistentExternalElement(element) || hasTrackedAncestor(element, state)) return;
139
+ const currentOwner = state.ownerByElement.get(element);
140
+ if (currentOwner === pathname) return;
141
+ if (currentOwner) {
142
+ const previousRouteState = state.routes.get(currentOwner);
143
+ if (previousRouteState) {
144
+ restoreOwnedExternalElement(previousRouteState, element);
145
+ previousRouteState.ownedElements.delete(element);
146
+ }
147
+ }
148
+ getOrCreateRouteState(state, pathname).ownedElements.add(element);
149
+ state.ownerByElement.set(element, pathname);
150
+ }
151
+ function trackAddedNode(node, pathname, state) {
152
+ const elements = getTrackableElementsFromNode(node);
153
+ for (const element of elements) trackExternalElement(pathname, element, state);
154
+ }
155
+ function untrackElement(routeState, state, element) {
156
+ routeState.hiddenElements.delete(element);
157
+ routeState.ownedElements.delete(element);
158
+ state.ownerByElement.delete(element);
159
+ }
160
+ function untrackRemovedNode(node, state) {
161
+ if (!(node instanceof HTMLElement)) return;
162
+ for (const routeState of state.routes.values()) for (const element of Array.from(routeState.ownedElements)) if (node === element || node.contains(element)) untrackElement(routeState, state, element);
163
+ }
164
+ function hideOwnedExternalElements(documentObject, pathname) {
165
+ const routeState = getOrCreateRouteState(getOrCreateDocumentState(documentObject), pathname);
166
+ for (const element of Array.from(routeState.ownedElements)) {
167
+ if (!isElementConnectedOutsideRouterCacheContainer(element)) {
168
+ routeState.ownedElements.delete(element);
169
+ routeState.hiddenElements.delete(element);
170
+ continue;
171
+ }
172
+ if (routeState.hiddenElements.has(element)) continue;
173
+ routeState.hiddenElements.set(element, {
174
+ ariaHidden: element.getAttribute("aria-hidden"),
175
+ display: element.style.getPropertyValue("display"),
176
+ displayPriority: element.style.getPropertyPriority("display"),
177
+ inert: element.inert
178
+ });
179
+ element.style.setProperty("display", "none", "important");
180
+ element.setAttribute("aria-hidden", "true");
181
+ element.inert = true;
182
+ }
183
+ }
184
+ function showOwnedExternalElements(documentObject, pathname) {
185
+ const routeState = getOrCreateRouteState(getOrCreateDocumentState(documentObject), pathname);
186
+ for (const [element] of Array.from(routeState.hiddenElements)) {
187
+ if (!element.isConnected) {
188
+ routeState.hiddenElements.delete(element);
189
+ routeState.ownedElements.delete(element);
190
+ continue;
191
+ }
192
+ restoreOwnedExternalElement(routeState, element);
193
+ }
194
+ }
195
+ function initializeTransientUiTracking(documentObject) {
196
+ getOrCreateDocumentState(documentObject);
197
+ }
198
+ function syncTransientUiRouteActivity(pathname, mode) {
199
+ if (typeof document === "undefined") return;
200
+ const documentState = getOrCreateDocumentState(document);
201
+ getOrCreateRouteState(documentState, pathname);
202
+ if (mode === "visible") {
203
+ documentState.visiblePathname = pathname;
204
+ showOwnedExternalElements(document, pathname);
205
+ return;
206
+ }
207
+ if (documentState.visiblePathname === pathname) documentState.visiblePathname = null;
208
+ dispatchHoverExitEvents(getOwnedExternalElements(document, pathname), document);
209
+ hideOwnedExternalElements(document, pathname);
210
+ }
211
+ function dismissTransientUi(container, pathname) {
212
+ if (typeof document === "undefined" || !container) return;
213
+ initializeTransientUiTracking(document);
214
+ const hoveredElements = getHoveredElements(document);
215
+ const hoverExitTargets = Array.from(/* @__PURE__ */ new Set([...hoveredElements, ...getOwnedExternalElements(document, pathname)]));
216
+ const activeElement = document.activeElement;
217
+ const activeElementBelongsToHoveredTree = activeElement instanceof Element && hoverExitTargets.some((hoveredElement) => hoveredElement === activeElement || hoveredElement.contains(activeElement));
218
+ if (activeElement instanceof Element && (container.contains(activeElement) || activeElementBelongsToHoveredTree) && isBlurTarget(activeElement)) activeElement.blur();
219
+ dispatchHoverExitEvents(hoverExitTargets, document);
220
+ dispatchEscapeKeyboardEvent(document, document, "keydown");
221
+ dispatchEscapeKeyboardEvent(document, document, "keyup");
222
+ hideOwnedExternalElements(document, pathname);
223
+ const nextActiveElement = document.activeElement;
224
+ const nextActiveElementBelongsToHoveredTree = nextActiveElement instanceof Element && hoverExitTargets.some((hoveredElement) => hoveredElement === nextActiveElement || hoveredElement.contains(nextActiveElement));
225
+ if (nextActiveElement instanceof Element && (container.contains(nextActiveElement) || nextActiveElementBelongsToHoveredTree)) focusDocumentBody(document);
226
+ }
227
+ //#endregion
228
+ export { dismissTransientUi, initializeTransientUiTracking, syncTransientUiRouteActivity };
@@ -0,0 +1,76 @@
1
+ let react = require("react");
2
+ //#region src/hooks/use-event-listener.ts
3
+ const EVENT_BUCKET_KEYS = ["on", "once"];
4
+ const instance = class RouterCacheEvent {
5
+ static instance;
6
+ listeners = {
7
+ activeChange: /* @__PURE__ */ new Set(),
8
+ cachedNavigationCancel: /* @__PURE__ */ new Set(),
9
+ cachedNavigationComplete: /* @__PURE__ */ new Set(),
10
+ cachedNavigationStart: /* @__PURE__ */ new Set()
11
+ };
12
+ constructor() {}
13
+ static getInstance() {
14
+ if (!RouterCacheEvent.instance) RouterCacheEvent.instance = new RouterCacheEvent();
15
+ return RouterCacheEvent.instance;
16
+ }
17
+ on(eventName, handler) {
18
+ this.listeners[eventName].add(handler);
19
+ return this;
20
+ }
21
+ once(eventName, handler) {
22
+ const onceHandler = (...args) => {
23
+ this.off(eventName, onceHandler);
24
+ handler(...args);
25
+ };
26
+ this.listeners[eventName].add(onceHandler);
27
+ return this;
28
+ }
29
+ off(eventName, handler) {
30
+ this.listeners[eventName].delete(handler);
31
+ return this;
32
+ }
33
+ emit(eventName, ...args) {
34
+ const handlers = this.listeners[eventName];
35
+ for (const handler of handlers) handler(...args);
36
+ return handlers.size > 0;
37
+ }
38
+ }.getInstance();
39
+ function syncEventHandler(type, eventName, handler) {
40
+ if (type === "on") {
41
+ instance.on(eventName, handler);
42
+ return;
43
+ }
44
+ instance.off(eventName, handler);
45
+ }
46
+ function syncEventBucket(type, bucket) {
47
+ if (bucket.activeChange) syncEventHandler(type, "activeChange", bucket.activeChange);
48
+ if (bucket.cachedNavigationCancel) syncEventHandler(type, "cachedNavigationCancel", bucket.cachedNavigationCancel);
49
+ if (bucket.cachedNavigationComplete) syncEventHandler(type, "cachedNavigationComplete", bucket.cachedNavigationComplete);
50
+ if (bucket.cachedNavigationStart) syncEventHandler(type, "cachedNavigationStart", bucket.cachedNavigationStart);
51
+ }
52
+ function syncEventHandlers(type, events) {
53
+ if (!events) return;
54
+ for (const key of EVENT_BUCKET_KEYS) {
55
+ const bucket = events[key];
56
+ if (!bucket) continue;
57
+ syncEventBucket(type, bucket);
58
+ }
59
+ }
60
+ function useEventListener(events) {
61
+ (0, react.useEffect)(() => {
62
+ const registerEvent = () => {
63
+ syncEventHandlers("on", events);
64
+ return () => {
65
+ syncEventHandlers("off", events);
66
+ };
67
+ };
68
+ const unregister = registerEvent();
69
+ return () => {
70
+ unregister?.();
71
+ };
72
+ }, [events]);
73
+ return { eventListener: instance };
74
+ }
75
+ //#endregion
76
+ exports.useEventListener = useEventListener;
@@ -0,0 +1,76 @@
1
+ import { useEffect } from "react";
2
+ //#region src/hooks/use-event-listener.ts
3
+ const EVENT_BUCKET_KEYS = ["on", "once"];
4
+ const instance = class RouterCacheEvent {
5
+ static instance;
6
+ listeners = {
7
+ activeChange: /* @__PURE__ */ new Set(),
8
+ cachedNavigationCancel: /* @__PURE__ */ new Set(),
9
+ cachedNavigationComplete: /* @__PURE__ */ new Set(),
10
+ cachedNavigationStart: /* @__PURE__ */ new Set()
11
+ };
12
+ constructor() {}
13
+ static getInstance() {
14
+ if (!RouterCacheEvent.instance) RouterCacheEvent.instance = new RouterCacheEvent();
15
+ return RouterCacheEvent.instance;
16
+ }
17
+ on(eventName, handler) {
18
+ this.listeners[eventName].add(handler);
19
+ return this;
20
+ }
21
+ once(eventName, handler) {
22
+ const onceHandler = (...args) => {
23
+ this.off(eventName, onceHandler);
24
+ handler(...args);
25
+ };
26
+ this.listeners[eventName].add(onceHandler);
27
+ return this;
28
+ }
29
+ off(eventName, handler) {
30
+ this.listeners[eventName].delete(handler);
31
+ return this;
32
+ }
33
+ emit(eventName, ...args) {
34
+ const handlers = this.listeners[eventName];
35
+ for (const handler of handlers) handler(...args);
36
+ return handlers.size > 0;
37
+ }
38
+ }.getInstance();
39
+ function syncEventHandler(type, eventName, handler) {
40
+ if (type === "on") {
41
+ instance.on(eventName, handler);
42
+ return;
43
+ }
44
+ instance.off(eventName, handler);
45
+ }
46
+ function syncEventBucket(type, bucket) {
47
+ if (bucket.activeChange) syncEventHandler(type, "activeChange", bucket.activeChange);
48
+ if (bucket.cachedNavigationCancel) syncEventHandler(type, "cachedNavigationCancel", bucket.cachedNavigationCancel);
49
+ if (bucket.cachedNavigationComplete) syncEventHandler(type, "cachedNavigationComplete", bucket.cachedNavigationComplete);
50
+ if (bucket.cachedNavigationStart) syncEventHandler(type, "cachedNavigationStart", bucket.cachedNavigationStart);
51
+ }
52
+ function syncEventHandlers(type, events) {
53
+ if (!events) return;
54
+ for (const key of EVENT_BUCKET_KEYS) {
55
+ const bucket = events[key];
56
+ if (!bucket) continue;
57
+ syncEventBucket(type, bucket);
58
+ }
59
+ }
60
+ function useEventListener(events) {
61
+ useEffect(() => {
62
+ const registerEvent = () => {
63
+ syncEventHandlers("on", events);
64
+ return () => {
65
+ syncEventHandlers("off", events);
66
+ };
67
+ };
68
+ const unregister = registerEvent();
69
+ return () => {
70
+ unregister?.();
71
+ };
72
+ }, [events]);
73
+ return { eventListener: instance };
74
+ }
75
+ //#endregion
76
+ export { useEventListener };
@@ -0,0 +1,19 @@
1
+ const require_pathname = require("../pathname.cjs");
2
+ const require_use_event_listener = require("./use-event-listener.cjs");
3
+ let _tanstack_react_router = require("@tanstack/react-router");
4
+ let react = require("react");
5
+ //#region src/hooks/use-route-cache-active.ts
6
+ function useRoutePathname(pathname) {
7
+ const locationPathname = (0, _tanstack_react_router.useLocation)({ select: (location) => location.pathname });
8
+ return require_pathname.normalizeCachedRoutePathname(pathname ?? locationPathname);
9
+ }
10
+ function useRouteCacheActive(pathname) {
11
+ const routePathname = useRoutePathname(pathname);
12
+ const [isActive, setIsActive] = (0, react.useState)(true);
13
+ require_use_event_listener.useEventListener({ on: { activeChange: ({ pathname: changedPathname, mode }) => {
14
+ if (changedPathname === routePathname) setIsActive(mode === "visible");
15
+ } } });
16
+ return isActive;
17
+ }
18
+ //#endregion
19
+ exports.useRouteCacheActive = useRouteCacheActive;
@@ -0,0 +1,19 @@
1
+ import { normalizeCachedRoutePathname } from "../pathname.js";
2
+ import { useEventListener } from "./use-event-listener.js";
3
+ import { useLocation } from "@tanstack/react-router";
4
+ import { useState } from "react";
5
+ //#region src/hooks/use-route-cache-active.ts
6
+ function useRoutePathname(pathname) {
7
+ const locationPathname = useLocation({ select: (location) => location.pathname });
8
+ return normalizeCachedRoutePathname(pathname ?? locationPathname);
9
+ }
10
+ function useRouteCacheActive(pathname) {
11
+ const routePathname = useRoutePathname(pathname);
12
+ const [isActive, setIsActive] = useState(true);
13
+ useEventListener({ on: { activeChange: ({ pathname: changedPathname, mode }) => {
14
+ if (changedPathname === routePathname) setIsActive(mode === "visible");
15
+ } } });
16
+ return isActive;
17
+ }
18
+ //#endregion
19
+ export { useRouteCacheActive };
@@ -0,0 +1,12 @@
1
+ const require_use_event_listener = require("./use-event-listener.cjs");
2
+ let _tanstack_react_router = require("@tanstack/react-router");
3
+ //#region src/hooks/use-route-cache-activity.ts
4
+ function useRouteCacheActivity(fn) {
5
+ const routePathname = (0, _tanstack_react_router.useLocation)({ select: (location) => location.pathname });
6
+ require_use_event_listener.useEventListener({ on: { activeChange: ({ pathname, mode, callback }) => {
7
+ if (pathname === routePathname) fn(mode === "visible");
8
+ callback?.();
9
+ } } });
10
+ }
11
+ //#endregion
12
+ exports.useRouteCacheActivity = useRouteCacheActivity;
@@ -0,0 +1,12 @@
1
+ import { useEventListener } from "./use-event-listener.js";
2
+ import { useLocation } from "@tanstack/react-router";
3
+ //#region src/hooks/use-route-cache-activity.ts
4
+ function useRouteCacheActivity(fn) {
5
+ const routePathname = useLocation({ select: (location) => location.pathname });
6
+ useEventListener({ on: { activeChange: ({ pathname, mode, callback }) => {
7
+ if (pathname === routePathname) fn(mode === "visible");
8
+ callback?.();
9
+ } } });
10
+ }
11
+ //#endregion
12
+ export { useRouteCacheActivity };