@apps-in-toss/framework 0.0.13 → 0.0.15

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
@@ -5,10 +5,49 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/core/registerApp.tsx
8
+ import { TDSProvider } from "@toss-design-system/react-native";
8
9
  import { Bedrock } from "react-native-bedrock";
9
- import { jsx } from "react/jsx-runtime";
10
+
11
+ // src/core/hooks/useAppsInTossBridge.ts
12
+ import { useBridge } from "@toss-design-system/react-native";
13
+ import { useEffect } from "react";
14
+
15
+ // src/core/utils/getAppsInTossGlobals.ts
16
+ function getAppsInTossGlobals() {
17
+ if (global.__appsInToss == null) {
18
+ throw new Error("invalid apps-in-toss globals");
19
+ }
20
+ return global.__appsInToss;
21
+ }
22
+
23
+ // src/core/utils/toIcon.ts
24
+ function toIcon(source) {
25
+ return source.startsWith("http") ? { source: { uri: source } } : { name: source };
26
+ }
27
+
28
+ // src/core/hooks/useAppsInTossBridge.ts
29
+ function useAppsInTossBridge() {
30
+ const controller = useBridge();
31
+ const appsInTossGlobals2 = getAppsInTossGlobals();
32
+ useEffect(() => {
33
+ const commonProps = {
34
+ serviceName: appsInTossGlobals2.brandDisplayName,
35
+ icon: toIcon(appsInTossGlobals2.brandIcon),
36
+ color: appsInTossGlobals2.brandPrimaryColor,
37
+ colorMode: appsInTossGlobals2.brandBridgeColorMode
38
+ };
39
+ controller.open({ ...commonProps });
40
+ }, []);
41
+ }
42
+
43
+ // src/core/registerApp.tsx
44
+ import { Fragment, jsx } from "react/jsx-runtime";
10
45
  function AppsInTossContainer(Container, { children, ...initialProps }) {
11
- return /* @__PURE__ */ jsx(Container, { ...initialProps, children });
46
+ return /* @__PURE__ */ jsx(Container, { ...initialProps, children: /* @__PURE__ */ jsx(TDSProvider, { colorPreference: "light", token: { color: { primary: getAppsInTossGlobals().brandPrimaryColor } }, children: /* @__PURE__ */ jsx(TDSContainer, { ...initialProps, children }) }) });
47
+ }
48
+ function TDSContainer({ children }) {
49
+ useAppsInTossBridge();
50
+ return /* @__PURE__ */ jsx(Fragment, { children });
12
51
  }
