@apps-in-toss/framework 0.0.0-dev.1758103372343 → 0.0.0-dev.1758198081085

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.cjs CHANGED
@@ -337,7 +337,7 @@ function NavigationBarImpressionArea({
337
337
  logging.navBarImpression({ home_icon_yn: withHomeButton ? "Y" : "N" });
338
338
  hasLogged.current = true;
339
339
  }
340
- }, []);
340
+ }, [logging, withHomeButton]);
341
341
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
342
342
  }
343
343
 
@@ -681,16 +681,16 @@ function RNNavigationBar() {
681
681
  }
682
682
  handleBackOrClose();
683
683
  }, [backEventContext, handleBackOrClose]);
684
- const handleAndroidBackEvent = (0, import_react9.useCallback)(() => {
685
- handleBack();
686
- return true;
687
- }, [handleBack]);
688
684
  (0, import_react9.useEffect)(() => {
685
+ const handleAndroidBackEvent = () => {
686
+ handleBack();
687
+ return true;
688
+ };
689
689
  import_react_native16.BackHandler.addEventListener("hardwareBackPress", handleAndroidBackEvent);
690
690
  return () => {
691
691
  import_react_native16.BackHandler.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
692
692
  };
693
- }, [handleAndroidBackEvent]);
693
+ }, [handleBack]);
694
694
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavigationBarImpressionArea, { withHomeButton, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
695
695
  import_private2.TopNavigation,
696
696
  {
@@ -771,9 +771,9 @@ function registerApp(container, { context, analytics }) {
771
771
  return global.Page;
772
772
  }
773
773
  function AppsInTossScreenContainer({ children }) {
774
- const isRN = getAppsInTossGlobals().webViewType == null;
774
+ const isReactNativeService = getAppsInTossGlobals().webViewType == null;
775
775
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_analytics.Analytics.Screen, { children: [
776
- isRN && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RNNavigationBar, {}),
776
+ isReactNativeService && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RNNavigationBar, {}),
777
777
  children
778
778
  ] });
779
779
  }
@@ -792,7 +792,7 @@ var AppsInToss = {
792
792
  };
793
793
 
794
794
  // src/components/WebView.tsx
795
- var import_native_modules17 = require("@apps-in-toss/native-modules");
795
+ var import_native_modules18 = require("@apps-in-toss/native-modules");
796
796
  var appsInTossAsyncBridges = __toESM(require("@apps-in-toss/native-modules/async-bridges"), 1);
797
797
  var appsInTossConstantBridges = __toESM(require("@apps-in-toss/native-modules/constant-bridges"), 1);
798
798
  var appsInTossEventBridges = __toESM(require("@apps-in-toss/native-modules/event-bridges"), 1);
