@ahnseungchan/webviewkit 2.0.0 → 2.2.0

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/index.js CHANGED
@@ -44,6 +44,7 @@ __export(index_exports, {
44
44
  FLUTTER_READY_EVENT: () => FLUTTER_READY_EVENT,
45
45
  FLUTTER_UNIFIED_HANDLER: () => FLUTTER_UNIFIED_HANDLER,
46
46
  HistoryAction: () => HistoryAction,
47
+ KEEP_ALIVE_LIMIT: () => KEEP_ALIVE_LIMIT,
47
48
  RN_BRIDGE_HANDLER: () => RN_BRIDGE_HANDLER,
48
49
  STACK_BRIDGE_METHODS: () => STACK_BRIDGE_METHODS,
49
50
  STACK_TRANSITION_MS: () => STACK_TRANSITION_MS,
@@ -77,6 +78,7 @@ __export(index_exports, {
77
78
  serializeBridgeMessage: () => serializeBridgeMessage,
78
79
  toStackPath: () => toStackPath,
79
80
  useActivity: () => useActivity,
81
+ useOnRevive: () => useOnRevive,
80
82
  useParams: () => useParams,
81
83
  useStackRouter: () => useStackRouter,
82
84
  waitForBridgeHost: () => waitForBridgeHost
@@ -84,12 +86,14 @@ __export(index_exports, {
84
86
  module.exports = __toCommonJS(index_exports);
85
87
 
86
88
  // src/constants.ts
87
- var STACK_TRANSITION_MS = 300;
89
+ var STACK_TRANSITION_MS = 500;
88
90
  var TRANSITION_END_GRACE_MS = 50;
89
91
  var BACK_TIMEOUT_MS = 1e3;
90
92
  var BRIDGE_TIMEOUT_MS = 5e3;
91
93
  var BRIDGE_HOST_WAIT_MS = 3e3;
92
94
  var BRIDGE_HOST_POLL_MS = 100;
95
+ var KEEP_ALIVE_LIMIT = 5;
96
+ var DEV_MOUNTED_PAGES_WARN = 15;
93
97
 
94
98
  // src/bridge/detect-host.ts
95
99
  var FLUTTER_READY_EVENT = "flutterInAppWebViewPlatformReady";
@@ -864,19 +868,55 @@ var import_styled4 = __toESM(require("@emotion/styled"));
864
868
 
865
869
  // src/stack-router/stack-router-provider.tsx
866
870
  var import_styled3 = __toESM(require("@emotion/styled"));
867
- var import_react9 = require("react");
871
+ var import_react10 = require("react");
868
872
 
869
873
  // src/stack-router/_components/header.tsx
870
874
  var import_styled = __toESM(require("@emotion/styled"));
875
+ var import_react4 = require("react");
876
+
877
+ // src/stack-router/activity-context.tsx
878
+ var import_react3 = require("react");
879
+ var ActivityContext = (0, import_react3.createContext)(null);
880
+ function useActivity() {
881
+ const context = (0, import_react3.useContext)(ActivityContext);
882
+ if (!context) {
883
+ throw new Error(
884
+ "useActivity must be used inside a StackRouterProvider page"
885
+ );
886
+ }
887
+ return context;
888
+ }
889
+ function useParams() {
890
+ return useActivity().params;
891
+ }
892
+ function useOnRevive(callback) {
893
+ const { revision, data } = useActivity();
894
+ const callbackRef = (0, import_react3.useRef)(callback);
895
+ callbackRef.current = callback;
896
+ const lastRevisionRef = (0, import_react3.useRef)(revision);
897
+ (0, import_react3.useEffect)(() => {
898
+ if (revision > lastRevisionRef.current) callbackRef.current(data);
899
+ lastRevisionRef.current = revision;
900
+ }, [revision, data]);
901
+ }
902
+
903
+ // src/stack-router/_components/header.tsx
871
904
  var import_jsx_runtime3 = require("@emotion/react/jsx-runtime");
872
905
  var Header = ({ title }) => {
906
+ var _a;
907
+ const activity = (0, import_react4.useContext)(ActivityContext);
873
908
  const { currentPath: currentPath2, canGoBack } = useStackRouter();
909
+ const path = (_a = activity == null ? void 0 : activity.path) != null ? _a : currentPath2;
910
+ const showBack = activity ? activity.index > 0 : canGoBack;
874
911
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(StyledHeader, { children: [
875
- canGoBack && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(back_router_default, {}),
876
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StyledTitle, { children: title != null ? title : currentPath2 })
912
+ showBack && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(back_router_default, {}),
913
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StyledTitle, { children: title != null ? title : path })
877
914
  ] });
878
915
  };
879
916
  var StyledHeader = import_styled.default.header`
917
+ position: sticky;
918
+ top: 0;
919
+ z-index: 1;
880
920
  width: 100%;
881
921
  height: 64px;
882
922
  flex-shrink: 0;
@@ -889,49 +929,77 @@ var StyledHeader = import_styled.default.header`
889
929
  `;
890
930
  var StyledTitle = import_styled.default.h1`
891
931
  margin: 0;
932
+ min-width: 0;
892
933
  font-size: 1.25rem;
893
934
  font-weight: 600;
894
935
  color: var(--wvk-header-color, #111827);
936
+ white-space: nowrap;
937
+ overflow: hidden;
938
+ text-overflow: ellipsis;
895
939
  `;
896
940
  var header_default = Header;
897
941
 
898
942
  // src/stack-router/_components/stack-page.tsx
899
- var import_react3 = require("@emotion/react");
943
+ var import_react5 = require("@emotion/react");
900
944
  var import_styled2 = __toESM(require("@emotion/styled"));
901
- var import_react4 = require("react");
945
+ var import_react6 = require("react");
902
946
  var import_jsx_runtime4 = require("@emotion/react/jsx-runtime");
903
- var slideInRight = import_react3.keyframes`
904
- from { transform: translate3d(100%, 0, 0); }
905
- to { transform: translate3d(0, 0, 0); }
906
- `;
907
- var slideOutLeft = import_react3.keyframes`
908
- from { transform: translate3d(0, 0, 0); opacity: 1; }
909
- to { transform: translate3d(-30%, 0, 0); opacity: 0.6; }
947
+ var IOS_EASING = "cubic-bezier(0.32, 0.72, 0, 1)";
948
+ var FADE_EASING = "ease";
949
+ var PARALLAX_OFFSET = "-30%";
950
+ var EDGE_SHADOW = "var(--wvk-edge-shadow, -6px 0 24px rgba(0, 0, 0, 0.12))";
951
+ var coverIn = import_react5.keyframes`
952
+ from { transform: translate3d(100%, 0, 0); box-shadow: none; }
953
+ to { transform: translate3d(0, 0, 0); box-shadow: ${EDGE_SHADOW}; }
910
954
  `;
911
- var slideInLeft = import_react3.keyframes`
912
- from { transform: translate3d(-30%, 0, 0); opacity: 0.6; }
913
- to { transform: translate3d(0, 0, 0); opacity: 1; }
955
+ var coverOut = import_react5.keyframes`
956
+ from { transform: translate3d(0, 0, 0); box-shadow: ${EDGE_SHADOW}; }
957
+ to { transform: translate3d(100%, 0, 0); box-shadow: none; }
914
958
  `;
915
- var slideOutRight = import_react3.keyframes`
959
+ var parallaxOut = import_react5.keyframes`
916
960
  from { transform: translate3d(0, 0, 0); }
917
- to { transform: translate3d(100%, 0, 0); }
961
+ to { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }
962
+ `;
963
+ var parallaxIn = import_react5.keyframes`
964
+ from { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }
965
+ to { transform: translate3d(0, 0, 0); }
918
966
  `;
919
- var fadeIn = import_react3.keyframes`
967
+ var dimIn = import_react5.keyframes`
920
968
  from { opacity: 0; }
921
969
  to { opacity: 1; }
922
970
  `;
923
- var fadeOut = import_react3.keyframes`
971
+ var dimOut = import_react5.keyframes`
924
972
  from { opacity: 1; }
925
973
  to { opacity: 0; }
926
974
  `;
927
- var SLIDE_KEYFRAMES = {
928
- push: { enter: slideInRight, exit: slideOutLeft },
929
- pop: { enter: slideInLeft, exit: slideOutRight }
930
- };
931
- var FADE_KEYFRAMES = { enter: fadeIn, exit: fadeOut };
932
- function pickKeyframes(transition, direction, pageState) {
933
- if (transition === "fade") return FADE_KEYFRAMES[pageState];
934
- return SLIDE_KEYFRAMES[direction][pageState];
975
+ var fadeIn = import_react5.keyframes`
976
+ from { opacity: 0; }
977
+ to { opacity: 1; }
978
+ `;
979
+ var fadeOut = import_react5.keyframes`
980
+ from { opacity: 1; }
981
+ to { opacity: 0; }
982
+ `;
983
+ var layerOf = (direction, pageState) => direction === "push" === (pageState === "enter") ? "upper" : "lower";
984
+ function slideStyles(direction, pageState, duration) {
985
+ const timing = `${duration}ms ${IOS_EASING} forwards`;
986
+ if (layerOf(direction, pageState) === "upper") {
987
+ return import_react5.css`
988
+ animation: ${direction === "push" ? coverIn : coverOut} ${timing};
989
+ `;
990
+ }
991
+ return import_react5.css`
992
+ animation: ${direction === "push" ? parallaxOut : parallaxIn} ${timing};
993
+ &::after {
994
+ content: "";
995
+ /* transform 중인 페이지 기준 fixed = 스크롤과 무관하게 페이지 전체를 덮음 */
996
+ position: fixed;
997
+ inset: 0;
998
+ pointer-events: none;
999
+ background: var(--wvk-dim-color, rgba(0, 0, 0, 0.12));
1000
+ animation: ${direction === "push" ? dimIn : dimOut} ${timing};
1001
+ }
1002
+ `;
935
1003
  }
936
1004
  var PageWrapper = import_styled2.default.div`
937
1005
  position: absolute;
@@ -940,14 +1008,20 @@ var PageWrapper = import_styled2.default.div`
940
1008
  -webkit-overflow-scrolling: touch;
941
1009
  background: var(--wvk-page-bg, #ffffff);
942
1010
  z-index: ${({ zIndex }) => zIndex};
943
- visibility: ${({ pageState }) => pageState === "covered" ? "hidden" : "visible"};
1011
+ visibility: ${({ pageState }) => pageState === "covered" || pageState === "cached" ? "hidden" : "visible"};
944
1012
  ${({ pageState, direction, transitionType, duration }) => {
945
1013
  if (pageState !== "enter" && pageState !== "exit") return "";
946
1014
  if (transitionType === "none" || duration === 0) return "";
947
- return import_react3.css`
948
- will-change: transform, opacity;
949
- animation: ${pickKeyframes(transitionType, direction, pageState)}
950
- ${duration}ms ease-in-out forwards;
1015
+ if (transitionType === "fade") {
1016
+ return import_react5.css`
1017
+ will-change: opacity;
1018
+ animation: ${pageState === "enter" ? fadeIn : fadeOut} ${duration}ms
1019
+ ${FADE_EASING} forwards;
1020
+ `;
1021
+ }
1022
+ return import_react5.css`
1023
+ will-change: transform;
1024
+ ${slideStyles(direction, pageState, duration)}
951
1025
  `;
952
1026
  }}
953
1027
  `;
@@ -957,8 +1031,8 @@ function StackPage({
957
1031
  children,
958
1032
  ...wrapperProps
959
1033
  }) {
960
- const ref = (0, import_react4.useRef)(null);
961
- (0, import_react4.useLayoutEffect)(() => {
1034
+ const ref = (0, import_react6.useRef)(null);
1035
+ (0, import_react6.useLayoutEffect)(() => {
962
1036
  var _a;
963
1037
  (_a = ref.current) == null ? void 0 : _a.toggleAttribute("inert", !isTop);
964
1038
  }, [isTop]);
@@ -970,39 +1044,126 @@ function StackPage({
970
1044
  "data-state": wrapperProps.pageState,
971
1045
  "aria-hidden": isTop ? void 0 : true,
972
1046
  onAnimationEnd: (event) => {
973
- if (event.target === event.currentTarget) onAnimationEnd == null ? void 0 : onAnimationEnd();
1047
+ if (event.target === event.currentTarget && !event.pseudoElement) {
1048
+ onAnimationEnd == null ? void 0 : onAnimationEnd();
1049
+ }
974
1050
  },
975
1051
  children
976
1052
  }
977
1053
  );
978
1054
  }
979
1055
 
980
- // src/stack-router/activity-context.tsx
981
- var import_react5 = require("react");
982
- var ActivityContext = (0, import_react5.createContext)(null);
983
- function useActivity() {
984
- const context = (0, import_react5.useContext)(ActivityContext);
985
- if (!context) {
986
- throw new Error(
987
- "useActivity must be used inside a StackRouterProvider page"
988
- );
989
- }
990
- return context;
991
- }
992
- function useParams() {
993
- return useActivity().params;
994
- }
995
-
996
1056
  // src/stack-router/stack-reducer.ts
997
1057
  var topOf = (entries) => entries[entries.length - 1];
998
- function createStackState(entry) {
999
- return { entries: [entry], leaving: [], transition: null };
1058
+ var bumpRevision = (entry) => {
1059
+ var _a;
1060
+ return {
1061
+ ...entry,
1062
+ revision: ((_a = entry.revision) != null ? _a : 0) + 1
1063
+ };
1064
+ };
1065
+ function createStackState(entry, cacheLimit = 0) {
1066
+ return {
1067
+ entries: [entry],
1068
+ leaving: [],
1069
+ transition: null,
1070
+ cached: [],
1071
+ cacheLimit
1072
+ };
1000
1073
  }
1074
+ function cacheEntries(state, removed) {
1075
+ const { entries, cached, cacheLimit } = state;
1076
+ const incoming = removed.filter((entry) => entry.keepAlive);
1077
+ if (cacheLimit <= 0 || incoming.length === 0) return cached;
1078
+ const incomingPaths = new Set(incoming.map((entry) => entry.path));
1079
+ const merged = [
1080
+ ...cached.filter((entry) => !incomingPaths.has(entry.path)),
1081
+ ...incoming
1082
+ ];
1083
+ const capacity = cacheLimit - entries.filter((e) => e.keepAlive).length;
1084
+ return capacity > 0 ? merged.slice(-capacity) : [];
1085
+ }
1086
+ function withoutPath(list, path) {
1087
+ return list.filter((entry) => entry.path !== path);
1088
+ }
1089
+ function flushLeaving(state, nextEntries) {
1090
+ const alive = new Set(nextEntries.map((entry) => entry.key));
1091
+ const removed = state.leaving.filter((entry) => !alive.has(entry.key));
1092
+ return cacheEntries({ ...state, entries: nextEntries }, removed);
1093
+ }
1094
+ function revive(state, action) {
1095
+ const { direction, index, animate } = action;
1096
+ const entry = bumpRevision(action.entry);
1097
+ const previousTop = topOf(state.entries);
1098
+ const entries = [...state.entries.slice(0, index), entry];
1099
+ const removed = state.entries.slice(index);
1100
+ const cached = state.cached.filter((item) => item.key !== entry.key);
1101
+ const base = { ...state, entries, cached };
1102
+ if (!animate || direction === "pop" && removed.length === 0) {
1103
+ return {
1104
+ ...base,
1105
+ cached: cacheEntries(base, removed),
1106
+ leaving: [],
1107
+ transition: null
1108
+ };
1109
+ }
1110
+ if (direction === "push") {
1111
+ const stillInStack = !removed.includes(previousTop);
1112
+ return {
1113
+ ...base,
1114
+ cached: cacheEntries(
1115
+ base,
1116
+ removed.filter((item) => item !== previousTop)
1117
+ ),
1118
+ leaving: stillInStack ? [] : [previousTop],
1119
+ transition: {
1120
+ type: "push",
1121
+ enterKey: entry.key,
1122
+ exitKey: previousTop.key
1123
+ }
1124
+ };
1125
+ }
1126
+ return {
1127
+ ...base,
1128
+ leaving: removed,
1129
+ transition: {
1130
+ type: "pop",
1131
+ enterKey: entry.key,
1132
+ exitKeys: removed.map((item) => item.key)
1133
+ }
1134
+ };
1135
+ }
1136
+ function findRevivable(state, path, opts = {}) {
1137
+ const matches = (entry) => entry.path === path;
1138
+ const fromStack = opts.includeRemovable ? [...state.entries.slice(1)].reverse().find((entry) => entry.keepAlive && matches(entry)) : void 0;
1139
+ return fromStack != null ? fromStack : [...state.cached].reverse().find((entry) => matches(entry));
1140
+ }
1141
+ var OVERWRITES_LEAVING = /* @__PURE__ */ new Set([
1142
+ "PUSH",
1143
+ "POP_TO",
1144
+ "RESET",
1145
+ "RESET_PUSH",
1146
+ "RESTORE",
1147
+ "REVIVE"
1148
+ ]);
1001
1149
  function stackReducer(state, action) {
1150
+ if (!OVERWRITES_LEAVING.has(action.type) || state.leaving.length === 0) {
1151
+ return reduce(state, action);
1152
+ }
1153
+ const settled = { ...state, leaving: [] };
1154
+ const next = reduce(settled, action);
1155
+ if (next === settled) return state;
1156
+ return reduce(
1157
+ { ...settled, cached: flushLeaving(state, next.entries) },
1158
+ action
1159
+ );
1160
+ }
1161
+ function reduce(state, action) {
1002
1162
  switch (action.type) {
1003
1163
  case "PUSH": {
1004
1164
  const previousTop = topOf(state.entries);
1005
1165
  return {
1166
+ ...state,
1006
1167
  entries: [...state.entries, action.entry],
1007
1168
  leaving: [],
1008
1169
  transition: action.animate ? {
@@ -1012,20 +1173,34 @@ function stackReducer(state, action) {
1012
1173
  } : null
1013
1174
  };
1014
1175
  }
1015
- case "REPLACE":
1176
+ case "REPLACE": {
1177
+ const entries = [...state.entries.slice(0, -1), action.entry];
1178
+ const { path } = action.entry;
1016
1179
  return {
1017
1180
  ...state,
1018
- entries: [...state.entries.slice(0, -1), action.entry]
1181
+ entries,
1182
+ cached: cacheEntries(
1183
+ { ...state, entries, cached: withoutPath(state.cached, path) },
1184
+ withoutPath([topOf(state.entries)], path)
1185
+ )
1019
1186
  };
1187
+ }
1020
1188
  case "POP_TO": {
1021
1189
  const index = Math.max(0, action.index);
1022
1190
  if (index >= state.entries.length - 1) return state;
1023
1191
  const entries = state.entries.slice(0, index + 1);
1024
1192
  const leaving = state.entries.slice(index + 1);
1025
1193
  if (!action.animate) {
1026
- return { entries, leaving: [], transition: null };
1194
+ return {
1195
+ ...state,
1196
+ entries,
1197
+ leaving: [],
1198
+ transition: null,
1199
+ cached: cacheEntries({ ...state, entries }, leaving)
1200
+ };
1027
1201
  }
1028
1202
  return {
1203
+ ...state,
1029
1204
  entries,
1030
1205
  leaving,
1031
1206
  transition: {
@@ -1035,21 +1210,80 @@ function stackReducer(state, action) {
1035
1210
  }
1036
1211
  };
1037
1212
  }
1038
- case "RESET":
1039
- return createStackState(action.entry);
1213
+ case "RESET": {
1214
+ const next = createStackState(action.entry, state.cacheLimit);
1215
+ const { path } = action.entry;
1216
+ return {
1217
+ ...next,
1218
+ cached: cacheEntries(
1219
+ {
1220
+ ...state,
1221
+ entries: next.entries,
1222
+ cached: withoutPath(state.cached, path)
1223
+ },
1224
+ withoutPath(state.entries, path)
1225
+ )
1226
+ };
1227
+ }
1228
+ case "REVIVE":
1229
+ return revive(state, action);
1230
+ case "RESET_PUSH": {
1231
+ const [root] = state.entries;
1232
+ const previousTop = topOf(state.entries);
1233
+ const reusedKey = action.entry.key;
1234
+ const isReused = [...state.entries, ...state.cached].some(
1235
+ (entry) => entry.key === reusedKey
1236
+ );
1237
+ const entries = [
1238
+ root,
1239
+ isReused ? bumpRevision(action.entry) : action.entry
1240
+ ];
1241
+ const sameTop = previousTop.key === reusedKey;
1242
+ const dropped = (action.animate ? state.entries.slice(1, -1) : state.entries.slice(1)).filter((entry) => entry.key !== reusedKey);
1243
+ const cached = state.cached.filter((entry) => entry.key !== reusedKey);
1244
+ const exiting = action.animate && !sameTop;
1245
+ return {
1246
+ ...state,
1247
+ entries,
1248
+ cached: cacheEntries({ ...state, entries, cached }, dropped),
1249
+ leaving: exiting ? [previousTop] : [],
1250
+ transition: exiting ? {
1251
+ type: "push",
1252
+ enterKey: action.entry.key,
1253
+ exitKey: previousTop.key
1254
+ } : null
1255
+ };
1256
+ }
1040
1257
  case "RESTORE":
1041
- return { entries: action.entries, leaving: [], transition: null };
1042
- case "END_TRANSITION":
1258
+ return {
1259
+ ...state,
1260
+ entries: action.entries,
1261
+ leaving: [],
1262
+ transition: null
1263
+ };
1264
+ case "END_TRANSITION": {
1043
1265
  if (!state.transition && state.leaving.length === 0) return state;
1044
- return { ...state, leaving: [], transition: null };
1266
+ return {
1267
+ ...state,
1268
+ leaving: [],
1269
+ transition: null,
1270
+ cached: flushLeaving(state, state.entries)
1271
+ };
1272
+ }
1045
1273
  default:
1046
1274
  return state;
1047
1275
  }
1048
1276
  }
1049
1277
  function getRenderedPages(state) {
1050
- const { entries, leaving, transition } = state;
1278
+ const { entries, leaving, transition, cached } = state;
1051
1279
  const top = topOf(entries);
1052
- return [...entries, ...leaving].map((entry) => {
1280
+ const ordered = (transition == null ? void 0 : transition.type) === "push" ? [...entries.slice(0, -1), ...leaving, top] : [...entries, ...leaving];
1281
+ const cachedPages = cached.map((entry) => ({
1282
+ entry,
1283
+ pageState: "cached",
1284
+ isTop: false
1285
+ }));
1286
+ const stackPages = ordered.map((entry) => {
1053
1287
  const isTop = entry.key === top.key;
1054
1288
  let pageState = isTop ? "idle" : "covered";
1055
1289
  if ((transition == null ? void 0 : transition.type) === "push") {
@@ -1062,20 +1296,21 @@ function getRenderedPages(state) {
1062
1296
  }
1063
1297
  return { entry, pageState, isTop };
1064
1298
  });
1299
+ return [...cachedPages, ...stackPages];
1065
1300
  }
1066
1301
 
1067
1302
  // src/stack-router/use-prefers-reduced-motion.ts
1068
- var import_react6 = require("react");
1303
+ var import_react7 = require("react");
1069
1304
  var QUERY = "(prefers-reduced-motion: reduce)";
1070
1305
  var getMediaQuery = () => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(QUERY) : null;
1071
1306
  function usePrefersReducedMotion() {
1072
- const [reduced, setReduced] = (0, import_react6.useState)(
1307
+ const [reduced, setReduced] = (0, import_react7.useState)(
1073
1308
  () => {
1074
1309
  var _a, _b;
1075
1310
  return (_b = (_a = getMediaQuery()) == null ? void 0 : _a.matches) != null ? _b : false;
1076
1311
  }
1077
1312
  );
1078
- (0, import_react6.useEffect)(() => {
1313
+ (0, import_react7.useEffect)(() => {
1079
1314
  var _a;
1080
1315
  const mediaQuery = getMediaQuery();
1081
1316
  if (!mediaQuery) return;
@@ -1090,13 +1325,13 @@ function usePrefersReducedMotion() {
1090
1325
  }
1091
1326
 
1092
1327
  // src/stack-router/use-stack-bridge-sync.ts
1093
- var import_react7 = require("react");
1328
+ var import_react8 = require("react");
1094
1329
  function useStackBridgeSync(bridge, router, onBackAtRoot) {
1095
1330
  const enabled = Boolean(bridge);
1096
1331
  const options = typeof bridge === "object" ? bridge : {};
1097
- const latest = (0, import_react7.useRef)({ router, options, onBackAtRoot });
1332
+ const latest = (0, import_react8.useRef)({ router, options, onBackAtRoot });
1098
1333
  latest.current = { router, options, onBackAtRoot };
1099
- (0, import_react7.useEffect)(() => {
1334
+ (0, import_react8.useEffect)(() => {
1100
1335
  if (!enabled) return;
1101
1336
  return installBridgeHost({
1102
1337
  allowUrl: latest.current.options.allowUrl,
@@ -1121,7 +1356,7 @@ function useStackBridgeSync(bridge, router, onBackAtRoot) {
1121
1356
  }, [enabled]);
1122
1357
  const { depth, currentPath: currentPath2 } = router;
1123
1358
  const emit = enabled && options.emitStackChanged !== false;
1124
- (0, import_react7.useEffect)(() => {
1359
+ (0, import_react8.useEffect)(() => {
1125
1360
  if (!emit || !isNativeBridgeHost(detectBridgeHost())) return;
1126
1361
  createWebViewBridgeClient().notifyStackChanged({ depth, path: currentPath2 }).catch((error) => {
1127
1362
  var _a, _b;
@@ -1131,7 +1366,7 @@ function useStackBridgeSync(bridge, router, onBackAtRoot) {
1131
1366
  }
1132
1367
 
1133
1368
  // src/stack-router/use-stack-navigation.ts
1134
- var import_react8 = require("react");
1369
+ var import_react9 = require("react");
1135
1370
 
1136
1371
  // src/stack-router/match-path.ts
1137
1372
  var splitSegments = (pathname) => pathname.split("/").filter((segment) => segment.length > 0);
@@ -1182,37 +1417,57 @@ var isDev2 = () => {
1182
1417
  var _a;
1183
1418
  return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.NODE_ENV) !== "production";
1184
1419
  };
1185
- function createEntry(hit, path, data, key = createBridgeId()) {
1420
+ function createEntry(hit, path, cacheLimit, data, key = createBridgeId()) {
1186
1421
  return {
1187
1422
  key,
1188
1423
  path,
1189
1424
  pattern: hit.activity.path,
1190
1425
  params: hit.match.params,
1191
1426
  query: hit.match.query,
1192
- data
1427
+ data,
1428
+ keepAlive: hit.activity.keepAlive === true && cacheLimit > 0
1193
1429
  };
1194
1430
  }
1195
1431
  var currentUrl = () => window.location.pathname + window.location.search;
1196
1432
  function useStackNavigation(options) {
1197
- const optionsRef = (0, import_react8.useRef)(options);
1433
+ const optionsRef = (0, import_react9.useRef)(options);
1198
1434
  optionsRef.current = options;
1199
- const [state, dispatch] = (0, import_react8.useReducer)(stackReducer, void 0, () => {
1435
+ const [state, dispatch] = (0, import_react9.useReducer)(stackReducer, void 0, () => {
1436
+ var _a;
1200
1437
  const { initialActivity } = options;
1438
+ const cacheLimit = (_a = options.keepAliveLimit) != null ? _a : KEEP_ALIVE_LIMIT;
1201
1439
  return createStackState(
1202
1440
  createEntry(
1203
1441
  { activity: initialActivity, match: { params: {}, query: {} } },
1204
- initialActivity.path
1205
- )
1442
+ initialActivity.path,
1443
+ cacheLimit
1444
+ ),
1445
+ cacheLimit
1206
1446
  );
1207
1447
  });
1208
- const stateRef = (0, import_react8.useRef)(state);
1448
+ const stateRef = (0, import_react9.useRef)(state);
1209
1449
  stateRef.current = state;
1210
- const busyRef = (0, import_react8.useRef)(false);
1211
- const resolve = (0, import_react8.useCallback)((path) => {
1450
+ const newEntry = (hit, path, data, key) => createEntry(hit, path, stateRef.current.cacheLimit, data, key);
1451
+ const busyRef = (0, import_react9.useRef)(false);
1452
+ const ignorePopRef = (0, import_react9.useRef)(0);
1453
+ const pendingTravelRef = (0, import_react9.useRef)(0);
1454
+ const isLocked = () => busyRef.current || pendingTravelRef.current > 0;
1455
+ const travel = (delta, ignorePop) => {
1456
+ pendingTravelRef.current += 1;
1457
+ if (ignorePop) ignorePopRef.current += 1;
1458
+ return history.travel(delta).then((popped) => {
1459
+ pendingTravelRef.current -= 1;
1460
+ if (!popped && ignorePop) {
1461
+ ignorePopRef.current = Math.max(0, ignorePopRef.current - 1);
1462
+ }
1463
+ return popped;
1464
+ });
1465
+ };
1466
+ const resolve = (0, import_react9.useCallback)((path) => {
1212
1467
  const { activities, initialActivity } = optionsRef.current;
1213
1468
  return findActivity([...activities, initialActivity], path);
1214
1469
  }, []);
1215
- const resolveOrNotify = (0, import_react8.useCallback)(
1470
+ const resolveOrNotify = (0, import_react9.useCallback)(
1216
1471
  (path) => {
1217
1472
  var _a, _b;
1218
1473
  const hit = resolve(path);
@@ -1227,29 +1482,35 @@ function useStackNavigation(options) {
1227
1482
  [resolve]
1228
1483
  );
1229
1484
  const animate = () => optionsRef.current.duration > 0;
1230
- const push = (0, import_react8.useCallback)(
1485
+ const push = (0, import_react9.useCallback)(
1231
1486
  (path, data) => {
1232
- if (busyRef.current) return false;
1487
+ if (isLocked()) return false;
1233
1488
  const hit = resolveOrNotify(path);
1234
1489
  if (!hit) return false;
1235
- const entry = createEntry(hit, path, data);
1490
+ const { entries } = stateRef.current;
1491
+ const revived = findRevivable(stateRef.current, path);
1492
+ const entry = revived ? { ...revived, data } : newEntry(hit, path, data);
1236
1493
  busyRef.current = true;
1237
- history.push(path, {
1238
- key: entry.key,
1239
- index: stateRef.current.entries.length,
1240
- data
1241
- });
1242
- dispatch({ type: "PUSH", entry, animate: animate() });
1494
+ history.push(path, { key: entry.key, index: entries.length, data });
1495
+ dispatch(
1496
+ revived ? {
1497
+ type: "REVIVE",
1498
+ entry,
1499
+ direction: "push",
1500
+ index: entries.length,
1501
+ animate: animate()
1502
+ } : { type: "PUSH", entry, animate: animate() }
1503
+ );
1243
1504
  return true;
1244
1505
  },
1245
1506
  [resolveOrNotify]
1246
1507
  );
1247
- const replace = (0, import_react8.useCallback)(
1508
+ const replace = (0, import_react9.useCallback)(
1248
1509
  (path, data) => {
1249
- if (busyRef.current) return false;
1510
+ if (isLocked()) return false;
1250
1511
  const hit = resolveOrNotify(path);
1251
1512
  if (!hit) return false;
1252
- const entry = createEntry(hit, path, data);
1513
+ const entry = newEntry(hit, path, data);
1253
1514
  history.replace(path, {
1254
1515
  key: entry.key,
1255
1516
  index: stateRef.current.entries.length - 1,
@@ -1260,21 +1521,46 @@ function useStackNavigation(options) {
1260
1521
  },
1261
1522
  [resolveOrNotify]
1262
1523
  );
1263
- const reset = (0, import_react8.useCallback)(
1524
+ const reset = (0, import_react9.useCallback)(
1264
1525
  (path, data) => {
1265
- if (busyRef.current) return false;
1526
+ if (isLocked()) return false;
1266
1527
  const hit = resolveOrNotify(path);
1267
1528
  if (!hit) return false;
1268
- const entry = createEntry(hit, path, data);
1269
- history.replace(path, { key: entry.key, index: 0, data });
1529
+ const entry = newEntry(hit, path, data);
1530
+ const depth = stateRef.current.entries.length;
1270
1531
  dispatch({ type: "RESET", entry });
1532
+ const commit = () => {
1533
+ history.replace(path, { key: entry.key, index: 0, data });
1534
+ };
1535
+ if (depth === 1) commit();
1536
+ else void travel(-(depth - 1), true).then(commit);
1271
1537
  return true;
1272
1538
  },
1273
1539
  [resolveOrNotify]
1274
1540
  );
1275
- const pop = (0, import_react8.useCallback)((count = 1) => {
1541
+ const resetPush = (0, import_react9.useCallback)(
1542
+ (path, data) => {
1543
+ const { entries } = stateRef.current;
1544
+ if (entries.length === 1) return push(path, data);
1545
+ if (isLocked()) return false;
1546
+ const hit = resolveOrNotify(path);
1547
+ if (!hit) return false;
1548
+ const revivable = findRevivable(stateRef.current, path, {
1549
+ includeRemovable: true
1550
+ });
1551
+ const entry = revivable ? { ...revivable, data } : newEntry(hit, path, data);
1552
+ busyRef.current = true;
1553
+ dispatch({ type: "RESET_PUSH", entry, animate: animate() });
1554
+ void travel(-(entries.length - 1), true).then(() => {
1555
+ history.push(path, { key: entry.key, index: 1, data });
1556
+ });
1557
+ return true;
1558
+ },
1559
+ [push, resolveOrNotify]
1560
+ );
1561
+ const pop = (0, import_react9.useCallback)((count = 1) => {
1276
1562
  var _a, _b;
1277
- if (busyRef.current) return false;
1563
+ if (isLocked()) return false;
1278
1564
  const { entries } = stateRef.current;
1279
1565
  if (entries.length <= 1) {
1280
1566
  (_b = (_a = optionsRef.current).onBackAtRoot) == null ? void 0 : _b.call(_a);
@@ -1283,16 +1569,12 @@ function useStackNavigation(options) {
1283
1569
  const delta = Math.min(Math.max(1, count), entries.length - 1);
1284
1570
  const targetIndex = entries.length - 1 - delta;
1285
1571
  busyRef.current = true;
1286
- void history.travel(-delta).then((popped) => {
1287
- if (!popped) {
1288
- busyRef.current = false;
1289
- dispatch({ type: "POP_TO", index: targetIndex, animate: false });
1290
- }
1291
- });
1572
+ dispatch({ type: "POP_TO", index: targetIndex, animate: animate() });
1573
+ void travel(-delta, false);
1292
1574
  return true;
1293
1575
  }, []);
1294
- const back = (0, import_react8.useCallback)(() => pop(1), [pop]);
1295
- const popTo = (0, import_react8.useCallback)(
1576
+ const back = (0, import_react9.useCallback)(() => pop(1), [pop]);
1577
+ const popTo = (0, import_react9.useCallback)(
1296
1578
  (path) => {
1297
1579
  const { entries } = stateRef.current;
1298
1580
  for (let i = entries.length - 2; i >= 0; i -= 1) {
@@ -1304,11 +1586,15 @@ function useStackNavigation(options) {
1304
1586
  },
1305
1587
  [pop]
1306
1588
  );
1307
- const endTransition = (0, import_react8.useCallback)(() => {
1589
+ const endTransition = (0, import_react9.useCallback)(() => {
1308
1590
  dispatch({ type: "END_TRANSITION" });
1309
1591
  }, []);
1310
- (0, import_react8.useEffect)(() => {
1592
+ (0, import_react9.useEffect)(() => {
1311
1593
  const onPop = (historyState) => {
1594
+ if (ignorePopRef.current > 0) {
1595
+ ignorePopRef.current -= 1;
1596
+ return;
1597
+ }
1312
1598
  const { entries } = stateRef.current;
1313
1599
  const index = historyState.key ? entries.findIndex((entry2) => entry2.key === historyState.key) : -1;
1314
1600
  if (index !== -1) {
@@ -1318,12 +1604,26 @@ function useStackNavigation(options) {
1318
1604
  }
1319
1605
  return;
1320
1606
  }
1607
+ const cachedEntry = historyState.key ? stateRef.current.cached.find((item) => item.key === historyState.key) : void 0;
1608
+ const targetIndex = historyState.index;
1609
+ if (cachedEntry && typeof targetIndex === "number" && // 루트 자리(0)는 되살리지 않는다. 아래 일반 처리(reset)로 넘긴다
1610
+ targetIndex >= 1 && targetIndex <= entries.length) {
1611
+ busyRef.current = true;
1612
+ dispatch({
1613
+ type: "REVIVE",
1614
+ entry: { ...cachedEntry, data: historyState.data },
1615
+ direction: targetIndex === entries.length ? "push" : "pop",
1616
+ index: targetIndex,
1617
+ animate: animate()
1618
+ });
1619
+ return;
1620
+ }
1321
1621
  const hit = resolveOrNotify(historyState.path);
1322
1622
  if (!hit) {
1323
1623
  busyRef.current = false;
1324
1624
  return;
1325
1625
  }
1326
- const entry = createEntry(
1626
+ const entry = newEntry(
1327
1627
  hit,
1328
1628
  historyState.path,
1329
1629
  historyState.data,
@@ -1341,8 +1641,8 @@ function useStackNavigation(options) {
1341
1641
  removeListener();
1342
1642
  };
1343
1643
  }, [resolveOrNotify]);
1344
- const restoredRef = (0, import_react8.useRef)(false);
1345
- (0, import_react8.useEffect)(() => {
1644
+ const restoredRef = (0, import_react9.useRef)(false);
1645
+ (0, import_react9.useEffect)(() => {
1346
1646
  if (restoredRef.current) return;
1347
1647
  restoredRef.current = true;
1348
1648
  const root = stateRef.current.entries[0];
@@ -1353,7 +1653,7 @@ function useStackNavigation(options) {
1353
1653
  return;
1354
1654
  }
1355
1655
  const savedData = history.getCurrentState().data;
1356
- const top = createEntry(hit, url, savedData);
1656
+ const top = newEntry(hit, url, savedData);
1357
1657
  if (optionsRef.current.restoreStack === "top-only") {
1358
1658
  history.replace(url, { key: top.key, index: 0, data: savedData });
1359
1659
  dispatch({ type: "RESTORE", entries: [top] });
@@ -1363,7 +1663,7 @@ function useStackNavigation(options) {
1363
1663
  history.push(url, { key: top.key, index: 1, data: savedData });
1364
1664
  dispatch({ type: "RESTORE", entries: [root, top] });
1365
1665
  }, [resolve]);
1366
- (0, import_react8.useEffect)(() => {
1666
+ (0, import_react9.useEffect)(() => {
1367
1667
  if (!state.transition) {
1368
1668
  busyRef.current = false;
1369
1669
  return;
@@ -1374,14 +1674,24 @@ function useStackNavigation(options) {
1374
1674
  );
1375
1675
  return () => clearTimeout(timer);
1376
1676
  }, [state, endTransition]);
1377
- return { state, push, replace, reset, back, pop, popTo, endTransition };
1677
+ return {
1678
+ state,
1679
+ push,
1680
+ replace,
1681
+ reset,
1682
+ resetPush,
1683
+ back,
1684
+ pop,
1685
+ popTo,
1686
+ endTransition
1687
+ };
1378
1688
  }
1379
1689
 
1380
1690
  // src/stack-router/stack-router-provider.tsx
1381
1691
  var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
1382
- var StackRouterContext = (0, import_react9.createContext)(null);
1692
+ var StackRouterContext = (0, import_react10.createContext)(null);
1383
1693
  var useStackRouter = () => {
1384
- const context = (0, import_react9.useContext)(StackRouterContext);
1694
+ const context = (0, import_react10.useContext)(StackRouterContext);
1385
1695
  if (!context) {
1386
1696
  throw new Error("useStackRouter must be used within a StackRouterProvider");
1387
1697
  }
@@ -1391,6 +1701,8 @@ var isDevEnv = () => {
1391
1701
  var _a;
1392
1702
  return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.NODE_ENV) === "development";
1393
1703
  };
1704
+ var MIN_MOUNTED_PAGES = 1;
1705
+ var CACHED_ACTIVITY_INDEX = -1;
1394
1706
  var StackRouterProvider = ({
1395
1707
  initialActivity,
1396
1708
  Activities = [],
@@ -1400,6 +1712,8 @@ var StackRouterProvider = ({
1400
1712
  transition = "slide",
1401
1713
  duration = STACK_TRANSITION_MS,
1402
1714
  restoreStack = "with-root",
1715
+ keepAliveLimit = KEEP_ALIVE_LIMIT,
1716
+ maxMountedPages,
1403
1717
  safeArea = false,
1404
1718
  onBackAtRoot,
1405
1719
  onNotFound,
@@ -1413,6 +1727,7 @@ var StackRouterProvider = ({
1413
1727
  activities: Activities,
1414
1728
  duration: effectiveDuration,
1415
1729
  restoreStack,
1730
+ keepAliveLimit,
1416
1731
  onBackAtRoot,
1417
1732
  onNotFound
1418
1733
  });
@@ -1422,7 +1737,7 @@ var StackRouterProvider = ({
1422
1737
  return (_b2 = (_a2 = Activities.find((activity) => activity.path === pattern)) == null ? void 0 : _a2.element) != null ? _b2 : initialActivity.path === pattern ? initialActivity.element : null;
1423
1738
  };
1424
1739
  const top = state.entries[state.entries.length - 1];
1425
- const value = (0, import_react9.useMemo)(
1740
+ const value = (0, import_react10.useMemo)(
1426
1741
  () => ({
1427
1742
  currentPath: top.path,
1428
1743
  currentState: {
@@ -1444,6 +1759,7 @@ var StackRouterProvider = ({
1444
1759
  push: navigation.push,
1445
1760
  replace: navigation.replace,
1446
1761
  reset: navigation.reset,
1762
+ resetPush: navigation.resetPush,
1447
1763
  back: navigation.back,
1448
1764
  pop: navigation.pop,
1449
1765
  popTo: navigation.popTo,
@@ -1454,11 +1770,60 @@ var StackRouterProvider = ({
1454
1770
  useStackBridgeSync(bridge, value, onBackAtRoot);
1455
1771
  const direction = (_b = (_a = state.transition) == null ? void 0 : _a.type) != null ? _b : "push";
1456
1772
  const pages = getRenderedPages(state);
1773
+ const stackIndexByKey = new Map(
1774
+ state.entries.map((entry, index) => [entry.key, index])
1775
+ );
1776
+ const activityIndexOf = (entry) => {
1777
+ const stackIndex = stackIndexByKey.get(entry.key);
1778
+ if (stackIndex !== void 0) return stackIndex;
1779
+ const leavingIndex = state.leaving.findIndex(
1780
+ (item) => item.key === entry.key
1781
+ );
1782
+ return leavingIndex === -1 ? CACHED_ACTIVITY_INDEX : state.entries.length + leavingIndex;
1783
+ };
1784
+ const mountLimit = maxMountedPages === void 0 || !Number.isFinite(maxMountedPages) ? Infinity : Math.max(MIN_MOUNTED_PAGES, maxMountedPages);
1785
+ const mountedKeysRef = (0, import_react10.useRef)(/* @__PURE__ */ new Set());
1786
+ const wasMounted = mountedKeysRef.current;
1787
+ const shouldMount = (page) => {
1788
+ const { entry, pageState } = page;
1789
+ if (pageState === "cached" || entry.keepAlive) return true;
1790
+ const stackIndex = stackIndexByKey.get(entry.key);
1791
+ if (stackIndex === void 0) return wasMounted.has(entry.key);
1792
+ if (pageState === "enter" || pageState === "exit") return true;
1793
+ return state.entries.length - stackIndex <= mountLimit;
1794
+ };
1795
+ const mountedKeys = new Set(
1796
+ pages.filter(shouldMount).map((page) => page.entry.key)
1797
+ );
1798
+ mountedKeysRef.current = mountedKeys;
1799
+ const mountedCount = mountedKeys.size;
1800
+ const domOrderRef = (0, import_react10.useRef)([]);
1801
+ const currentKeys = new Set(pages.map((page) => page.entry.key));
1802
+ const knownKeys = new Set(domOrderRef.current);
1803
+ domOrderRef.current = [
1804
+ ...domOrderRef.current.filter((key) => currentKeys.has(key)),
1805
+ ...pages.map((page) => page.entry.key).filter((key) => !knownKeys.has(key))
1806
+ ];
1807
+ const domOrder = domOrderRef.current;
1808
+ const domPages = pages.map((page, index) => ({ page, index })).sort(
1809
+ (a, b) => domOrder.indexOf(a.page.entry.key) - domOrder.indexOf(b.page.entry.key)
1810
+ );
1811
+ const hasWarnedRef = (0, import_react10.useRef)(false);
1812
+ (0, import_react10.useEffect)(() => {
1813
+ if (hasWarnedRef.current || !isDevEnv() || mountedCount <= DEV_MOUNTED_PAGES_WARN) {
1814
+ return;
1815
+ }
1816
+ hasWarnedRef.current = true;
1817
+ console.warn(
1818
+ `[webviewkit] \uB9C8\uC6B4\uD2B8\uB41C \uD398\uC774\uC9C0\uAC00 ${mountedCount}\uAC1C\uC785\uB2C8\uB2E4. \uBA54\uBAA8\uB9AC \uC0AC\uC6A9\uC774 \uCEE4\uC9C8 \uC218 \uC788\uC73C\uB2C8 maxMountedPages \uB85C \uC0C1\uD55C\uC744 \uB450\uC138\uC694.`
1819
+ );
1820
+ }, [mountedCount]);
1457
1821
  const showDevTools = enableDevTools != null ? enableDevTools : isDevEnv();
1458
1822
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(StackRouterContext.Provider, { value, children: [
1459
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LayoutContainer, { safeArea, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Layout, { maxWidth, "data-testid": "layout", children: [
1460
- isShowHeader && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(header_default, {}),
1461
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageContainer, { children: pages.map(({ entry, pageState, isTop }, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1823
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LayoutContainer, { safeArea, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Layout, { maxWidth, "data-testid": "layout", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageContainer, { children: domPages.map(({ page, index }) => {
1824
+ var _a2;
1825
+ const { entry, pageState, isTop } = page;
1826
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1462
1827
  ActivityContext.Provider,
1463
1828
  {
1464
1829
  value: {
@@ -1468,10 +1833,12 @@ var StackRouterProvider = ({
1468
1833
  params: entry.params,
1469
1834
  query: entry.query,
1470
1835
  data: entry.data,
1471
- index,
1472
- isTop
1836
+ index: activityIndexOf(entry),
1837
+ isTop,
1838
+ isCached: pageState === "cached",
1839
+ revision: (_a2 = entry.revision) != null ? _a2 : 0
1473
1840
  },
1474
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1841
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1475
1842
  StackPage,
1476
1843
  {
1477
1844
  pageState,
@@ -1481,13 +1848,16 @@ var StackRouterProvider = ({
1481
1848
  zIndex: index,
1482
1849
  isTop,
1483
1850
  onAnimationEnd: pageState === "enter" ? endTransition : void 0,
1484
- children: elementFor(entry.pattern)
1851
+ children: [
1852
+ mountedKeys.has(entry.key) && isShowHeader && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(header_default, {}),
1853
+ mountedKeys.has(entry.key) ? elementFor(entry.pattern) : null
1854
+ ]
1485
1855
  }
1486
1856
  )
1487
1857
  },
1488
1858
  entry.key
1489
- )) })
1490
- ] }) }),
1859
+ );
1860
+ }) }) }) }),
1491
1861
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1492
1862
  StackDevRoadmap,
1493
1863
  {
@@ -1592,6 +1962,7 @@ var BackIcon = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1592
1962
  FLUTTER_READY_EVENT,
1593
1963
  FLUTTER_UNIFIED_HANDLER,
1594
1964
  HistoryAction,
1965
+ KEEP_ALIVE_LIMIT,
1595
1966
  RN_BRIDGE_HANDLER,
1596
1967
  STACK_BRIDGE_METHODS,
1597
1968
  STACK_TRANSITION_MS,
@@ -1625,6 +1996,7 @@ var BackIcon = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1625
1996
  serializeBridgeMessage,
1626
1997
  toStackPath,
1627
1998
  useActivity,
1999
+ useOnRevive,
1628
2000
  useParams,
1629
2001
  useStackRouter,
1630
2002
  waitForBridgeHost