13
52
  function registerApp(container, { context }) {
14
53
  return Bedrock.registerApp(AppsInTossContainer.bind(null, container), {
@@ -103,6 +142,16 @@ function startUpdateLocation(eventParams) {
103
142
  return appsInTossEvent.addEventListener("updateLocationEvent", eventParams);
104
143
  }
105
144
 
145
+ // src/native-modules/checkoutPayment.ts
146
+ async function checkoutPayment(options) {
147
+ return AppsInTossModule.checkoutPayment(options);
148
+ }
149
+
150
+ // src/native-modules/executePayment.ts
151
+ async function executePayment(options) {
152
+ return AppsInTossModule.executePayment(options);
153
+ }
154
+
106
155
  // src/native-modules/setClipboardText.ts
107
156
  async function setClipboardText(text) {
108
157
  const permissionStatus = await requestPermission({ name: "clipboard", access: "write" });
@@ -189,19 +238,145 @@ function getOperationalEnvironment() {
189
238
  return AppsInTossModule.operationalEnvironment;
190
239
  }
191
240
 
241
+ // src/native-modules/index.ts
242
+ var TossPay = {
243
+ checkoutPayment,
244
+ executePayment
245
+ };
246
+
192
247
  // src/components/WebView.tsx
193
248
  import {
194
- WebView as OriginalWebView
195
- } from "@react-native-bedrock/native/react-native-webview";
249
+ PartnerWebViewScreen,
250
+ ExternalWebViewScreen
251
+ } from "@toss-design-system/react-native";
196
252
  import { useMemo } from "react";
197
- import { useBridgeHandler } from "react-native-bedrock";
253
+ import { getSchemeUri, useBridgeHandler } from "react-native-bedrock";
198
254
  import * as bedrockAsyncBridges from "react-native-bedrock/async-bridges";
199
255
  import * as bedrockConstantBridges from "react-native-bedrock/constant-bridges";
200
256
 
257
+ // src/components/GameWebView.tsx
258
+ import {
259
+ WebView as PlainWebView
260
+ } from "@react-native-bedrock/native/react-native-webview";
261
+ import { forwardRef } from "react";
262
+ import { View as View3 } from "react-native";
263
+ import { closeView } from "react-native-bedrock";
264
+
265
+ // src/components/GameWebViewNavigationBar/GameNavigationBar.tsx
266
+ import { SvgXml } from "@react-native-bedrock/native/react-native-svg";
267
+ import { PageNavbar } from "@toss-design-system/react-native";
268
+ import { Platform as Platform3, TouchableOpacity, View as View2 } from "react-native";
269
+
270
+ // src/components/GameWebViewNavigationBar/HeaderRight.tsx
271
+ import { StyleSheet, View } from "react-native";
272
+
273
+ // src/components/GameWebViewNavigationBar/byPlatform.ts
274
+ import { Platform } from "react-native";
275
+ function byPlatform({
276
+ ...props
277
+ }) {
278
+ return (props[Platform.OS] ?? props.fallback)();
279
+ }
280
+
281
+ // src/components/GameWebViewNavigationBar/constants.ts
282
+ var RIGHT_MARGIN = 24;
283
+ var IOS_DEFAULT_MARGIN = 20;
284
+
285
+ // src/components/GameWebViewNavigationBar/HeaderRight.tsx
286
+ import { jsx as jsx2 } from "react/jsx-runtime";
287
+ function IOSHeaderRight(props) {
288
+ return /* @__PURE__ */ jsx2(View, { style: styles.ios, ...props });
289
+ }
290
+ function AndroidHeaderRight(props) {
291
+ return /* @__PURE__ */ jsx2(View, { style: styles.android, ...props });
292
+ }
293
+ function HeaderRight(props) {
294
+ return byPlatform({
295
+ ios: () => /* @__PURE__ */ jsx2(IOSHeaderRight, { ...props }),
296
+ android: () => /* @__PURE__ */ jsx2(AndroidHeaderRight, { ...props }),
297
+ fallback: () => /* @__PURE__ */ jsx2(IOSHeaderRight, { ...props })
298
+ });
299
+ }
300
+ var styles = StyleSheet.create({
301
+ ios: {
302
+ marginRight: -IOS_DEFAULT_MARGIN + RIGHT_MARGIN,
303
+ flexDirection: "row"
304
+ },
305
+ android: {
306
+ flexDirection: "row"
307
+ }
308
+ });
309
+
310
+ // src/components/GameWebViewNavigationBar/useSafeAreaTop.ts
311
+ import { useSafeAreaInsets } from "@react-native-bedrock/native/react-native-safe-area-context";
312
+ import { Platform as Platform2 } from "react-native";
313
+ function useSafeAreaTop() {
314
+ const safeAreaInsets = useSafeAreaInsets();
315
+ const hasDynamicIsland = Platform2.OS === "ios" && safeAreaInsets.top > 50;
316
+ const safeAreaTop = hasDynamicIsland ? safeAreaInsets.top - 5 : safeAreaInsets.top;
317
+ return safeAreaTop;
318
+ }
319
+
320
+ // src/components/GameWebViewNavigationBar/GameNavigationBar.tsx
321
+ import { Fragment as Fragment2, jsx as jsx3, jsxs } from "react/jsx-runtime";
322
+ var originXML = '<svg fill="none" height="30" viewBox="0 0 30 30" width="30" xmlns="https://www.w3.org/2000/svg"><rect fill="#031832" fill-opacity=".46" height="30" rx="15" width="30"/><rect height="29.5" rx="14.75" stroke="#d9d9ff" stroke-opacity=".11" stroke-width=".5" width="29.5" x=".25" y=".25"/><path clip-rule="evenodd" d="m16.5119 15.0014 4.7092-4.7092c.0929-.0928.1666-.2031.2169-.32441.0503-.12134.0762-.25141.0762-.38276.0001-.13136-.0258-.26144-.076-.38281s-.1239-.23166-.2167-.32457c-.0929-.09291-.2031-.16662-.3245-.21692-.1213-.05031-.2514-.07622-.3827-.07626-.1314-.00004-.2615.0258-.3828.07603-.1214.05023-.2317.12388-.3246.21673l-4.7092 4.70997-4.71-4.70997c-.1897-.17718-.4408-.27373-.70034-.26927s-.5072.10959-.69069.2932c-.1835.1836-.28848.43132-.29279.69087-.00432.25954.09238.51057.26968.70017l4.71004 4.7092-4.71004 4.7092c-.1392.1401-.23385.3183-.27204.5121-.0382.1939-.01823.3946.05739.5771s.20351.3386.36759.4486.35702.169.55456.1697c.25583 0 .51164-.0975.70664-.2925l4.71-4.71 4.7092 4.71c.0927.093.2029.1668.3243.2172.1213.0504.2514.0763.3828.0763s.2614-.0259.3828-.0763c.1213-.0504.2315-.1242.3243-.2172.0929-.0929.1667-.2032.217-.3246s.0762-.2515.0762-.3829-.0259-.2616-.0762-.383-.1241-.2317-.217-.3245z" fill="#fdfdfe" fill-opacity=".89" fill-rule="evenodd"/></svg>';
323
+ function GameNavigationBar({ onClose }) {
324
+ const safeAreaTop = useSafeAreaTop();
325
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
326
+ /* @__PURE__ */ jsx3(PageNavbar, { preference: { type: "none" } }),
327
+ /* @__PURE__ */ jsx3(
328
+ View2,
329
+ {
330
+ style: {
331
+ width: "100%",
332
+ height: Platform3.OS === "ios" ? 44 : 54,
333
+ flexDirection: "row",
334
+ alignItems: "center",
335
+ justifyContent: "flex-end",
336
+ position: "absolute",
337
+ zIndex: 9999,
338
+ marginTop: safeAreaTop,
339
+ paddingRight: Platform3.OS === "ios" ? 10 : 8
340
+ },
341
+ pointerEvents: "box-none",
342
+ children: /* @__PURE__ */ jsx3(HeaderRight, { children: /* @__PURE__ */ jsx3(
343
+ TouchableOpacity,
344
+ {
345
+ hitSlop: { left: 8, right: 8 },
346
+ style: {
347
+ padding: Platform3.OS === "ios" ? 7 : 9
348
+ },
349
+ onPress: onClose,
350
+ children: /* @__PURE__ */ jsx3(SvgXml, { xml: originXML, width: 30, height: 30 })
351
+ }
352
+ ) })
353
+ }
354
+ )
355
+ ] });
356
+ }
357
+
358
+ // src/components/GameWebView.tsx
359
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
360
+ var GameWebView = forwardRef(function GameWebView2(props, ref) {
361
+ return /* @__PURE__ */ jsxs2(Fragment3, { children: [
362
+ /* @__PURE__ */ jsx4(
363
+ GameNavigationBar,
364
+ {
365
+ onClose: () => {
366
+ closeView();
367
+ }
368
+ }
369
+ ),
370
+ /* @__PURE__ */ jsx4(View3, { style: { flex: 1 }, children: /* @__PURE__ */ jsx4(PlainWebView, { ref, ...props }) })
371
+ ] });
372
+ });
373
+
201
374
  // src/async-bridges.ts