@@ -801,7 +801,7 @@ var graniteAsyncBridges = __toESM(require("@granite-js/react-native/async-bridge
801
801
  var graniteConstantBridges = __toESM(require("@granite-js/react-native/constant-bridges"), 1);
802
802
  var import_react_native37 = require("@toss-design-system/react-native");
803
803
  var import_private7 = require("@toss-design-system/react-native/private");
804
- var import_react19 = require("react");
804
+ var import_react18 = require("react");
805
805
  var import_react_native38 = require("react-native");
806
806
 
807
807
  // src/components/GameWebView.tsx
@@ -817,7 +817,7 @@ var import_react11 = require("react");
817
817
  var import_react_native25 = require("react-native");
818
818
 
819
819
  // src/constant/game-center.ts
820
- var GAME_PROFILE_WEBVIEW_URL = "https://service.toss.im/game-center/profile";
820
+ var GAME_PROFILE_WEBVIEW_URL = "servicetoss://game-center/profile";
821
821
  var GAME_CENTER_MIN_VERSION = {
822
822
  android: "5.221.0",
823
823
  ios: "5.221.0"
@@ -1155,14 +1155,14 @@ function GameWebviewNavigationBar() {
1155
1155
  (0, import_react_native26.closeView)();
1156
1156
  }
1157
1157
  }, [captureExitLog, global2.brandDisplayName, logging, openConfirm]);
1158
- const handleAndroidBackEvent = (0, import_react12.useCallback)(() => {
1159
- handleGameWebviewClose();
1160
- return true;
1161
- }, [handleGameWebviewClose]);
1162
1158
  (0, import_react12.useEffect)(() => {
1159
+ const handleAndroidBackEvent = () => {
1160
+ handleGameWebviewClose();
1161
+ return true;
1162
+ };
1163
1163
  import_react_native28.BackHandler.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1164
1164
  return () => import_react_native28.BackHandler.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1165
- }, [handleAndroidBackEvent]);
1165
+ }, [handleGameWebviewClose]);
1166
1166
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
1167
1167
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native27.PageNavbar, { preference: { type: "none" } }),
1168
1168
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
@@ -1170,6 +1170,7 @@ function GameWebviewNavigationBar() {
1170
1170
  {
1171
1171
  style: {
1172
1172
  width: "100%",
1173
+ // TODO: UI관련 스타일 설정은 TDS로 이관
1173
1174
  height: import_react_native28.Platform.OS === "ios" ? 44 : 54,
1174
1175
  flexDirection: "row",
1175
1176
  alignItems: "center",
@@ -1185,7 +1186,10 @@ function GameWebviewNavigationBar() {
1185
1186
  {
1186
1187
  fixedRightButton: initialAccessoryButton,
1187
1188
  onPressDots: openMoreButtonBottomSheet,
1188
- onPressClose: handleGameWebviewClose,
1189
+ onPressClose: () => {
1190
+ logging.closeButtonClick();
1191
+ handleGameWebviewClose();
1192
+ },
1189
1193
  theme: "dark"
1190
1194
  }
1191
1195
  )
@@ -1223,17 +1227,18 @@ var GameWebView = (0, import_react13.forwardRef)(function GameWebView2(props, re
1223
1227
  // src/components/PartnerWebView.tsx
1224
1228
  var import_native_modules14 = require("@apps-in-toss/native-modules");
1225
1229
  var import_react_native_webview2 = require("@granite-js/native/react-native-webview");
1226
- var import_react16 = require("react");
1227
- var import_react_native33 = require("react-native");
1230
+ var import_react15 = require("react");
1231
+ var import_react_native32 = require("react-native");
1228
1232
 
1229
1233
  // src/components/NavigationBar/PartnerWebviewNavigationBar.tsx
1234
+ var import_native_modules13 = require("@apps-in-toss/native-modules");
1230
1235
  var import_react_native30 = require("@granite-js/react-native");
1231
1236
  var import_react_native31 = require("@toss-design-system/react-native");
1232
1237
  var import_private6 = require("@toss-design-system/react-native/private");
1233
1238
  var import_es_hangul4 = require("es-hangul");
1234
1239
  var import_react14 = require("react");
1235
1240
  var import_jsx_runtime10 = require("react/jsx-runtime");
1236
- function PartnerWebviewNavigationBar({ handleBackEvent, handleHomeIconButtonClick }) {
1241
+ function PartnerWebviewNavigationBar({ handleBackEvent }) {
1237
1242
  const globals = getAppsInTossGlobals();
1238
1243
  const { captureExitLog } = useCaptureExitLog();
1239
1244
  const logging = useNavigationBarLogging();
@@ -1245,8 +1250,8 @@ function PartnerWebviewNavigationBar({ handleBackEvent, handleHomeIconButtonClic
1245
1250
  const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
1246
1251
  const handlePressTitle = (0, import_react14.useCallback)(() => {
1247
1252
  logging.homeButtonClick();
1248
- handleHomeIconButtonClick();
1249
- }, [handleHomeIconButtonClick, logging]);
1253
+ import_native_modules13.appsInTossEvent.emit("homeIconButtonClickEvent", void 0);
1254
+ }, [logging]);
1250
1255
  const handleClose = (0, import_react14.useCallback)(async () => {
1251
1256
  logging.closeButtonClick();
1252
1257
  const isConfirmed = await openConfirm({
@@ -1291,182 +1296,53 @@ function mergeRefs(...refs) {
1291
1296
  };
1292
1297
  }
1293
1298
 
1294
- // src/hooks/useWebviewHistoryStack.tsx
1295
- var import_react15 = require("react");
1296
- function useWebViewHistory() {
1297
- const [stack, setStack] = (0, import_react15.useState)([]);
1298
- const [index, setIndex] = (0, import_react15.useState)(-1);
1299
- const canGoBack = index > 0;
1300
- const canGoForward = index >= 0 && index < stack.length - 1;
1301
- const push = (0, import_react15.useCallback)(
1302
- (url) => {
1303
- setStack((prev) => {
1304
- const base = prev.slice(0, index + 1);
1305
- return [...base, url];
1306
- });
1307
- setIndex((i) => i + 1);
1308
- },
1309
- [index]
1310
- );
1311
- const onNavigationStateChange = (0, import_react15.useCallback)(
1312
- ({ url }) => {
1313
- if (stack.length === 0) {
1314
- setStack([url]);
1315
- setIndex(0);
1316
- return;
1317
- }
1318
- const cur = stack[index];
1319
- if (url === cur) {
1320
- return;
1321
- }
1322
- const prev = index > 0 ? stack[index - 1] : void 0;
1323
- const next = index < stack.length - 1 ? stack[index + 1] : void 0;
1324
- if (prev && url === prev) {
1325
- setIndex((i) => i - 1);
1326
- return;
1327
- }
1328
- if (next && url === next) {
1329
- setIndex((i) => i + 1);
1330
- return;
1331
- }
1332
- push(url);
1333
- },
1334
- [stack, index, push]
1335
- );
1336
- return {
1337
- onNavigationStateChange,
1338
- canGoBack,
1339
- canGoForward
1340
- };
1341
- }
1342
-
1343
- // src/utils/log.ts
1344
- var import_native_modules13 = require("@apps-in-toss/native-modules");
1345
- var import_react_native32 = require("@granite-js/react-native");
1346
-
1347
- // src/utils/extractDateFromUUIDv7.ts
1348
- var extractDateFromUUIDv7 = (uuid) => {
1349
- const timestampHex = uuid.split("-").join("").slice(0, 12);
1350
- const timestamp = Number.parseInt(timestampHex, 16);
1351
- return new Date(timestamp);
1352
- };
1353
-
1354
- // src/utils/log.ts
1355
- var getGroupId = (url) => {
1356
- try {
1357
- const urlObject = new URL(url);
1358
- return {
1359
- groupId: urlObject.pathname,
1360
- search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1361
- };
1362
- } catch {
1363
- return {
1364
- groupId: "unknown",
1365
- search: "unknown"
1366
- };
1367
- }
1368
- };
1369
- var getReferrer = () => {
1370
- try {
1371
- const referrer = new URL((0, import_react_native32.getSchemeUri)());
1372
- return referrer.searchParams.get("referrer");
1373
- } catch {
1374
- return "";
1375
- }
1376
- };
1377
- var trackScreen = (url) => {
1378
- const { groupId, search } = getGroupId(url);
1379
- const log = {
1380
- log_type: "screen",
1381
- log_name: `${groupId}::screen`,
1382
- params: {
1383
- search,
1384
- referrer: getReferrer(),
1385
- deployment_id: env.getDeploymentId(),
1386
- deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1387
- }
1388
- };
1389
- return (0, import_native_modules13.eventLog)(log);
1390
- };
1391
-
1392
1299
  // src/components/PartnerWebView.tsx
1393
1300
  var import_jsx_runtime11 = require("react/jsx-runtime");
1394
- var PartnerWebView = (0, import_react16.forwardRef)(
1395
- function PartnerWebViewScreen(webViewProps, ref) {
1396
- const webViewRef = (0, import_react16.useRef)(null);
1397
- const refs = mergeRefs(ref, webViewRef);
1398
- const { captureExitLog } = useCaptureExitLog();
1399
- const { canGoBack, onNavigationStateChange } = useWebViewHistory();
1400
- const historyBackScript = `
1401
- (function() {
1402
- history.back();
1403
- true;
1404
- })();
1405
- `;
1406
- const historyHomeScript = `
1407
- (function() {
1408
- history.replaceState(null, '', '/');
1409
- true;
1410
- })();
1411
- `;
1412
- const handleBackEvent = (0, import_react16.useCallback)(() => {
1413
- if (canGoBack) {
1414
- webViewRef.current?.injectJavaScript(historyBackScript);
1415
- } else {
1416
- captureExitLog(Date.now());
1417
- (0, import_native_modules14.closeView)();
1418
- }
1419
- }, [canGoBack, captureExitLog, historyBackScript]);
1420
- const handleAndroidBackEvent = (0, import_react16.useCallback)(() => {
1421
- if (canGoBack) {
1422
- webViewRef.current?.injectJavaScript(historyBackScript);
1301
+ var PartnerWebView = (0, import_react15.forwardRef)(function PartnerWebViewScreen({ canHistoryGoBack, ...webViewProps }, ref) {
1302
+ const webViewRef = (0, import_react15.useRef)(null);
1303
+ const refs = mergeRefs(ref, webViewRef);
1304
+ const { captureExitLog } = useCaptureExitLog();
1305
+ const handleBackEvent = (0, import_react15.useCallback)(() => {
1306
+ if (canHistoryGoBack) {
1307
+ webViewRef.current?.goBack();
1308
+ } else {
1309
+ captureExitLog(Date.now());
1310
+ (0, import_native_modules14.closeView)();
1311
+ }
1312
+ }, [canHistoryGoBack, captureExitLog]);
1313
+ (0, import_react15.useEffect)(() => {
1314
+ const handleAndroidBackEvent = () => {
1315
+ if (canHistoryGoBack) {
1316
+ webViewRef.current?.goBack();
1423
1317
  return true;
1424
1318
  } else {
1319
+ captureExitLog(Date.now());
1425
1320
  return false;
1426
1321
  }
1427
- }, [canGoBack, historyBackScript]);
1428
- (0, import_react16.useEffect)(() => {
1429
- import_react_native33.BackHandler.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1430
- return () => import_react_native33.BackHandler.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1431
- }, [handleAndroidBackEvent]);
1432
- const handleHomeIconButtonClick = (0, import_react16.useCallback)(() => {
1433
- webViewRef.current?.injectJavaScript(historyHomeScript);
1434
- }, [historyHomeScript]);
1435
- const handleNavigationStateChange = (0, import_react16.useCallback)(
1436
- (event) => {
1437
- if (event.url) {
1438
- trackScreen(event.url);
1439
- }
1440
- onNavigationStateChange(event);
1441
- },
1442
- [onNavigationStateChange]
1443
- );
1444
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1445
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1446
- PartnerWebviewNavigationBar,
1447
- {
1448
- handleBackEvent,
1449
- handleHomeIconButtonClick
1450
- }
1451
- ),
1452
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1453
- import_react_native_webview2.WebView,
1454
- {
1455
- ref: refs,
1456
- ...webViewProps,
1457
- style: { flex: 1 },
1458
- onNavigationStateChange: (event) => {
1459
- webViewProps?.onNavigationStateChange?.(event);
1460
- handleNavigationStateChange(event);
1461
- }
1462
- }
1463
- )
1464
- ] });
1465
- }
1466
- );
1322
+ };
1323
+ import_react_native32.BackHandler.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1324
+ return () => import_react_native32.BackHandler.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1325
+ }, [canHistoryGoBack, captureExitLog]);
1326
+ (0, import_react15.useEffect)(() => {
1327
+ return import_native_modules14.appsInTossEvent.addEventListener("homeIconButtonClickEvent", {
1328
+ onEvent: () => {
1329
+ webViewRef.current?.injectJavaScript(`
1330
+ (function() {
1331
+ window.history.replaceState(null, '', '/');
1332
+ true;
1333
+ })();
1334
+ `);
1335
+ }
1336
+ });
1337
+ }, [webViewRef]);
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1339
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PartnerWebviewNavigationBar, { handleBackEvent }),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_webview2.WebView, { ref: refs, ...webViewProps, style: { flex: 1 } })
1341
+ ] });
1342
+ });
1467
1343
 
1468
1344
  // src/bridge-handler/useBridgeHandler.tsx
1469
- var import_react17 = require("react");
1345
+ var import_react16 = require("react");
1470
1346
  function serializeError(error) {
1471
1347
  return JSON.stringify(error, (_, value) => {
1472
1348
  if (value instanceof Error) {
@@ -1515,8 +1391,8 @@ function useBridgeHandler({
1515
1391
  eventListenerMap,
1516
1392
  injectedJavaScript: originalInjectedJavaScript
1517
1393
  }) {
1518
- const ref = (0, import_react17.useRef)(null);
1519
- const injectedJavaScript = (0, import_react17.useMemo)(
1394
+ const ref = (0, import_react16.useRef)(null);
1395
+ const injectedJavaScript = (0, import_react16.useMemo)(
1520
1396
  () => [
1521
1397
  `window.__CONSTANT_HANDLER_MAP = ${JSON.stringify(
1522
1398
  Object.entries(constantHandlerMap).reduce(
@@ -1543,7 +1419,7 @@ function useBridgeHandler({
1543
1419
  window.__GRANITE_NATIVE_EMITTER.emit('${functionName}/onError/${eventId}', ${serializedError});
1544
1420
  `);
1545
1421
  };
1546
- const $onMessage = (0, import_react17.useCallback)(
1422
+ const $onMessage = (0, import_react16.useCallback)(
1547
1423
  async (e) => {
1548
1424
  onMessage?.(e);
1549
1425
  const data = JSON.parse(e.nativeEvent.data);
@@ -1595,7 +1471,7 @@ function useBridgeHandler({
1595
1471
 
1596
1472
  // src/hooks/useCreateUserAgent.ts
1597
1473
  var import_native_modules15 = require("@apps-in-toss/native-modules");
1598
- var import_react_native34 = require("react-native");
1474
+ var import_react_native33 = require("react-native");
1599
1475
  var FontA11yCategory = {
1600
1476
  Large: "Large",
1601
1477
  xLarge: "xLarge",
@@ -1730,7 +1606,7 @@ function useCreateUserAgent({
1730
1606
  }) {
1731
1607
  const platform = (0, import_native_modules15.getPlatformOS)();
1732
1608
  const appVersion = (0, import_native_modules15.getTossAppVersion)();
1733
- const { fontScale } = (0, import_react_native34.useWindowDimensions)();
1609
+ const { fontScale } = (0, import_react_native33.useWindowDimensions)();
1734
1610
  const platformString = platform === "ios" ? "iPhone" : "Android";
1735
1611
  const fontA11y = mapFontScaleToCategory(fontScale, platform);
1736
1612
  const normalizedFontScale = convertToAndroidStyleScale(fontScale, platform);
@@ -1751,12 +1627,12 @@ function useCreateUserAgent({
1751
1627
 
1752
1628
  // src/hooks/useGeolocation.ts
1753
1629
  var import_native_modules16 = require("@apps-in-toss/native-modules");
1754
- var import_react_native35 = require("@granite-js/react-native");
1755
- var import_react18 = require("react");
1630
+ var import_react_native34 = require("@granite-js/react-native");
1631
+ var import_react17 = require("react");
1756
1632
  function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
1757
- const isVisible = (0, import_react_native35.useVisibility)();
1758
- const [location, setLocation] = (0, import_react18.useState)(null);
1759
- (0, import_react18.useEffect)(() => {
1633
+ const isVisible = (0, import_react_native34.useVisibility)();
1634
+ const [location, setLocation] = (0, import_react17.useState)(null);
1635
+ (0, import_react17.useEffect)(() => {
1760
1636
  if (!isVisible) {
1761
1637
  return;
1762
1638
  }
@@ -1773,6 +1649,55 @@ function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
1773
1649
  return location;
1774
1650
  }
1775
1651
 
1652
+ // src/utils/log.ts
1653
+ var import_native_modules17 = require("@apps-in-toss/native-modules");
1654
+ var import_react_native35 = require("@granite-js/react-native");
1655
+
1656
+ // src/utils/extractDateFromUUIDv7.ts
1657
+ var extractDateFromUUIDv7 = (uuid) => {
1658
+ const timestampHex = uuid.split("-").join("").slice(0, 12);
1659
+ const timestamp = Number.parseInt(timestampHex, 16);
1660
+ return new Date(timestamp);
1661
+ };
1662
+
1663
+ // src/utils/log.ts
1664
+ var getGroupId = (url) => {
1665
+ try {
1666
+ const urlObject = new URL(url);
1667
+ return {
1668
+ groupId: urlObject.pathname,
1669
+ search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1670
+ };
1671
+ } catch {
1672
+ return {
1673
+ groupId: "unknown",
1674
+ search: "unknown"
1675
+ };
1676
+ }
1677
+ };
1678
+ var getReferrer = () => {
1679
+ try {
1680
+ const referrer = new URL((0, import_react_native35.getSchemeUri)());
1681
+ return referrer.searchParams.get("referrer");
1682
+ } catch {
1683
+ return "";
1684
+ }
1685
+ };
1686
+ var trackScreen = (url) => {
1687
+ const { groupId, search } = getGroupId(url);
1688
+ const log = {
1689
+ log_type: "screen",
1690
+ log_name: `${groupId}::screen`,
1691
+ params: {
1692
+ search,
1693
+ referrer: getReferrer(),
1694
+ deployment_id: env.getDeploymentId(),
1695
+ deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1696
+ }
1697
+ };
1698
+ return (0, import_native_modules17.eventLog)(log);
1699
+ };
1700
+
1776
1701
  // src/components/WebView.tsx
1777
1702
  var import_jsx_runtime12 = require("react/jsx-runtime");
1778
1703
  var operationalEnvironment = appsInTossConstantBridges.getOperationalEnvironment();
@@ -1796,7 +1721,7 @@ function getWebViewUri(local) {
1796
1721
  const devUrl = `http://${local.host}:${local.port}`;
1797
1722
  return mergeSchemeQueryParamsInto(devUrl).toString();
1798
1723
  }
1799
- const { url: rawUrl } = import_native_modules17.AppsInTossModule.getWebBundleURL({});
1724
+ const { url: rawUrl } = import_native_modules18.AppsInTossModule.getWebBundleURL({});
1800
1725
  const url = mergeSchemeQueryParamsInto(rawUrl);
1801
1726
  const deploymentId = env.getDeploymentId();
1802
1727
  if (deploymentId) {
@@ -1809,7 +1734,7 @@ function WebView({ type, local, onMessage, ...props }) {
1809
1734
  throw new Error(`Invalid WebView type: '${type}'`);
1810
1735
  }
1811
1736
  const graniteEvent = (0, import_react_native36.useGraniteEvent)();
1812
- const uri = (0, import_react19.useMemo)(() => getWebViewUri(local), [local]);
1737
+ const uri = (0, import_react18.useMemo)(() => getWebViewUri(local), [local]);
1813
1738
  const top = (0, import_private7.useSafeAreaTop)();
1814
1739
  const bottom = (0, import_private7.useSafeAreaBottom)();
1815
1740
  const global2 = getAppsInTossGlobals();
@@ -1821,7 +1746,7 @@ function WebView({ type, local, onMessage, ...props }) {
1821
1746
  document.head.appendChild(style);
1822
1747
  })();
1823
1748
  `;
1824
- const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = (0, import_react19.useState)(
1749
+ const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = (0, import_react18.useState)(
1825
1750
  props.allowsBackForwardNavigationGestures
1826
1751
  );
1827
1752
  const handler = useBridgeHandler({
@@ -1832,18 +1757,18 @@ function WebView({ type, local, onMessage, ...props }) {
1832
1757
  ...appsInTossEventBridges,
1833
1758
  navigationAccessoryEvent: ({ onEvent, onError }) => import_react_native37.tdsEvent.addEventListener("navigationAccessoryEvent", { onEvent, onError }),
1834
1759
  backEvent: ({ onEvent, onError, options }) => graniteEvent.addEventListener("backEvent", { onEvent, onError, options }),
1835
- entryMessageExited: ({ onEvent, onError }) => import_native_modules17.appsInTossEvent.addEventListener("entryMessageExited", { onEvent, onError }),
1836
- updateLocationEvent: ({ onEvent, onError, options }) => import_native_modules17.appsInTossEvent.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1760
+ entryMessageExited: ({ onEvent, onError }) => import_native_modules18.appsInTossEvent.addEventListener("entryMessageExited", { onEvent, onError }),
1761
+ updateLocationEvent: ({ onEvent, onError, options }) => import_native_modules18.appsInTossEvent.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1837
1762
  /** @internal */
1838
- appBridgeCallbackEvent: ({ onEvent, onError, options }) => import_native_modules17.appsInTossEvent.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1763
+ appBridgeCallbackEvent: ({ onEvent, onError, options }) => import_native_modules18.appsInTossEvent.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1839
1764
  /** AdMob */
1840
- loadAdMobInterstitialAd: import_native_modules17.GoogleAdMob.loadAdMobInterstitialAd,
1841
- showAdMobInterstitialAd: import_native_modules17.GoogleAdMob.showAdMobInterstitialAd,
1842
- loadAdMobRewardedAd: import_native_modules17.GoogleAdMob.loadAdMobRewardedAd,
1843
- showAdMobRewardedAd: import_native_modules17.GoogleAdMob.showAdMobRewardedAd,
1765
+ loadAdMobInterstitialAd: import_native_modules18.GoogleAdMob.loadAdMobInterstitialAd,
1766
+ showAdMobInterstitialAd: import_native_modules18.GoogleAdMob.showAdMobInterstitialAd,
1767
+ loadAdMobRewardedAd: import_native_modules18.GoogleAdMob.loadAdMobRewardedAd,
1768
+ showAdMobRewardedAd: import_native_modules18.GoogleAdMob.showAdMobRewardedAd,
1844
1769
  /** AdMobV2 */
1845
- loadAppsInTossAdMob: import_native_modules17.GoogleAdMob.loadAppsInTossAdMob,
1846
- showAppsInTossAdMob: import_native_modules17.GoogleAdMob.showAppsInTossAdMob
1770
+ loadAppsInTossAdMob: import_native_modules18.GoogleAdMob.loadAppsInTossAdMob,
1771
+ showAppsInTossAdMob: import_native_modules18.GoogleAdMob.showAppsInTossAdMob
1847
1772
  },
1848
1773
  constantHandlerMap: {
1849
1774
  ...graniteConstantBridges,
@@ -1852,13 +1777,13 @@ function WebView({ type, local, onMessage, ...props }) {
1852
1777
  getSafeAreaBottom: () => bottom,
1853
1778
  ...Object.fromEntries(Object.entries(global2).map(([key, value]) => [key, () => value])),
1854
1779
  /** AdMob */
1855
- loadAdMobInterstitialAd_isSupported: import_native_modules17.GoogleAdMob.loadAdMobInterstitialAd.isSupported,
1856
- showAdMobInterstitialAd_isSupported: import_native_modules17.GoogleAdMob.showAdMobInterstitialAd.isSupported,
1857
- loadAdMobRewardedAd_isSupported: import_native_modules17.GoogleAdMob.loadAdMobRewardedAd.isSupported,
1858
- showAdMobRewardedAd_isSupported: import_native_modules17.GoogleAdMob.showAdMobRewardedAd.isSupported,
1780
+ loadAdMobInterstitialAd_isSupported: import_native_modules18.GoogleAdMob.loadAdMobInterstitialAd.isSupported,
1781
+ showAdMobInterstitialAd_isSupported: import_native_modules18.GoogleAdMob.showAdMobInterstitialAd.isSupported,
1782
+ loadAdMobRewardedAd_isSupported: import_native_modules18.GoogleAdMob.loadAdMobRewardedAd.isSupported,
1783
+ showAdMobRewardedAd_isSupported: import_native_modules18.GoogleAdMob.showAdMobRewardedAd.isSupported,
1859
1784
  /** AdMobV2 */
1860
- loadAppsInTossAdMob_isSupported: import_native_modules17.GoogleAdMob.loadAppsInTossAdMob.isSupported,
1861
- showAppsInTossAdMob_isSupported: import_native_modules17.GoogleAdMob.showAppsInTossAdMob.isSupported,
1785
+ loadAppsInTossAdMob_isSupported: import_native_modules18.GoogleAdMob.loadAppsInTossAdMob.isSupported,
1786
+ showAppsInTossAdMob_isSupported: import_native_modules18.GoogleAdMob.showAppsInTossAdMob.isSupported,
1862
1787
  /** env */
1863
1788
  getDeploymentId: env.getDeploymentId
1864
1789
  },
@@ -1882,16 +1807,16 @@ function WebView({ type, local, onMessage, ...props }) {
1882
1807
  getCurrentLocation: appsInTossAsyncBridges.getCurrentLocation,
1883
1808
  openCamera: appsInTossAsyncBridges.openCamera,
1884
1809
  /** Storage */
1885
- getStorageItem: import_native_modules17.Storage.getItem,
1886
- setStorageItem: import_native_modules17.Storage.setItem,
1887
- removeStorageItem: import_native_modules17.Storage.removeItem,
1888
- clearItems: import_native_modules17.Storage.clearItems,
1810
+ getStorageItem: import_native_modules18.Storage.getItem,
1811
+ setStorageItem: import_native_modules18.Storage.setItem,
1812
+ removeStorageItem: import_native_modules18.Storage.removeItem,
1813
+ clearItems: import_native_modules18.Storage.clearItems,
1889
1814
  /** IAP */
1890
- iapCreateOneTimePurchaseOrder: import_native_modules17.IAP.createOneTimePurchaseOrder,
1891
- iapGetProductItemList: import_native_modules17.IAP.getProductItemList
1815
+ iapCreateOneTimePurchaseOrder: import_native_modules18.IAP.createOneTimePurchaseOrder,
1816
+ iapGetProductItemList: import_native_modules18.IAP.getProductItemList
1892
1817
  }
1893
1818
  });
1894
- const headerPropForExternalWebView = (0, import_react19.useMemo)(() => {
1819
+ const headerPropForExternalWebView = (0, import_react18.useMemo)(() => {
1895
1820
  const parsedNavigationBar = global2.navigationBar != null ? safeParseNavigationBar(global2.navigationBar) : null;
1896
1821
  const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
1897
1822
  const withBackButton = parsedNavigationBar?.withBackButton ?? true;
@@ -1908,6 +1833,16 @@ function WebView({ type, local, onMessage, ...props }) {
1908
1833
  }, [global2.navigationBar, type]);
1909
1834
  const BaseWebView = WEBVIEW_TYPES[type];
1910
1835
  const webViewDebuggingEnabled = operationalEnvironment === "sandbox";
1836
+ const [canHistoryGoBack, setCanHistoryGoBack] = (0, import_react18.useState)(false);
1837
+ const handleNavigationStateChange = (0, import_react18.useCallback)(
1838
+ (event) => {
1839
+ if (event.url) {
1840
+ trackScreen(event.url);
1841
+ }
1842
+ setCanHistoryGoBack(event.canGoBack);
1843
+ },
1844
+ [setCanHistoryGoBack]
1845
+ );
1911
1846
  const userAgent = useCreateUserAgent({
1912
1847
  colorPreference: "light"
1913
1848
  });
@@ -1929,6 +1864,8 @@ function WebView({ type, local, onMessage, ...props }) {
1929
1864
  webviewDebuggingEnabled: webViewDebuggingEnabled,
1930
1865
  thirdPartyCookiesEnabled: true,
1931
1866
  onMessage: handler.onMessage,
1867
+ canHistoryGoBack,
1868
+ onNavigationStateChange: handleNavigationStateChange,
1932
1869
  injectedJavaScript: handler.injectedJavaScript,
1933
1870
  injectedJavaScriptBeforeContentLoaded: handler.injectedJavaScript,
1934
1871
  decelerationRate: import_react_native38.Platform.OS === "ios" ? 1 : void 0,
package/dist/index.d.cts CHANGED
@@ -27,7 +27,9 @@ declare const AppsInToss: {
27
27
  registerApp: typeof registerApp;
28
28
  };
29
29
 
30
- type GameWebViewProps$1 = WebViewProps$1;
30
+ type GameWebViewProps$1 = WebViewProps$1 & {
31
+ canHistoryGoBack: boolean;
32
+ };
31
33
 
32
34
  type WebViewProps = PartnerWebViewProps | ExternalWebViewProps | GameWebViewProps;
33
35
  interface PartnerWebViewProps extends Omit<WebViewProps$1, InternalProps> {
package/dist/index.d.ts CHANGED
@@ -27,7 +27,9 @@ declare const AppsInToss: {
27
27
  registerApp: typeof registerApp;
28
28
  };
29
29
 
30
- type GameWebViewProps$1 = WebViewProps$1;
30
+ type GameWebViewProps$1 = WebViewProps$1 & {
31
+ canHistoryGoBack: boolean;
32
+ };
31
33
 
32
34
  type WebViewProps = PartnerWebViewProps | ExternalWebViewProps | GameWebViewProps;
33
35
  interface PartnerWebViewProps extends Omit<WebViewProps$1, InternalProps> {
package/dist/index.js CHANGED
@@ -295,7 +295,7 @@ function NavigationBarImpressionArea({
295
295
  logging.navBarImpression({ home_icon_yn: withHomeButton ? "Y" : "N" });
296
296
  hasLogged.current = true;
297
297
  }
298
- }, []);
298
+ }, [logging, withHomeButton]);
299
299
  return /* @__PURE__ */ jsx2(Fragment2, { children });
300
300
  }
301
301
 
@@ -639,16 +639,16 @@ function RNNavigationBar() {
639
639
  }
640
640
  handleBackOrClose();
641
641
  }, [backEventContext, handleBackOrClose]);
642
- const handleAndroidBackEvent = useCallback3(() => {
643
- handleBack();
644
- return true;
645
- }, [handleBack]);
646
642
  useEffect7(() => {
643
+ const handleAndroidBackEvent = () => {
644
+ handleBack();
645
+ return true;
646
+ };
647
647
  BackHandler.addEventListener("hardwareBackPress", handleAndroidBackEvent);
648
648
  return () => {
649
649
  BackHandler.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
650
650
  };
651
- }, [handleAndroidBackEvent]);
651
+ }, [handleBack]);
652
652
  return /* @__PURE__ */ jsx4(NavigationBarImpressionArea, { withHomeButton, children: /* @__PURE__ */ jsx4(
653
653
  TopNavigation,
654
654
  {
@@ -729,9 +729,9 @@ function registerApp(container, { context, analytics }) {
729
729
  return global.Page;
730
730
  }
731
731
  function AppsInTossScreenContainer({ children }) {
732
- const isRN = getAppsInTossGlobals().webViewType == null;
732
+ const isReactNativeService = getAppsInTossGlobals().webViewType == null;
733
733
  return /* @__PURE__ */ jsxs(Analytics.Screen, { children: [
734
- isRN && /* @__PURE__ */ jsx5(RNNavigationBar, {}),
734
+ isReactNativeService && /* @__PURE__ */ jsx5(RNNavigationBar, {}),
735
735
  children
736
736
  ] });
737
737
  }
@@ -750,7 +750,7 @@ var AppsInToss = {
750
750
  };
751
751
 
752
752
  // src/components/WebView.tsx
753
- import { GoogleAdMob, IAP, Storage, AppsInTossModule, appsInTossEvent as appsInTossEvent3 } from "@apps-in-toss/native-modules";
753
+ import { GoogleAdMob, IAP, Storage, AppsInTossModule, appsInTossEvent as appsInTossEvent5 } from "@apps-in-toss/native-modules";
754
754
  import * as appsInTossAsyncBridges from "@apps-in-toss/native-modules/async-bridges";
755
755
  import * as appsInTossConstantBridges from "@apps-in-toss/native-modules/constant-bridges";
756
756
  import * as appsInTossEventBridges from "@apps-in-toss/native-modules/event-bridges";
@@ -759,7 +759,7 @@ import * as graniteAsyncBridges from "@granite-js/react-native/async-bridges";
759
759
  import * as graniteConstantBridges from "@granite-js/react-native/constant-bridges";
760
760
  import { ExternalWebViewScreen, tdsEvent } from "@toss-design-system/react-native";
761
761
  import { useSafeAreaBottom, useSafeAreaTop as useSafeAreaTop2, useTopNavigation } from "@toss-design-system/react-native/private";
762
- import { useMemo as useMemo3, useState as useState6 } from "react";
762
+ import { useCallback as useCallback9, useMemo as useMemo3, useState as useState5 } from "react";
763
763
  import { Platform as Platform4 } from "react-native";
764
764
 
765
765
  // src/components/GameWebView.tsx
@@ -777,7 +777,7 @@ import { useEffect as useEffect8 } from "react";
777
777
  import { Pressable, View } from "react-native";
778
778
 
779
779
  // src/constant/game-center.ts
780
- var GAME_PROFILE_WEBVIEW_URL = "https://service.toss.im/game-center/profile";
780
+ var GAME_PROFILE_WEBVIEW_URL = "servicetoss://game-center/profile";
781
781
  var GAME_CENTER_MIN_VERSION = {
782
782
  android: "5.221.0",
783
783
  ios: "5.221.0"
@@ -1115,14 +1115,14 @@ function GameWebviewNavigationBar() {
1115
1115
  closeView3();
1116
1116
  }
1117
1117
  }, [captureExitLog, global2.brandDisplayName, logging, openConfirm]);
1118
- const handleAndroidBackEvent = useCallback5(() => {
1119
- handleGameWebviewClose();
1120
- return true;
1121
- }, [handleGameWebviewClose]);
1122
1118
  useEffect9(() => {
1119
+ const handleAndroidBackEvent = () => {
1120
+ handleGameWebviewClose();
1121
+ return true;
1122
+ };
1123
1123
  BackHandler2.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1124
1124
  return () => BackHandler2.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1125
- }, [handleAndroidBackEvent]);
1125
+ }, [handleGameWebviewClose]);
1126
1126
  return /* @__PURE__ */ jsxs3(Fragment6, { children: [
1127
1127
  /* @__PURE__ */ jsx8(PageNavbar, { preference: { type: "none" } }),
1128
1128
  /* @__PURE__ */ jsx8(
@@ -1130,6 +1130,7 @@ function GameWebviewNavigationBar() {
1130
1130
  {
1131
1131
  style: {
1132
1132
  width: "100%",
1133
+ // TODO: UI관련 스타일 설정은 TDS로 이관
1133
1134
  height: Platform2.OS === "ios" ? 44 : 54,
1134
1135
  flexDirection: "row",
1135
1136
  alignItems: "center",
@@ -1145,7 +1146,10 @@ function GameWebviewNavigationBar() {
1145
1146
  {
1146
1147
  fixedRightButton: initialAccessoryButton,
1147
1148
  onPressDots: openMoreButtonBottomSheet,
1148
- onPressClose: handleGameWebviewClose,
1149
+ onPressClose: () => {
1150
+ logging.closeButtonClick();
1151
+ handleGameWebviewClose();
1152
+ },
1149
1153
  theme: "dark"
1150
1154
  }
1151
1155
  )
@@ -1181,21 +1185,22 @@ var GameWebView = forwardRef(function GameWebView2(props, ref) {
1181
1185
  });
1182
1186
 
1183
1187
  // src/components/PartnerWebView.tsx
1184
- import { closeView as closeView5 } from "@apps-in-toss/native-modules";
1188
+ import { appsInTossEvent as appsInTossEvent4, closeView as closeView5 } from "@apps-in-toss/native-modules";
1185
1189
  import {
1186
1190
  WebView as PlainWebView2
1187
1191
  } from "@granite-js/native/react-native-webview";
1188
- import { forwardRef as forwardRef2, useCallback as useCallback8, useEffect as useEffect11, useRef as useRef4 } from "react";
1192
+ import { forwardRef as forwardRef2, useCallback as useCallback7, useEffect as useEffect11, useRef as useRef4 } from "react";
1189
1193
  import { BackHandler as BackHandler3 } from "react-native";
1190
1194
 
1191
1195
  // src/components/NavigationBar/PartnerWebviewNavigationBar.tsx
1196
+ import { appsInTossEvent as appsInTossEvent3 } from "@apps-in-toss/native-modules";
1192
1197
  import { closeView as closeView4 } from "@granite-js/react-native";
1193
1198
  import { useDialog as useDialog5 } from "@toss-design-system/react-native";
1194
1199
  import { NavigationBackButton as NavigationBackButton2, NavigationLeft as NavigationLeft2, TopNavigation as TopNavigation2 } from "@toss-design-system/react-native/private";
1195
1200
  import { josa as josa4 } from "es-hangul";
1196
1201
  import { useCallback as useCallback6 } from "react";
1197
1202
  import { jsx as jsx10 } from "react/jsx-runtime";
1198
- function PartnerWebviewNavigationBar({ handleBackEvent, handleHomeIconButtonClick }) {
1203
+ function PartnerWebviewNavigationBar({ handleBackEvent }) {
1199
1204
  const globals = getAppsInTossGlobals();
1200
1205
  const { captureExitLog } = useCaptureExitLog();
1201
1206
  const logging = useNavigationBarLogging();
@@ -1207,8 +1212,8 @@ function PartnerWebviewNavigationBar({ handleBackEvent, handleHomeIconButtonClic
1207
1212
  const initialAccessoryButton = parsedNavigationBar?.initialAccessoryButton;
1208
1213
  const handlePressTitle = useCallback6(() => {
1209
1214
  logging.homeButtonClick();
1210
- handleHomeIconButtonClick();
1211
- }, [handleHomeIconButtonClick, logging]);
1215
+ appsInTossEvent3.emit("homeIconButtonClickEvent", void 0);
1216
+ }, [logging]);
1212
1217
  const handleClose = useCallback6(async () => {
1213
1218
  logging.closeButtonClick();
1214
1219
  const isConfirmed = await openConfirm({
@@ -1253,182 +1258,53 @@ function mergeRefs(...refs) {
1253
1258
  };
1254
1259
  }
1255
1260
 
1256
- // src/hooks/useWebviewHistoryStack.tsx
1257
- import { useCallback as useCallback7, useState as useState4 } from "react";
1258
- function useWebViewHistory() {
1259
- const [stack, setStack] = useState4([]);
1260
- const [index, setIndex] = useState4(-1);
1261
- const canGoBack = index > 0;
1262
- const canGoForward = index >= 0 && index < stack.length - 1;
1263
- const push = useCallback7(
1264
- (url) => {
1265
- setStack((prev) => {
1266
- const base = prev.slice(0, index + 1);
1267
- return [...base, url];
1268
- });
1269
- setIndex((i) => i + 1);
1270
- },
1271
- [index]
1272
- );
1273
- const onNavigationStateChange = useCallback7(
1274
- ({ url }) => {
1275
- if (stack.length === 0) {
1276
- setStack([url]);
1277
- setIndex(0);
1278
- return;
1279
- }
1280
- const cur = stack[index];
1281
- if (url === cur) {
1282
- return;
1283
- }
1284
- const prev = index > 0 ? stack[index - 1] : void 0;
1285
- const next = index < stack.length - 1 ? stack[index + 1] : void 0;
1286
- if (prev && url === prev) {
1287
- setIndex((i) => i - 1);
1288
- return;
1289
- }
1290
- if (next && url === next) {
1291
- setIndex((i) => i + 1);
1292
- return;
1293
- }
1294
- push(url);
1295
- },
1296
- [stack, index, push]
1297
- );
1298
- return {
1299
- onNavigationStateChange,
1300
- canGoBack,
1301
- canGoForward
1302
- };
1303
- }
1304
-
1305
- // src/utils/log.ts
1306
- import { eventLog as eventLogNative } from "@apps-in-toss/native-modules";
1307
- import { getSchemeUri as getSchemeUri4 } from "@granite-js/react-native";
1308
-
1309
- // src/utils/extractDateFromUUIDv7.ts
1310
- var extractDateFromUUIDv7 = (uuid) => {
1311
- const timestampHex = uuid.split("-").join("").slice(0, 12);
1312
- const timestamp = Number.parseInt(timestampHex, 16);
1313
- return new Date(timestamp);
1314
- };
1315
-
1316
- // src/utils/log.ts
1317
- var getGroupId = (url) => {
1318
- try {
1319
- const urlObject = new URL(url);
1320
- return {
1321
- groupId: urlObject.pathname,
1322
- search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1323
- };
1324
- } catch {
1325
- return {
1326
- groupId: "unknown",
1327
- search: "unknown"
1328
- };
1329
- }
1330
- };
1331
- var getReferrer = () => {
1332
- try {
1333
- const referrer = new URL(getSchemeUri4());
1334
- return referrer.searchParams.get("referrer");
1335
- } catch {
1336
- return "";
1337
- }
1338
- };
1339
- var trackScreen = (url) => {
1340
- const { groupId, search } = getGroupId(url);
1341
- const log = {
1342
- log_type: "screen",
1343
- log_name: `${groupId}::screen`,
1344
- params: {
1345
- search,
1346
- referrer: getReferrer(),
1347
- deployment_id: env.getDeploymentId(),
1348
- deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1349
- }
1350
- };
1351
- return eventLogNative(log);
1352
- };
1353
-
1354
1261
  // src/components/PartnerWebView.tsx
1355
1262
  import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1356
- var PartnerWebView = forwardRef2(
1357
- function PartnerWebViewScreen(webViewProps, ref) {
1358
- const webViewRef = useRef4(null);
1359
- const refs = mergeRefs(ref, webViewRef);
1360
- const { captureExitLog } = useCaptureExitLog();
1361
- const { canGoBack, onNavigationStateChange } = useWebViewHistory();
1362
- const historyBackScript = `
1363
- (function() {
1364
- history.back();
1365
- true;
1366
- })();
1367
- `;
1368
- const historyHomeScript = `
1369
- (function() {
1370
- history.replaceState(null, '', '/');
1371
- true;
1372
- })();
1373
- `;
1374
- const handleBackEvent = useCallback8(() => {
1375
- if (canGoBack) {
1376
- webViewRef.current?.injectJavaScript(historyBackScript);
1377
- } else {
1378
- captureExitLog(Date.now());
1379
- closeView5();
1380
- }
1381
- }, [canGoBack, captureExitLog, historyBackScript]);
1382
- const handleAndroidBackEvent = useCallback8(() => {
1383
- if (canGoBack) {
1384
- webViewRef.current?.injectJavaScript(historyBackScript);
1263
+ var PartnerWebView = forwardRef2(function PartnerWebViewScreen({ canHistoryGoBack, ...webViewProps }, ref) {
1264
+ const webViewRef = useRef4(null);
1265
+ const refs = mergeRefs(ref, webViewRef);
1266
+ const { captureExitLog } = useCaptureExitLog();
1267
+ const handleBackEvent = useCallback7(() => {
1268
+ if (canHistoryGoBack) {
1269
+ webViewRef.current?.goBack();
1270
+ } else {
1271
+ captureExitLog(Date.now());
1272
+ closeView5();
1273
+ }
1274
+ }, [canHistoryGoBack, captureExitLog]);
1275
+ useEffect11(() => {
1276
+ const handleAndroidBackEvent = () => {
1277
+ if (canHistoryGoBack) {
1278
+ webViewRef.current?.goBack();
1385
1279
  return true;
1386
1280
  } else {
1281
+ captureExitLog(Date.now());
1387
1282
  return false;
1388
1283
  }
1389
- }, [canGoBack, historyBackScript]);
1390
- useEffect11(() => {
1391
- BackHandler3.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1392
- return () => BackHandler3.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1393
- }, [handleAndroidBackEvent]);
1394
- const handleHomeIconButtonClick = useCallback8(() => {
1395
- webViewRef.current?.injectJavaScript(historyHomeScript);
1396
- }, [historyHomeScript]);
1397
- const handleNavigationStateChange = useCallback8(
1398
- (event) => {
1399
- if (event.url) {
1400
- trackScreen(event.url);
1401
- }
1402
- onNavigationStateChange(event);
1403
- },
1404
- [onNavigationStateChange]
1405
- );
1406
- return /* @__PURE__ */ jsxs5(Fragment8, { children: [
1407
- /* @__PURE__ */ jsx11(
1408
- PartnerWebviewNavigationBar,
1409
- {
1410
- handleBackEvent,
1411
- handleHomeIconButtonClick
1412
- }
1413
- ),
1414
- /* @__PURE__ */ jsx11(
1415
- PlainWebView2,
1416
- {
1417
- ref: refs,
1418
- ...webViewProps,
1419
- style: { flex: 1 },
1420
- onNavigationStateChange: (event) => {
1421
- webViewProps?.onNavigationStateChange?.(event);
1422
- handleNavigationStateChange(event);
1423
- }
1424
- }
1425
- )
1426
- ] });
1427
- }
1428
- );
1284
+ };
1285
+ BackHandler3.addEventListener("hardwareBackPress", handleAndroidBackEvent);
1286
+ return () => BackHandler3.removeEventListener("hardwareBackPress", handleAndroidBackEvent);
1287
+ }, [canHistoryGoBack, captureExitLog]);
1288
+ useEffect11(() => {
1289
+ return appsInTossEvent4.addEventListener("homeIconButtonClickEvent", {
1290
+ onEvent: () => {
1291
+ webViewRef.current?.injectJavaScript(`
1292
+ (function() {
1293
+ window.history.replaceState(null, '', '/');
1294
+ true;
1295
+ })();
1296
+ `);
1297
+ }
1298
+ });
1299
+ }, [webViewRef]);
1300
+ return /* @__PURE__ */ jsxs5(Fragment8, { children: [
1301
+ /* @__PURE__ */ jsx11(PartnerWebviewNavigationBar, { handleBackEvent }),
1302
+ /* @__PURE__ */ jsx11(PlainWebView2, { ref: refs, ...webViewProps, style: { flex: 1 } })
1303
+ ] });
1304
+ });
1429
1305
 
1430
1306
  // src/bridge-handler/useBridgeHandler.tsx
1431
- import { useCallback as useCallback9, useMemo as useMemo2, useRef as useRef5 } from "react";
1307
+ import { useCallback as useCallback8, useMemo as useMemo2, useRef as useRef5 } from "react";
1432
1308
  function serializeError(error) {
1433
1309
  return JSON.stringify(error, (_, value) => {
1434
1310
  if (value instanceof Error) {
@@ -1505,7 +1381,7 @@ function useBridgeHandler({
1505
1381
  window.__GRANITE_NATIVE_EMITTER.emit('${functionName}/onError/${eventId}', ${serializedError});
1506
1382
  `);
1507
1383
  };
1508
- const $onMessage = useCallback9(
1384
+ const $onMessage = useCallback8(
1509
1385
  async (e) => {
1510
1386
  onMessage?.(e);
1511
1387
  const data = JSON.parse(e.nativeEvent.data);
@@ -1714,10 +1590,10 @@ function useCreateUserAgent({
1714
1590
  // src/hooks/useGeolocation.ts
1715
1591
  import { startUpdateLocation } from "@apps-in-toss/native-modules";
1716
1592
  import { useVisibility as useVisibility3 } from "@granite-js/react-native";
1717
- import { useEffect as useEffect12, useState as useState5 } from "react";
1593
+ import { useEffect as useEffect12, useState as useState4 } from "react";
1718
1594
  function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
1719
1595
  const isVisible = useVisibility3();
1720
- const [location, setLocation] = useState5(null);
1596
+ const [location, setLocation] = useState4(null);
1721
1597
  useEffect12(() => {
1722
1598
  if (!isVisible) {
1723
1599
  return;
@@ -1735,6 +1611,55 @@ function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
1735
1611
  return location;
1736
1612
  }
1737
1613
 
1614
+ // src/utils/log.ts
1615
+ import { eventLog as eventLogNative } from "@apps-in-toss/native-modules";
1616
+ import { getSchemeUri as getSchemeUri4 } from "@granite-js/react-native";
1617
+
1618
+ // src/utils/extractDateFromUUIDv7.ts
1619
+ var extractDateFromUUIDv7 = (uuid) => {
1620
+ const timestampHex = uuid.split("-").join("").slice(0, 12);
1621
+ const timestamp = Number.parseInt(timestampHex, 16);
1622
+ return new Date(timestamp);
1623
+ };
1624
+
1625
+ // src/utils/log.ts
1626
+ var getGroupId = (url) => {
1627
+ try {
1628
+ const urlObject = new URL(url);
1629
+ return {
1630
+ groupId: urlObject.pathname,
1631
+ search: urlObject.search.startsWith("?") ? urlObject.search.substring(1) : urlObject.search
1632
+ };
1633
+ } catch {
1634
+ return {
1635
+ groupId: "unknown",
1636
+ search: "unknown"
1637
+ };
1638
+ }
1639
+ };
1640
+ var getReferrer = () => {
1641
+ try {
1642
+ const referrer = new URL(getSchemeUri4());
1643
+ return referrer.searchParams.get("referrer");
1644
+ } catch {
1645
+ return "";
1646
+ }
1647
+ };
1648
+ var trackScreen = (url) => {
1649
+ const { groupId, search } = getGroupId(url);
1650
+ const log = {
1651
+ log_type: "screen",
1652
+ log_name: `${groupId}::screen`,
1653
+ params: {
1654
+ search,
1655
+ referrer: getReferrer(),
1656
+ deployment_id: env.getDeploymentId(),
1657
+ deployment_timestamp: extractDateFromUUIDv7(env.getDeploymentId()).getTime()
1658
+ }
1659
+ };
1660
+ return eventLogNative(log);
1661
+ };
1662
+
1738
1663
  // src/components/WebView.tsx
1739
1664
  import { jsx as jsx12 } from "react/jsx-runtime";
1740
1665
  var operationalEnvironment = appsInTossConstantBridges.getOperationalEnvironment();
@@ -1783,7 +1708,7 @@ function WebView({ type, local, onMessage, ...props }) {
1783
1708
  document.head.appendChild(style);
1784
1709
  })();
1785
1710
  `;
1786
- const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = useState6(
1711
+ const [allowsBackForwardNavigationGestures, setAllowsBackForwardNavigationGestures] = useState5(
1787
1712
  props.allowsBackForwardNavigationGestures
1788
1713
  );
1789
1714
  const handler = useBridgeHandler({
@@ -1794,10 +1719,10 @@ function WebView({ type, local, onMessage, ...props }) {
1794
1719
  ...appsInTossEventBridges,
1795
1720
  navigationAccessoryEvent: ({ onEvent, onError }) => tdsEvent.addEventListener("navigationAccessoryEvent", { onEvent, onError }),
1796
1721
  backEvent: ({ onEvent, onError, options }) => graniteEvent.addEventListener("backEvent", { onEvent, onError, options }),
1797
- entryMessageExited: ({ onEvent, onError }) => appsInTossEvent3.addEventListener("entryMessageExited", { onEvent, onError }),
1798
- updateLocationEvent: ({ onEvent, onError, options }) => appsInTossEvent3.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1722
+ entryMessageExited: ({ onEvent, onError }) => appsInTossEvent5.addEventListener("entryMessageExited", { onEvent, onError }),
1723
+ updateLocationEvent: ({ onEvent, onError, options }) => appsInTossEvent5.addEventListener("updateLocationEvent", { onEvent, onError, options }),
1799
1724
  /** @internal */
1800
- appBridgeCallbackEvent: ({ onEvent, onError, options }) => appsInTossEvent3.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1725
+ appBridgeCallbackEvent: ({ onEvent, onError, options }) => appsInTossEvent5.addEventListener("appBridgeCallbackEvent", { onEvent, onError, options }),
1801
1726
  /** AdMob */
1802
1727
  loadAdMobInterstitialAd: GoogleAdMob.loadAdMobInterstitialAd,
1803
1728
  showAdMobInterstitialAd: GoogleAdMob.showAdMobInterstitialAd,
@@ -1870,6 +1795,16 @@ function WebView({ type, local, onMessage, ...props }) {
1870
1795
  }, [global2.navigationBar, type]);
1871
1796
  const BaseWebView = WEBVIEW_TYPES[type];
1872
1797
  const webViewDebuggingEnabled = operationalEnvironment === "sandbox";
1798
+ const [canHistoryGoBack, setCanHistoryGoBack] = useState5(false);
1799
+ const handleNavigationStateChange = useCallback9(
1800
+ (event) => {
1801
+ if (event.url) {
1802
+ trackScreen(event.url);
1803
+ }
1804
+ setCanHistoryGoBack(event.canGoBack);
1805
+ },
1806
+ [setCanHistoryGoBack]
1807
+ );
1873
1808
  const userAgent = useCreateUserAgent({
1874
1809
  colorPreference: "light"
1875
1810
  });
@@ -1891,6 +1826,8 @@ function WebView({ type, local, onMessage, ...props }) {
1891
1826
  webviewDebuggingEnabled: webViewDebuggingEnabled,
1892
1827
  thirdPartyCookiesEnabled: true,
1893
1828
  onMessage: handler.onMessage,
1829
+ canHistoryGoBack,
1830
+ onNavigationStateChange: handleNavigationStateChange,
1894
1831
  injectedJavaScript: handler.injectedJavaScript,
1895
1832
  injectedJavaScriptBeforeContentLoaded: handler.injectedJavaScript,
1896
1833
  decelerationRate: Platform4.OS === "ios" ? 1 : void 0,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@apps-in-toss/framework",
3
3
  "type": "module",
4
- "version": "0.0.0-dev.1758103372343",
4
+ "version": "0.0.0-dev.1758198081085",
5
5
  "description": "The framework for Apps In Toss",
6
6
  "scripts": {
7
7
  "prepack": "yarn build",
@@ -56,11 +56,11 @@
56
56
  "ait": "./bin/ait.js"
57
57
  },
58
58
  "dependencies": {
59
- "@apps-in-toss/analytics": "0.0.0-dev.1758103372343",
60
- "@apps-in-toss/cli": "0.0.0-dev.1758103372343",
61
- "@apps-in-toss/native-modules": "0.0.0-dev.1758103372343",
62
- "@apps-in-toss/plugins": "0.0.0-dev.1758103372343",
63
- "@apps-in-toss/types": "0.0.0-dev.1758103372343",
59
+ "@apps-in-toss/analytics": "0.0.0-dev.1758198081085",
60
+ "@apps-in-toss/cli": "0.0.0-dev.1758198081085",
61
+ "@apps-in-toss/native-modules": "0.0.0-dev.1758198081085",
62
+ "@apps-in-toss/plugins": "0.0.0-dev.1758198081085",
63
+ "@apps-in-toss/types": "0.0.0-dev.1758198081085",
64
64
  "es-hangul": "^2.3.2"
65
65
  },
66
66
  "devDependencies": {
@@ -96,5 +96,5 @@
96
96
  "publishConfig": {
97
97
  "access": "public"
98
98
  },
99
- "gitHead": "dd32f2c8028913b7f866a3a099728410d783dcd6"
99
+ "gitHead": "bfc8653621ef7fc455cc5cf8fd9ff885da0f69d0"
100
100
  }