@yoamigo.com/core 0.3.6 → 0.3.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.
- package/dist/{MarkdownText-Nvkeyr1z.d.ts → MarkdownText-DHJo0ofY.d.ts} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +148 -14
- package/dist/prod.d.ts +2 -2
- package/dist/prod.js +141 -7
- package/dist/router.d.ts +12 -1
- package/dist/router.js +97 -0
- package/package.json +1 -1
|
@@ -16,7 +16,7 @@ interface ContentStoreProviderProps {
|
|
|
16
16
|
initialContent?: Record<string, string>;
|
|
17
17
|
initialMode?: EditMode;
|
|
18
18
|
}
|
|
19
|
-
declare function ContentStoreProvider({ children }: ContentStoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
19
|
+
declare function ContentStoreProvider({ children, initialContent }: ContentStoreProviderProps): react_jsx_runtime.JSX.Element;
|
|
20
20
|
|
|
21
21
|
type EmbedType = 'spotify' | 'soundcloud' | 'twitter' | 'instagram' | 'custom';
|
|
22
22
|
interface EmbedFieldValue {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1, { ReactNode, CSSProperties } from 'react';
|
|
3
|
-
export { C as ContentStoreProviderProd, g as EmbedFieldValue, h as EmbedType, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, Y as YaEmbed, f as YaEmbedProps, i as YaLink, j as YaLinkProps, p as parseEmbedUrl, s as serializeEmbedValue, u as useContentStoreProd } from './MarkdownText-
|
|
4
|
-
export { Link, LinkProps, NavigateFunction, Router, RouterProps, useNavigate } from './router.js';
|
|
3
|
+
export { C as ContentStoreProviderProd, g as EmbedFieldValue, h as EmbedType, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, Y as YaEmbed, f as YaEmbedProps, i as YaLink, j as YaLinkProps, p as parseEmbedUrl, s as serializeEmbedValue, u as useContentStoreProd } from './MarkdownText-DHJo0ofY.js';
|
|
4
|
+
export { Link, LinkProps, NavigateFunction, Router, RouterProps, ScrollRestoration, useNavigate } from './router.js';
|
|
5
5
|
export { Route, Switch, useParams } from 'wouter';
|
|
6
6
|
export { A as AssetResolverFn, C as ContentRegistry, c as contentRegistry, a as getAllContent, g as getContent, h as hasContent, r as registerContent, b as resolveAssetUrl, s as setAssetResolver } from './asset-resolver-BnIvDkVv.js';
|
|
7
7
|
export { i as initBuilderSelection } from './builder-selection-CYP91nRu.js';
|
package/dist/index.js
CHANGED
|
@@ -963,11 +963,10 @@ function ContentStoreProvider({
|
|
|
963
963
|
}
|
|
964
964
|
|
|
965
965
|
// src/components/ContentStoreProvider.prod.tsx
|
|
966
|
-
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
966
|
+
import { createContext as createContext2, useContext as useContext2, useMemo } from "react";
|
|
967
967
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
968
|
-
var
|
|
969
|
-
|
|
970
|
-
getValue: (fieldId) => contentMap2.get(fieldId) ?? "",
|
|
968
|
+
var defaultStore = {
|
|
969
|
+
getValue: () => "",
|
|
971
970
|
setValue: () => {
|
|
972
971
|
},
|
|
973
972
|
// No-op in production
|
|
@@ -980,12 +979,50 @@ var staticStore = {
|
|
|
980
979
|
// No-op, return empty unsubscribe
|
|
981
980
|
saveToWorker: void 0
|
|
982
981
|
};
|
|
983
|
-
var ContentStoreContext2 = createContext2(
|
|
982
|
+
var ContentStoreContext2 = createContext2(defaultStore);
|
|
984
983
|
function useContentStore2() {
|
|
985
984
|
return useContext2(ContentStoreContext2);
|
|
986
985
|
}
|
|
987
|
-
function ContentStoreProvider2({ children }) {
|
|
988
|
-
|
|
986
|
+
function ContentStoreProvider2({ children, initialContent }) {
|
|
987
|
+
const parentStore = useContext2(ContentStoreContext2);
|
|
988
|
+
const hasParent = parentStore !== defaultStore;
|
|
989
|
+
const store = useMemo(() => {
|
|
990
|
+
if (initialContent) {
|
|
991
|
+
return {
|
|
992
|
+
getValue: (fieldId) => initialContent[fieldId] ?? "",
|
|
993
|
+
setValue: () => {
|
|
994
|
+
},
|
|
995
|
+
// No-op in production
|
|
996
|
+
mode: "read-only",
|
|
997
|
+
setMode: () => {
|
|
998
|
+
},
|
|
999
|
+
// No-op in production
|
|
1000
|
+
subscribe: () => () => {
|
|
1001
|
+
},
|
|
1002
|
+
// No-op, return empty unsubscribe
|
|
1003
|
+
saveToWorker: void 0
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
if (hasParent) {
|
|
1007
|
+
return parentStore;
|
|
1008
|
+
}
|
|
1009
|
+
const registryContent = getAllContent();
|
|
1010
|
+
return {
|
|
1011
|
+
getValue: (fieldId) => registryContent[fieldId] ?? "",
|
|
1012
|
+
setValue: () => {
|
|
1013
|
+
},
|
|
1014
|
+
// No-op in production
|
|
1015
|
+
mode: "read-only",
|
|
1016
|
+
setMode: () => {
|
|
1017
|
+
},
|
|
1018
|
+
// No-op in production
|
|
1019
|
+
subscribe: () => () => {
|
|
1020
|
+
},
|
|
1021
|
+
// No-op, return empty unsubscribe
|
|
1022
|
+
saveToWorker: void 0
|
|
1023
|
+
};
|
|
1024
|
+
}, [initialContent, hasParent, parentStore]);
|
|
1025
|
+
return /* @__PURE__ */ jsx2(ContentStoreContext2.Provider, { value: store, children });
|
|
989
1026
|
}
|
|
990
1027
|
|
|
991
1028
|
// src/components/YaText.tsx
|
|
@@ -1271,13 +1308,13 @@ function SafeHtml({ content, className, mode = "read-only" }) {
|
|
|
1271
1308
|
}
|
|
1272
1309
|
|
|
1273
1310
|
// src/hooks/useAnimatedText.ts
|
|
1274
|
-
import { useMemo as
|
|
1311
|
+
import { useMemo as useMemo4 } from "react";
|
|
1275
1312
|
|
|
1276
1313
|
// src/hooks/useAIEditAnimation.ts
|
|
1277
|
-
import { useState as useState3, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback4, useMemo as
|
|
1314
|
+
import { useState as useState3, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback4, useMemo as useMemo3 } from "react";
|
|
1278
1315
|
|
|
1279
1316
|
// src/contexts/AIEditContext.tsx
|
|
1280
|
-
import { createContext as createContext3, useContext as useContext3, useCallback as useCallback3, useRef as useRef3, useMemo } from "react";
|
|
1317
|
+
import { createContext as createContext3, useContext as useContext3, useCallback as useCallback3, useRef as useRef3, useMemo as useMemo2 } from "react";
|
|
1281
1318
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1282
1319
|
var AIEditContext = createContext3(null);
|
|
1283
1320
|
function useAIEditContext() {
|
|
@@ -1389,7 +1426,7 @@ function AIEditProvider({ children, staggerDelay = 100 }) {
|
|
|
1389
1426
|
},
|
|
1390
1427
|
[notifyListeners]
|
|
1391
1428
|
);
|
|
1392
|
-
const value =
|
|
1429
|
+
const value = useMemo2(
|
|
1393
1430
|
() => ({
|
|
1394
1431
|
queueAnimation,
|
|
1395
1432
|
cancelAnimation,
|
|
@@ -1508,7 +1545,7 @@ function useAIEditAnimation(fieldId, value, options) {
|
|
|
1508
1545
|
}
|
|
1509
1546
|
};
|
|
1510
1547
|
}, []);
|
|
1511
|
-
const wrapperProps =
|
|
1548
|
+
const wrapperProps = useMemo3(
|
|
1512
1549
|
() => ({
|
|
1513
1550
|
className: phase === "animating" ? "ya-ai-editing" : phase === "complete" ? "ya-ai-complete" : "",
|
|
1514
1551
|
"data-ai-editing": phase === "animating"
|
|
@@ -1730,7 +1767,7 @@ function useAnimatedText(fieldId, content, options = {}) {
|
|
|
1730
1767
|
onStart,
|
|
1731
1768
|
onComplete
|
|
1732
1769
|
} = options;
|
|
1733
|
-
const customStrategy =
|
|
1770
|
+
const customStrategy = useMemo4(() => {
|
|
1734
1771
|
if (charDelay === 50) {
|
|
1735
1772
|
return textTypingStrategy;
|
|
1736
1773
|
}
|
|
@@ -1769,7 +1806,7 @@ function useAnimatedText(fieldId, content, options = {}) {
|
|
|
1769
1806
|
onStart,
|
|
1770
1807
|
onComplete
|
|
1771
1808
|
});
|
|
1772
|
-
const cursorPosition =
|
|
1809
|
+
const cursorPosition = useMemo4(() => {
|
|
1773
1810
|
if (!isAnimating) return null;
|
|
1774
1811
|
const diff = computeTextDiff(content, displayValue);
|
|
1775
1812
|
const { deleteDuration, typeDuration } = calculateAnimationTiming(diff, {
|
|
@@ -5872,6 +5909,102 @@ function Router({ children, base }) {
|
|
|
5872
5909
|
return /* @__PURE__ */ jsx21(WouterRouter, { base: basename, children });
|
|
5873
5910
|
}
|
|
5874
5911
|
|
|
5912
|
+
// src/router/ScrollRestoration.tsx
|
|
5913
|
+
import { useEffect as useEffect15, useRef as useRef15 } from "react";
|
|
5914
|
+
import { useLocation as useLocation3 } from "wouter";
|
|
5915
|
+
var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
|
|
5916
|
+
var HISTORY_INDEX_KEY = "yoamigo-history-index";
|
|
5917
|
+
function getScrollPositions() {
|
|
5918
|
+
if (typeof sessionStorage === "undefined") return {};
|
|
5919
|
+
try {
|
|
5920
|
+
const stored = sessionStorage.getItem(SCROLL_POSITIONS_KEY);
|
|
5921
|
+
return stored ? JSON.parse(stored) : {};
|
|
5922
|
+
} catch {
|
|
5923
|
+
return {};
|
|
5924
|
+
}
|
|
5925
|
+
}
|
|
5926
|
+
function saveScrollPositions(positions) {
|
|
5927
|
+
if (typeof sessionStorage === "undefined") return;
|
|
5928
|
+
try {
|
|
5929
|
+
sessionStorage.setItem(SCROLL_POSITIONS_KEY, JSON.stringify(positions));
|
|
5930
|
+
} catch {
|
|
5931
|
+
}
|
|
5932
|
+
}
|
|
5933
|
+
function getHistoryIndex() {
|
|
5934
|
+
if (typeof history === "undefined") return 0;
|
|
5935
|
+
const state = history.state;
|
|
5936
|
+
if (state && typeof state[HISTORY_INDEX_KEY] === "number") {
|
|
5937
|
+
return state[HISTORY_INDEX_KEY];
|
|
5938
|
+
}
|
|
5939
|
+
return 0;
|
|
5940
|
+
}
|
|
5941
|
+
function setHistoryIndex(index) {
|
|
5942
|
+
if (typeof history === "undefined") return;
|
|
5943
|
+
const newState = { ...history.state, [HISTORY_INDEX_KEY]: index };
|
|
5944
|
+
history.replaceState(newState, "");
|
|
5945
|
+
}
|
|
5946
|
+
var globalHistoryIndex = 0;
|
|
5947
|
+
function ScrollRestoration() {
|
|
5948
|
+
const [location] = useLocation3();
|
|
5949
|
+
const previousLocation = useRef15(location);
|
|
5950
|
+
const isPopState = useRef15(false);
|
|
5951
|
+
const scrollPositionsRef = useRef15({});
|
|
5952
|
+
useEffect15(() => {
|
|
5953
|
+
if (typeof history !== "undefined" && "scrollRestoration" in history) {
|
|
5954
|
+
history.scrollRestoration = "manual";
|
|
5955
|
+
}
|
|
5956
|
+
scrollPositionsRef.current = getScrollPositions();
|
|
5957
|
+
const existingIndex = getHistoryIndex();
|
|
5958
|
+
if (existingIndex === 0 && !history.state?.[HISTORY_INDEX_KEY]) {
|
|
5959
|
+
globalHistoryIndex = 1;
|
|
5960
|
+
setHistoryIndex(globalHistoryIndex);
|
|
5961
|
+
} else {
|
|
5962
|
+
globalHistoryIndex = existingIndex;
|
|
5963
|
+
}
|
|
5964
|
+
const handlePopState = () => {
|
|
5965
|
+
isPopState.current = true;
|
|
5966
|
+
};
|
|
5967
|
+
window.addEventListener("popstate", handlePopState);
|
|
5968
|
+
return () => window.removeEventListener("popstate", handlePopState);
|
|
5969
|
+
}, []);
|
|
5970
|
+
useEffect15(() => {
|
|
5971
|
+
if (previousLocation.current === location) return;
|
|
5972
|
+
const prevHistoryIndex = globalHistoryIndex;
|
|
5973
|
+
const currentScrollY = window.scrollY;
|
|
5974
|
+
if (isPopState.current) {
|
|
5975
|
+
isPopState.current = false;
|
|
5976
|
+
globalHistoryIndex = getHistoryIndex() || globalHistoryIndex;
|
|
5977
|
+
const savedScroll = scrollPositionsRef.current[`${globalHistoryIndex}-${location}`];
|
|
5978
|
+
requestAnimationFrame(() => {
|
|
5979
|
+
window.scrollTo({ top: savedScroll ?? 0, behavior: "instant" });
|
|
5980
|
+
});
|
|
5981
|
+
} else {
|
|
5982
|
+
scrollPositionsRef.current[`${prevHistoryIndex}-${previousLocation.current}`] = currentScrollY;
|
|
5983
|
+
saveScrollPositions(scrollPositionsRef.current);
|
|
5984
|
+
globalHistoryIndex = prevHistoryIndex + 1;
|
|
5985
|
+
setHistoryIndex(globalHistoryIndex);
|
|
5986
|
+
window.scrollTo({ top: 0, behavior: "instant" });
|
|
5987
|
+
}
|
|
5988
|
+
previousLocation.current = location;
|
|
5989
|
+
}, [location]);
|
|
5990
|
+
useEffect15(() => {
|
|
5991
|
+
let timeoutId;
|
|
5992
|
+
const handleScroll = () => {
|
|
5993
|
+
clearTimeout(timeoutId);
|
|
5994
|
+
timeoutId = setTimeout(() => {
|
|
5995
|
+
scrollPositionsRef.current[`${globalHistoryIndex}-${location}`] = window.scrollY;
|
|
5996
|
+
saveScrollPositions(scrollPositionsRef.current);
|
|
5997
|
+
}, 100);
|
|
5998
|
+
};
|
|
5999
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
6000
|
+
return () => {
|
|
6001
|
+
clearTimeout(timeoutId);
|
|
6002
|
+
window.removeEventListener("scroll", handleScroll);
|
|
6003
|
+
};
|
|
6004
|
+
}, [location]);
|
|
6005
|
+
return null;
|
|
6006
|
+
}
|
|
6007
|
+
|
|
5875
6008
|
// src/router/index.ts
|
|
5876
6009
|
import { Route, Switch, useParams } from "wouter";
|
|
5877
6010
|
export {
|
|
@@ -5884,6 +6017,7 @@ export {
|
|
|
5884
6017
|
Router,
|
|
5885
6018
|
SafeHtml,
|
|
5886
6019
|
SafeTriangleBelow,
|
|
6020
|
+
ScrollRestoration,
|
|
5887
6021
|
MpImage as StaticImage,
|
|
5888
6022
|
MpText as StaticText,
|
|
5889
6023
|
Switch,
|
package/dist/prod.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, p as parseEmbedUrl, u as useContentStore } from './MarkdownText-
|
|
1
|
+
export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, p as parseEmbedUrl, u as useContentStore } from './MarkdownText-DHJo0ofY.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import React, { CSSProperties, ReactNode } from 'react';
|
|
4
|
-
export { Link, LinkProps, NavigateFunction, Router, RouterProps, useNavigate } from './router.js';
|
|
4
|
+
export { Link, LinkProps, NavigateFunction, Router, RouterProps, ScrollRestoration, useNavigate } from './router.js';
|
|
5
5
|
export { Route, Switch, useParams } from 'wouter';
|
|
6
6
|
export { A as AssetResolverFn, C as ContentRegistry, c as contentRegistry, a as getAllContent, g as getContent, h as hasContent, r as registerContent, b as resolveAssetUrl, s as setAssetResolver } from './asset-resolver-BnIvDkVv.js';
|
|
7
7
|
|
package/dist/prod.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/ContentStoreProvider.prod.tsx
|
|
2
|
-
import { createContext, useContext } from "react";
|
|
2
|
+
import { createContext, useContext, useMemo } from "react";
|
|
3
3
|
|
|
4
4
|
// src/lib/content-registry.ts
|
|
5
5
|
var contentMap = /* @__PURE__ */ new Map();
|
|
@@ -24,9 +24,8 @@ var contentRegistry = {
|
|
|
24
24
|
|
|
25
25
|
// src/components/ContentStoreProvider.prod.tsx
|
|
26
26
|
import { jsx } from "react/jsx-runtime";
|
|
27
|
-
var
|
|
28
|
-
|
|
29
|
-
getValue: (fieldId) => contentMap2.get(fieldId) ?? "",
|
|
27
|
+
var defaultStore = {
|
|
28
|
+
getValue: () => "",
|
|
30
29
|
setValue: () => {
|
|
31
30
|
},
|
|
32
31
|
// No-op in production
|
|
@@ -39,12 +38,50 @@ var staticStore = {
|
|
|
39
38
|
// No-op, return empty unsubscribe
|
|
40
39
|
saveToWorker: void 0
|
|
41
40
|
};
|
|
42
|
-
var ContentStoreContext = createContext(
|
|
41
|
+
var ContentStoreContext = createContext(defaultStore);
|
|
43
42
|
function useContentStore() {
|
|
44
43
|
return useContext(ContentStoreContext);
|
|
45
44
|
}
|
|
46
|
-
function ContentStoreProvider({ children }) {
|
|
47
|
-
|
|
45
|
+
function ContentStoreProvider({ children, initialContent }) {
|
|
46
|
+
const parentStore = useContext(ContentStoreContext);
|
|
47
|
+
const hasParent = parentStore !== defaultStore;
|
|
48
|
+
const store = useMemo(() => {
|
|
49
|
+
if (initialContent) {
|
|
50
|
+
return {
|
|
51
|
+
getValue: (fieldId) => initialContent[fieldId] ?? "",
|
|
52
|
+
setValue: () => {
|
|
53
|
+
},
|
|
54
|
+
// No-op in production
|
|
55
|
+
mode: "read-only",
|
|
56
|
+
setMode: () => {
|
|
57
|
+
},
|
|
58
|
+
// No-op in production
|
|
59
|
+
subscribe: () => () => {
|
|
60
|
+
},
|
|
61
|
+
// No-op, return empty unsubscribe
|
|
62
|
+
saveToWorker: void 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (hasParent) {
|
|
66
|
+
return parentStore;
|
|
67
|
+
}
|
|
68
|
+
const registryContent = getAllContent();
|
|
69
|
+
return {
|
|
70
|
+
getValue: (fieldId) => registryContent[fieldId] ?? "",
|
|
71
|
+
setValue: () => {
|
|
72
|
+
},
|
|
73
|
+
// No-op in production
|
|
74
|
+
mode: "read-only",
|
|
75
|
+
setMode: () => {
|
|
76
|
+
},
|
|
77
|
+
// No-op in production
|
|
78
|
+
subscribe: () => () => {
|
|
79
|
+
},
|
|
80
|
+
// No-op, return empty unsubscribe
|
|
81
|
+
saveToWorker: void 0
|
|
82
|
+
};
|
|
83
|
+
}, [initialContent, hasParent, parentStore]);
|
|
84
|
+
return /* @__PURE__ */ jsx(ContentStoreContext.Provider, { value: store, children });
|
|
48
85
|
}
|
|
49
86
|
|
|
50
87
|
// src/components/StaticText.tsx
|
|
@@ -916,6 +953,102 @@ function Router({ children, base }) {
|
|
|
916
953
|
return /* @__PURE__ */ jsx12(WouterRouter, { base: basename, children });
|
|
917
954
|
}
|
|
918
955
|
|
|
956
|
+
// src/router/ScrollRestoration.tsx
|
|
957
|
+
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
958
|
+
import { useLocation as useLocation3 } from "wouter";
|
|
959
|
+
var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
|
|
960
|
+
var HISTORY_INDEX_KEY = "yoamigo-history-index";
|
|
961
|
+
function getScrollPositions() {
|
|
962
|
+
if (typeof sessionStorage === "undefined") return {};
|
|
963
|
+
try {
|
|
964
|
+
const stored = sessionStorage.getItem(SCROLL_POSITIONS_KEY);
|
|
965
|
+
return stored ? JSON.parse(stored) : {};
|
|
966
|
+
} catch {
|
|
967
|
+
return {};
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
function saveScrollPositions(positions) {
|
|
971
|
+
if (typeof sessionStorage === "undefined") return;
|
|
972
|
+
try {
|
|
973
|
+
sessionStorage.setItem(SCROLL_POSITIONS_KEY, JSON.stringify(positions));
|
|
974
|
+
} catch {
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
function getHistoryIndex() {
|
|
978
|
+
if (typeof history === "undefined") return 0;
|
|
979
|
+
const state = history.state;
|
|
980
|
+
if (state && typeof state[HISTORY_INDEX_KEY] === "number") {
|
|
981
|
+
return state[HISTORY_INDEX_KEY];
|
|
982
|
+
}
|
|
983
|
+
return 0;
|
|
984
|
+
}
|
|
985
|
+
function setHistoryIndex(index) {
|
|
986
|
+
if (typeof history === "undefined") return;
|
|
987
|
+
const newState = { ...history.state, [HISTORY_INDEX_KEY]: index };
|
|
988
|
+
history.replaceState(newState, "");
|
|
989
|
+
}
|
|
990
|
+
var globalHistoryIndex = 0;
|
|
991
|
+
function ScrollRestoration() {
|
|
992
|
+
const [location] = useLocation3();
|
|
993
|
+
const previousLocation = useRef4(location);
|
|
994
|
+
const isPopState = useRef4(false);
|
|
995
|
+
const scrollPositionsRef = useRef4({});
|
|
996
|
+
useEffect4(() => {
|
|
997
|
+
if (typeof history !== "undefined" && "scrollRestoration" in history) {
|
|
998
|
+
history.scrollRestoration = "manual";
|
|
999
|
+
}
|
|
1000
|
+
scrollPositionsRef.current = getScrollPositions();
|
|
1001
|
+
const existingIndex = getHistoryIndex();
|
|
1002
|
+
if (existingIndex === 0 && !history.state?.[HISTORY_INDEX_KEY]) {
|
|
1003
|
+
globalHistoryIndex = 1;
|
|
1004
|
+
setHistoryIndex(globalHistoryIndex);
|
|
1005
|
+
} else {
|
|
1006
|
+
globalHistoryIndex = existingIndex;
|
|
1007
|
+
}
|
|
1008
|
+
const handlePopState = () => {
|
|
1009
|
+
isPopState.current = true;
|
|
1010
|
+
};
|
|
1011
|
+
window.addEventListener("popstate", handlePopState);
|
|
1012
|
+
return () => window.removeEventListener("popstate", handlePopState);
|
|
1013
|
+
}, []);
|
|
1014
|
+
useEffect4(() => {
|
|
1015
|
+
if (previousLocation.current === location) return;
|
|
1016
|
+
const prevHistoryIndex = globalHistoryIndex;
|
|
1017
|
+
const currentScrollY = window.scrollY;
|
|
1018
|
+
if (isPopState.current) {
|
|
1019
|
+
isPopState.current = false;
|
|
1020
|
+
globalHistoryIndex = getHistoryIndex() || globalHistoryIndex;
|
|
1021
|
+
const savedScroll = scrollPositionsRef.current[`${globalHistoryIndex}-${location}`];
|
|
1022
|
+
requestAnimationFrame(() => {
|
|
1023
|
+
window.scrollTo({ top: savedScroll ?? 0, behavior: "instant" });
|
|
1024
|
+
});
|
|
1025
|
+
} else {
|
|
1026
|
+
scrollPositionsRef.current[`${prevHistoryIndex}-${previousLocation.current}`] = currentScrollY;
|
|
1027
|
+
saveScrollPositions(scrollPositionsRef.current);
|
|
1028
|
+
globalHistoryIndex = prevHistoryIndex + 1;
|
|
1029
|
+
setHistoryIndex(globalHistoryIndex);
|
|
1030
|
+
window.scrollTo({ top: 0, behavior: "instant" });
|
|
1031
|
+
}
|
|
1032
|
+
previousLocation.current = location;
|
|
1033
|
+
}, [location]);
|
|
1034
|
+
useEffect4(() => {
|
|
1035
|
+
let timeoutId;
|
|
1036
|
+
const handleScroll = () => {
|
|
1037
|
+
clearTimeout(timeoutId);
|
|
1038
|
+
timeoutId = setTimeout(() => {
|
|
1039
|
+
scrollPositionsRef.current[`${globalHistoryIndex}-${location}`] = window.scrollY;
|
|
1040
|
+
saveScrollPositions(scrollPositionsRef.current);
|
|
1041
|
+
}, 100);
|
|
1042
|
+
};
|
|
1043
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
1044
|
+
return () => {
|
|
1045
|
+
clearTimeout(timeoutId);
|
|
1046
|
+
window.removeEventListener("scroll", handleScroll);
|
|
1047
|
+
};
|
|
1048
|
+
}, [location]);
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
919
1052
|
// src/router/index.ts
|
|
920
1053
|
import { Route, Switch, useParams } from "wouter";
|
|
921
1054
|
export {
|
|
@@ -925,6 +1058,7 @@ export {
|
|
|
925
1058
|
Route,
|
|
926
1059
|
Router,
|
|
927
1060
|
SafeHtml,
|
|
1061
|
+
ScrollRestoration,
|
|
928
1062
|
StaticContainer,
|
|
929
1063
|
StaticEmbed,
|
|
930
1064
|
MpImage as StaticImage,
|
package/dist/router.d.ts
CHANGED
|
@@ -44,4 +44,15 @@ interface RouterProps {
|
|
|
44
44
|
}
|
|
45
45
|
declare function Router({ children, base }: RouterProps): react_jsx_runtime.JSX.Element;
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* ScrollRestoration Component
|
|
49
|
+
*
|
|
50
|
+
* Handles scroll position management for SPA navigation:
|
|
51
|
+
* - Forward navigation (link clicks) → instantly at top (no scroll animation)
|
|
52
|
+
* - Back navigation (browser back) → restore previous scroll position
|
|
53
|
+
*
|
|
54
|
+
* Uses sessionStorage to persist scroll positions across page refreshes.
|
|
55
|
+
*/
|
|
56
|
+
declare function ScrollRestoration(): null;
|
|
57
|
+
|
|
58
|
+
export { Link, type LinkProps, type NavigateFunction, Router, type RouterProps$1 as RouterProps, ScrollRestoration, useNavigate };
|
package/dist/router.js
CHANGED
|
@@ -40,12 +40,109 @@ function Router({ children, base }) {
|
|
|
40
40
|
return /* @__PURE__ */ jsx2(WouterRouter, { base: basename, children });
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// src/router/ScrollRestoration.tsx
|
|
44
|
+
import { useEffect, useRef } from "react";
|
|
45
|
+
import { useLocation as useLocation2 } from "wouter";
|
|
46
|
+
var SCROLL_POSITIONS_KEY = "yoamigo-scroll-positions";
|
|
47
|
+
var HISTORY_INDEX_KEY = "yoamigo-history-index";
|
|
48
|
+
function getScrollPositions() {
|
|
49
|
+
if (typeof sessionStorage === "undefined") return {};
|
|
50
|
+
try {
|
|
51
|
+
const stored = sessionStorage.getItem(SCROLL_POSITIONS_KEY);
|
|
52
|
+
return stored ? JSON.parse(stored) : {};
|
|
53
|
+
} catch {
|
|
54
|
+
return {};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function saveScrollPositions(positions) {
|
|
58
|
+
if (typeof sessionStorage === "undefined") return;
|
|
59
|
+
try {
|
|
60
|
+
sessionStorage.setItem(SCROLL_POSITIONS_KEY, JSON.stringify(positions));
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function getHistoryIndex() {
|
|
65
|
+
if (typeof history === "undefined") return 0;
|
|
66
|
+
const state = history.state;
|
|
67
|
+
if (state && typeof state[HISTORY_INDEX_KEY] === "number") {
|
|
68
|
+
return state[HISTORY_INDEX_KEY];
|
|
69
|
+
}
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
function setHistoryIndex(index) {
|
|
73
|
+
if (typeof history === "undefined") return;
|
|
74
|
+
const newState = { ...history.state, [HISTORY_INDEX_KEY]: index };
|
|
75
|
+
history.replaceState(newState, "");
|
|
76
|
+
}
|
|
77
|
+
var globalHistoryIndex = 0;
|
|
78
|
+
function ScrollRestoration() {
|
|
79
|
+
const [location] = useLocation2();
|
|
80
|
+
const previousLocation = useRef(location);
|
|
81
|
+
const isPopState = useRef(false);
|
|
82
|
+
const scrollPositionsRef = useRef({});
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (typeof history !== "undefined" && "scrollRestoration" in history) {
|
|
85
|
+
history.scrollRestoration = "manual";
|
|
86
|
+
}
|
|
87
|
+
scrollPositionsRef.current = getScrollPositions();
|
|
88
|
+
const existingIndex = getHistoryIndex();
|
|
89
|
+
if (existingIndex === 0 && !history.state?.[HISTORY_INDEX_KEY]) {
|
|
90
|
+
globalHistoryIndex = 1;
|
|
91
|
+
setHistoryIndex(globalHistoryIndex);
|
|
92
|
+
} else {
|
|
93
|
+
globalHistoryIndex = existingIndex;
|
|
94
|
+
}
|
|
95
|
+
const handlePopState = () => {
|
|
96
|
+
isPopState.current = true;
|
|
97
|
+
};
|
|
98
|
+
window.addEventListener("popstate", handlePopState);
|
|
99
|
+
return () => window.removeEventListener("popstate", handlePopState);
|
|
100
|
+
}, []);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (previousLocation.current === location) return;
|
|
103
|
+
const prevHistoryIndex = globalHistoryIndex;
|
|
104
|
+
const currentScrollY = window.scrollY;
|
|
105
|
+
if (isPopState.current) {
|
|
106
|
+
isPopState.current = false;
|
|
107
|
+
globalHistoryIndex = getHistoryIndex() || globalHistoryIndex;
|
|
108
|
+
const savedScroll = scrollPositionsRef.current[`${globalHistoryIndex}-${location}`];
|
|
109
|
+
requestAnimationFrame(() => {
|
|
110
|
+
window.scrollTo({ top: savedScroll ?? 0, behavior: "instant" });
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
scrollPositionsRef.current[`${prevHistoryIndex}-${previousLocation.current}`] = currentScrollY;
|
|
114
|
+
saveScrollPositions(scrollPositionsRef.current);
|
|
115
|
+
globalHistoryIndex = prevHistoryIndex + 1;
|
|
116
|
+
setHistoryIndex(globalHistoryIndex);
|
|
117
|
+
window.scrollTo({ top: 0, behavior: "instant" });
|
|
118
|
+
}
|
|
119
|
+
previousLocation.current = location;
|
|
120
|
+
}, [location]);
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
let timeoutId;
|
|
123
|
+
const handleScroll = () => {
|
|
124
|
+
clearTimeout(timeoutId);
|
|
125
|
+
timeoutId = setTimeout(() => {
|
|
126
|
+
scrollPositionsRef.current[`${globalHistoryIndex}-${location}`] = window.scrollY;
|
|
127
|
+
saveScrollPositions(scrollPositionsRef.current);
|
|
128
|
+
}, 100);
|
|
129
|
+
};
|
|
130
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
131
|
+
return () => {
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
window.removeEventListener("scroll", handleScroll);
|
|
134
|
+
};
|
|
135
|
+
}, [location]);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
43
139
|
// src/router/index.ts
|
|
44
140
|
import { Route, Switch, useParams } from "wouter";
|
|
45
141
|
export {
|
|
46
142
|
Link,
|
|
47
143
|
Route,
|
|
48
144
|
Router,
|
|
145
|
+
ScrollRestoration,
|
|
49
146
|
Switch,
|
|
50
147
|
useNavigate,
|
|
51
148
|
useParams
|