202
375
  var async_bridges_exports = {};
203
376
  __export(async_bridges_exports, {
204
377
  appLogin: () => appLogin,
378
+ checkoutPayment: () => checkoutPayment,
379
+ executePayment: () => executePayment,
205
380
  fetchAlbumPhotos: () => fetchAlbumPhotos,
206
381
  fetchContacts: () => fetchContacts,
207
382
  getClipboardText: () => getClipboardText,
@@ -228,19 +403,37 @@ __export(event_bridges_exports, {
228
403
  });
229
404
 
230
405
  // src/components/WebView.tsx
231
- import { jsx as jsx2 } from "react/jsx-runtime";
232
- function WebView({ local, onMessage, ...props }) {
233
- const uri = useMemo(() => {
234
- if (__DEV__) {
235
- return `http://${local.host}:${local.port}`;
236
- }
237
- const url = new URL(AppsInTossModule.getWebBundleURL({}).url);
238
- const deploymentId = env.getDeploymentId();
239
- if (deploymentId) {
240
- url.searchParams.set("_deploymentId", deploymentId);
241
- }
242
- return url.toString();
243
- }, [local]);
406
+ import { jsx as jsx5 } from "react/jsx-runtime";
407
+ var appsInTossGlobals = getAppsInTossGlobals();
408
+ var WEBVIEW_TYPES = {
409
+ partner: PartnerWebViewScreen,
410
+ external: ExternalWebViewScreen,
411
+ game: GameWebView
412
+ };
413
+ function mergeSchemeQueryParamsInto(url) {
414
+ const baseUrl = new URL(url);
415
+ const schemeUrl = new URL(getSchemeUri());
416
+ baseUrl.pathname = schemeUrl.pathname;
417
+ for (const [key, value] of schemeUrl.searchParams.entries()) {
418
+ baseUrl.searchParams.set(key, value);
419
+ }
420
+ return baseUrl;
421
+ }
422
+ function getWebViewUri(local) {
423
+ if (__DEV__) {
424
+ const devUrl = `http://${local.host}:${local.port}`;
425
+ return mergeSchemeQueryParamsInto(devUrl).toString();
426
+ }
427
+ const { url: rawUrl } = AppsInTossModule.getWebBundleURL({});
428
+ const url = mergeSchemeQueryParamsInto(rawUrl);
429
+ const deploymentId = env.getDeploymentId();
430
+ if (deploymentId) {
431
+ url.searchParams.set("_deploymentId", deploymentId);
432
+ }
433
+ return url.toString();
434
+ }
435
+ function WebView({ type, local, onMessage, ...props }) {
436
+ const uri = useMemo(() => getWebViewUri(local), [local]);
244
437
  const handler = useBridgeHandler({
245
438
  onMessage,
246
439
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -258,14 +451,41 @@ function WebView({ local, onMessage, ...props }) {
258
451
  ...async_bridges_exports
259
452
  }
260
453
  });
261
- return /* @__PURE__ */ jsx2(
262
- OriginalWebView,
454
+ const baseProps = useMemo(() => {
455
+ switch (type) {
456
+ case "partner": {
457
+ return {
458
+ header: {
459
+ ...props.header,
460
+ icon: toIcon(appsInTossGlobals.brandIcon),
461
+ title: appsInTossGlobals.brandDisplayName,
462
+ rightButtons: void 0
463
+ // TODO: onClick 이벤트를 받아야 하기에 런타임에서 설정 받아야 함
464
+ }
465
+ };
466
+ }
467
+ case "external": {
468
+ return {
469
+ header: {
470
+ ...props.header,
471
+ icon: toIcon(appsInTossGlobals.brandIcon),
472
+ title: appsInTossGlobals.brandDisplayName
473
+ }
474
+ };
475
+ }
476
+ default: {
477
+ return {};
478
+ }
479
+ }
480
+ }, [type, props]);
481
+ const BaseWebView = WEBVIEW_TYPES[type];
482
+ return /* @__PURE__ */ jsx5(
483
+ BaseWebView,
263
484
  {
264
485
  ref: handler.ref,
486
+ ...baseProps,
265
487
  ...props,
266
- source: {
267
- uri
268
- },
488
+ source: { uri },
269
489
  sharedCookiesEnabled: true,
270
490
  thirdPartyCookiesEnabled: true,
271
491
  cacheEnabled: false,
@@ -278,12 +498,12 @@ function WebView({ local, onMessage, ...props }) {
278
498
  }
279
499
 
280
500
  // src/hooks/useGeolocation.ts
281
- import { useState, useEffect } from "react";
501
+ import { useState, useEffect as useEffect2 } from "react";
282
502
  import { useVisibility } from "react-native-bedrock";
283
503
  function useGeolocation({ accuracy, distanceInterval, timeInterval }) {
284
504
  const isVisible = useVisibility();
285
505
  const [location, setLocation] = useState(null);
286
- useEffect(() => {
506
+ useEffect2(() => {
287
507
  if (!isVisible) {
288
508
  return;
289
509
  }
@@ -313,6 +533,7 @@ var Accuracy2 = /* @__PURE__ */ ((Accuracy3) => {
313
533
  export {
314
534
  Accuracy2 as Accuracy,
315
535
  AppsInToss,
536
+ TossPay,
316
537
  WebView,
317
538
  appLogin,
318
539
  env,