@ahnseungchan/webviewkit 1.3.0 → 2.1.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.
Files changed (54) hide show
  1. package/README.md +68 -61
  2. package/dist/index.d.mts +454 -0
  3. package/dist/index.d.ts +454 -11
  4. package/dist/index.js +1659 -45
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +1574 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +26 -6
  9. package/dist/bridge/WebViewBridgeProvider.d.ts +0 -18
  10. package/dist/bridge/WebViewBridgeProvider.d.ts.map +0 -1
  11. package/dist/bridge/WebViewBridgeProvider.js +0 -26
  12. package/dist/bridge/client.d.ts +0 -20
  13. package/dist/bridge/client.d.ts.map +0 -1
  14. package/dist/bridge/client.js +0 -48
  15. package/dist/bridge/detect-host.d.ts +0 -4
  16. package/dist/bridge/detect-host.d.ts.map +0 -1
  17. package/dist/bridge/detect-host.js +0 -19
  18. package/dist/bridge/host.d.ts +0 -31
  19. package/dist/bridge/host.d.ts.map +0 -1
  20. package/dist/bridge/host.js +0 -77
  21. package/dist/bridge/index.d.ts +0 -10
  22. package/dist/bridge/index.d.ts.map +0 -1
  23. package/dist/bridge/index.js +0 -33
  24. package/dist/bridge/protocol.d.ts +0 -51
  25. package/dist/bridge/protocol.d.ts.map +0 -1
  26. package/dist/bridge/protocol.js +0 -65
  27. package/dist/bridge/stack-router-bridge.d.ts +0 -17
  28. package/dist/bridge/stack-router-bridge.d.ts.map +0 -1
  29. package/dist/bridge/stack-router-bridge.js +0 -38
  30. package/dist/bridge/transport.d.ts +0 -11
  31. package/dist/bridge/transport.d.ts.map +0 -1
  32. package/dist/bridge/transport.js +0 -65
  33. package/dist/constants.d.ts +0 -3
  34. package/dist/constants.d.ts.map +0 -1
  35. package/dist/constants.js +0 -5
  36. package/dist/history.d.ts +0 -11
  37. package/dist/history.d.ts.map +0 -1
  38. package/dist/history.js +0 -91
  39. package/dist/index.d.ts.map +0 -1
  40. package/dist/stack-dev/stack-dev-roadmap.d.ts +0 -15
  41. package/dist/stack-dev/stack-dev-roadmap.d.ts.map +0 -1
  42. package/dist/stack-dev/stack-dev-roadmap.js +0 -66
  43. package/dist/stack-router/_components/back-router.d.ts +0 -3
  44. package/dist/stack-router/_components/back-router.d.ts.map +0 -1
  45. package/dist/stack-router/_components/back-router.js +0 -39
  46. package/dist/stack-router/_components/header.d.ts +0 -3
  47. package/dist/stack-router/_components/header.d.ts.map +0 -1
  48. package/dist/stack-router/_components/header.js +0 -42
  49. package/dist/stack-router/stack-router-provider.d.ts +0 -27
  50. package/dist/stack-router/stack-router-provider.d.ts.map +0 -1
  51. package/dist/stack-router/stack-router-provider.js +0 -227
  52. package/dist/type.d.ts +0 -37
  53. package/dist/type.d.ts.map +0 -1
  54. package/dist/type.js +0 -14
package/dist/index.js CHANGED
@@ -1,46 +1,1660 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.WebViewBridgeProvider = exports.installStackRouterBridge = exports.getStackRouterBridge = exports.createStackRouterBridge = exports.emitBridgeEnvelope = exports.handleBridgeMessage = exports.installBridgeHost = exports.createWebViewBridgeClient = exports.WebViewBridgeClient = exports.createBridgeTransport = exports.isNativeBridgeHost = exports.detectBridgeHost = exports.serializeBridgeMessage = exports.parseBridgeMessage = exports.isBridgeEnvelope = exports.createBridgeEnvelope = exports.createBridgeId = exports.RN_BRIDGE_HANDLER = exports.FLUTTER_UNIFIED_HANDLER = exports.FLUTTER_LEGACY_STACK_HANDLERS = exports.STACK_BRIDGE_METHODS = exports.BRIDGE_NAMESPACE = exports.BRIDGE_PROTOCOL_VERSION = exports.StackDevRoadmap = exports.StackHeader = exports.BackRouter = exports.useStackRouter = exports.StackRouterProvider = exports.history = exports.HistoryAction = exports.Direction = exports.STACK_TRANSITION_MS = void 0;
7
- var constants_1 = require("./constants");
8
- Object.defineProperty(exports, "STACK_TRANSITION_MS", { enumerable: true, get: function () { return constants_1.STACK_TRANSITION_MS; } });
9
- var type_1 = require("./type");
10
- Object.defineProperty(exports, "Direction", { enumerable: true, get: function () { return type_1.Direction; } });
11
- Object.defineProperty(exports, "HistoryAction", { enumerable: true, get: function () { return type_1.HistoryAction; } });
12
- var history_1 = require("./history");
13
- Object.defineProperty(exports, "history", { enumerable: true, get: function () { return history_1.history; } });
14
- var stack_router_provider_1 = require("./stack-router/stack-router-provider");
15
- Object.defineProperty(exports, "StackRouterProvider", { enumerable: true, get: function () { return __importDefault(stack_router_provider_1).default; } });
16
- Object.defineProperty(exports, "useStackRouter", { enumerable: true, get: function () { return stack_router_provider_1.useStackRouter; } });
17
- var back_router_1 = require("./stack-router/_components/back-router");
18
- Object.defineProperty(exports, "BackRouter", { enumerable: true, get: function () { return __importDefault(back_router_1).default; } });
19
- var header_1 = require("./stack-router/_components/header");
20
- Object.defineProperty(exports, "StackHeader", { enumerable: true, get: function () { return __importDefault(header_1).default; } });
21
- var stack_dev_roadmap_1 = require("./stack-dev/stack-dev-roadmap");
22
- Object.defineProperty(exports, "StackDevRoadmap", { enumerable: true, get: function () { return stack_dev_roadmap_1.StackDevRoadmap; } });
23
- var bridge_1 = require("./bridge");
24
- Object.defineProperty(exports, "BRIDGE_PROTOCOL_VERSION", { enumerable: true, get: function () { return bridge_1.BRIDGE_PROTOCOL_VERSION; } });
25
- Object.defineProperty(exports, "BRIDGE_NAMESPACE", { enumerable: true, get: function () { return bridge_1.BRIDGE_NAMESPACE; } });
26
- Object.defineProperty(exports, "STACK_BRIDGE_METHODS", { enumerable: true, get: function () { return bridge_1.STACK_BRIDGE_METHODS; } });
27
- Object.defineProperty(exports, "FLUTTER_LEGACY_STACK_HANDLERS", { enumerable: true, get: function () { return bridge_1.FLUTTER_LEGACY_STACK_HANDLERS; } });
28
- Object.defineProperty(exports, "FLUTTER_UNIFIED_HANDLER", { enumerable: true, get: function () { return bridge_1.FLUTTER_UNIFIED_HANDLER; } });
29
- Object.defineProperty(exports, "RN_BRIDGE_HANDLER", { enumerable: true, get: function () { return bridge_1.RN_BRIDGE_HANDLER; } });
30
- Object.defineProperty(exports, "createBridgeId", { enumerable: true, get: function () { return bridge_1.createBridgeId; } });
31
- Object.defineProperty(exports, "createBridgeEnvelope", { enumerable: true, get: function () { return bridge_1.createBridgeEnvelope; } });
32
- Object.defineProperty(exports, "isBridgeEnvelope", { enumerable: true, get: function () { return bridge_1.isBridgeEnvelope; } });
33
- Object.defineProperty(exports, "parseBridgeMessage", { enumerable: true, get: function () { return bridge_1.parseBridgeMessage; } });
34
- Object.defineProperty(exports, "serializeBridgeMessage", { enumerable: true, get: function () { return bridge_1.serializeBridgeMessage; } });
35
- Object.defineProperty(exports, "detectBridgeHost", { enumerable: true, get: function () { return bridge_1.detectBridgeHost; } });
36
- Object.defineProperty(exports, "isNativeBridgeHost", { enumerable: true, get: function () { return bridge_1.isNativeBridgeHost; } });
37
- Object.defineProperty(exports, "createBridgeTransport", { enumerable: true, get: function () { return bridge_1.createBridgeTransport; } });
38
- Object.defineProperty(exports, "WebViewBridgeClient", { enumerable: true, get: function () { return bridge_1.WebViewBridgeClient; } });
39
- Object.defineProperty(exports, "createWebViewBridgeClient", { enumerable: true, get: function () { return bridge_1.createWebViewBridgeClient; } });
40
- Object.defineProperty(exports, "installBridgeHost", { enumerable: true, get: function () { return bridge_1.installBridgeHost; } });
41
- Object.defineProperty(exports, "handleBridgeMessage", { enumerable: true, get: function () { return bridge_1.handleBridgeMessage; } });
42
- Object.defineProperty(exports, "emitBridgeEnvelope", { enumerable: true, get: function () { return bridge_1.emitBridgeEnvelope; } });
43
- Object.defineProperty(exports, "createStackRouterBridge", { enumerable: true, get: function () { return bridge_1.createStackRouterBridge; } });
44
- Object.defineProperty(exports, "getStackRouterBridge", { enumerable: true, get: function () { return bridge_1.getStackRouterBridge; } });
45
- Object.defineProperty(exports, "installStackRouterBridge", { enumerable: true, get: function () { return bridge_1.installStackRouterBridge; } });
46
- Object.defineProperty(exports, "WebViewBridgeProvider", { enumerable: true, get: function () { return bridge_1.WebViewBridgeProvider; } });
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BACK_REQUEST_METHOD: () => BACK_REQUEST_METHOD,
34
+ BACK_TIMEOUT_MS: () => BACK_TIMEOUT_MS,
35
+ BRIDGE_ERROR_CODES: () => BRIDGE_ERROR_CODES,
36
+ BRIDGE_NAMESPACE: () => BRIDGE_NAMESPACE,
37
+ BRIDGE_PROTOCOL_VERSION: () => BRIDGE_PROTOCOL_VERSION,
38
+ BRIDGE_RESPONSE_METHOD: () => BRIDGE_RESPONSE_METHOD,
39
+ BRIDGE_TIMEOUT_MS: () => BRIDGE_TIMEOUT_MS,
40
+ BackRouter: () => back_router_default,
41
+ BridgeError: () => BridgeError,
42
+ Direction: () => Direction,
43
+ FLUTTER_LEGACY_STACK_HANDLERS: () => FLUTTER_LEGACY_STACK_HANDLERS,
44
+ FLUTTER_READY_EVENT: () => FLUTTER_READY_EVENT,
45
+ FLUTTER_UNIFIED_HANDLER: () => FLUTTER_UNIFIED_HANDLER,
46
+ HistoryAction: () => HistoryAction,
47
+ RN_BRIDGE_HANDLER: () => RN_BRIDGE_HANDLER,
48
+ STACK_BRIDGE_METHODS: () => STACK_BRIDGE_METHODS,
49
+ STACK_TRANSITION_MS: () => STACK_TRANSITION_MS,
50
+ StackDevRoadmap: () => StackDevRoadmap,
51
+ StackHeader: () => header_default,
52
+ StackRouterProvider: () => stack_router_provider_default,
53
+ WebViewBridgeClient: () => WebViewBridgeClient,
54
+ WebViewBridgeProvider: () => WebViewBridgeProvider,
55
+ assertStackUrl: () => assertStackUrl,
56
+ createBridgeEnvelope: () => createBridgeEnvelope,
57
+ createBridgeId: () => createBridgeId,
58
+ createBridgeResponse: () => createBridgeResponse,
59
+ createBridgeTransport: () => createBridgeTransport,
60
+ createStackRouterBridge: () => createStackRouterBridge,
61
+ createWebViewBridgeClient: () => createWebViewBridgeClient,
62
+ detectBridgeHost: () => detectBridgeHost,
63
+ emitBridgeEnvelope: () => emitBridgeEnvelope,
64
+ findActivity: () => findActivity,
65
+ getStackRouterBridge: () => getStackRouterBridge,
66
+ handleBridgeMessage: () => handleBridgeMessage,
67
+ history: () => history,
68
+ installBridgeHost: () => installBridgeHost,
69
+ installStackRouterBridge: () => installStackRouterBridge,
70
+ isBridgeEnvelope: () => isBridgeEnvelope,
71
+ isNativeBridgeHost: () => isNativeBridgeHost,
72
+ isSafeStackUrl: () => isSafeStackUrl,
73
+ matchPath: () => matchPath,
74
+ parseBridgeMessage: () => parseBridgeMessage,
75
+ parseQuery: () => parseQuery,
76
+ resetStackRouterBridgeCache: () => resetStackRouterBridgeCache,
77
+ serializeBridgeMessage: () => serializeBridgeMessage,
78
+ toStackPath: () => toStackPath,
79
+ useActivity: () => useActivity,
80
+ useParams: () => useParams,
81
+ useStackRouter: () => useStackRouter,
82
+ waitForBridgeHost: () => waitForBridgeHost
83
+ });
84
+ module.exports = __toCommonJS(index_exports);
85
+
86
+ // src/constants.ts
87
+ var STACK_TRANSITION_MS = 500;
88
+ var TRANSITION_END_GRACE_MS = 50;
89
+ var BACK_TIMEOUT_MS = 1e3;
90
+ var BRIDGE_TIMEOUT_MS = 5e3;
91
+ var BRIDGE_HOST_WAIT_MS = 3e3;
92
+ var BRIDGE_HOST_POLL_MS = 100;
93
+
94
+ // src/bridge/detect-host.ts
95
+ var FLUTTER_READY_EVENT = "flutterInAppWebViewPlatformReady";
96
+ function detectBridgeHost() {
97
+ var _a, _b;
98
+ if (typeof window === "undefined") return "unknown";
99
+ if ((_a = window.ReactNativeWebView) == null ? void 0 : _a.postMessage) {
100
+ return "react-native";
101
+ }
102
+ if ((_b = window.flutter_inappwebview) == null ? void 0 : _b.callHandler) {
103
+ return "flutter";
104
+ }
105
+ return "browser";
106
+ }
107
+ function isNativeBridgeHost(host) {
108
+ return host === "react-native" || host === "flutter";
109
+ }
110
+ function waitForBridgeHost({
111
+ timeoutMs = BRIDGE_HOST_WAIT_MS,
112
+ signal
113
+ } = {}) {
114
+ const host = detectBridgeHost();
115
+ if (isNativeBridgeHost(host) || host === "unknown") {
116
+ return Promise.resolve(host);
117
+ }
118
+ return new Promise((resolve) => {
119
+ const finish = () => {
120
+ clearInterval(poll);
121
+ clearTimeout(timer);
122
+ window.removeEventListener(FLUTTER_READY_EVENT, check);
123
+ signal == null ? void 0 : signal.removeEventListener("abort", finish);
124
+ resolve(detectBridgeHost());
125
+ };
126
+ const check = () => {
127
+ if (isNativeBridgeHost(detectBridgeHost())) finish();
128
+ };
129
+ const poll = setInterval(check, BRIDGE_HOST_POLL_MS);
130
+ const timer = setTimeout(finish, timeoutMs);
131
+ window.addEventListener(FLUTTER_READY_EVENT, check);
132
+ signal == null ? void 0 : signal.addEventListener("abort", finish);
133
+ });
134
+ }
135
+
136
+ // src/bridge/errors.ts
137
+ var BRIDGE_ERROR_CODES = {
138
+ TIMEOUT: "TIMEOUT",
139
+ BRIDGE_UNAVAILABLE: "BRIDGE_UNAVAILABLE",
140
+ INVALID_PAYLOAD: "INVALID_PAYLOAD",
141
+ URL_NOT_ALLOWED: "URL_NOT_ALLOWED",
142
+ UNKNOWN_METHOD: "UNKNOWN_METHOD",
143
+ HANDLER_ERROR: "HANDLER_ERROR"
144
+ };
145
+ var BridgeError = class extends Error {
146
+ constructor(code, message, cause) {
147
+ super(message);
148
+ Object.setPrototypeOf(this, new.target.prototype);
149
+ this.name = "BridgeError";
150
+ this.code = code;
151
+ if (cause !== void 0) {
152
+ this.cause = cause;
153
+ }
154
+ }
155
+ toBody() {
156
+ return { code: this.code, message: this.message };
157
+ }
158
+ };
159
+ function toBridgeError(error, fallbackCode) {
160
+ if (error instanceof BridgeError) return error;
161
+ const message = error instanceof Error ? error.message : String(error);
162
+ return new BridgeError(fallbackCode, message, error);
163
+ }
164
+
165
+ // src/bridge/pending-responses.ts
166
+ var pending = /* @__PURE__ */ new Map();
167
+ function waitForResponse(requestId, timeoutMs) {
168
+ return new Promise((resolve, reject) => {
169
+ const timer = setTimeout(() => {
170
+ pending.delete(requestId);
171
+ reject(
172
+ new BridgeError(
173
+ BRIDGE_ERROR_CODES.TIMEOUT,
174
+ `No response for ${requestId} within ${timeoutMs}ms`
175
+ )
176
+ );
177
+ }, timeoutMs);
178
+ pending.set(requestId, { resolve, reject, timer });
179
+ });
180
+ }
181
+ function settleResponse(envelope) {
182
+ if (!envelope.replyTo) return false;
183
+ const request = pending.get(envelope.replyTo);
184
+ if (!request) return false;
185
+ clearTimeout(request.timer);
186
+ pending.delete(envelope.replyTo);
187
+ if (envelope.error) {
188
+ request.reject(
189
+ new BridgeError(envelope.error.code, envelope.error.message)
190
+ );
191
+ } else {
192
+ request.resolve(envelope);
193
+ }
194
+ return true;
195
+ }
196
+ function cancelResponse(requestId) {
197
+ const request = pending.get(requestId);
198
+ if (!request) return;
199
+ clearTimeout(request.timer);
200
+ pending.delete(requestId);
201
+ }
202
+
203
+ // src/bridge/protocol.ts
204
+ var BRIDGE_PROTOCOL_VERSION = 1;
205
+ var BRIDGE_NAMESPACE = "webviewkit";
206
+ var STACK_BRIDGE_METHODS = {
207
+ PUSH: "stack.push",
208
+ REPLACE: "stack.replace",
209
+ POP: "stack.pop",
210
+ RESET: "stack.reset",
211
+ /** web → native: 웹 스택 깊이 변경 알림 */
212
+ CHANGED: "stack.changed"
213
+ };
214
+ var BACK_REQUEST_METHOD = "back.request";
215
+ var BRIDGE_RESPONSE_METHOD = "bridge.response";
216
+ function createBridgeId() {
217
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
218
+ return crypto.randomUUID();
219
+ }
220
+ return `wv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
221
+ }
222
+ function createBridgeEnvelope(method, payload, id) {
223
+ return {
224
+ v: BRIDGE_PROTOCOL_VERSION,
225
+ ns: BRIDGE_NAMESPACE,
226
+ id: id != null ? id : createBridgeId(),
227
+ method,
228
+ ...payload !== void 0 ? { payload } : {}
229
+ };
230
+ }
231
+ function createBridgeResponse(request, result) {
232
+ return {
233
+ ...createBridgeEnvelope(BRIDGE_RESPONSE_METHOD, result.payload),
234
+ replyTo: request.id,
235
+ ...result.error ? { error: result.error } : {}
236
+ };
237
+ }
238
+ function isBridgeEnvelope(value) {
239
+ if (!value || typeof value !== "object") return false;
240
+ const o = value;
241
+ return o.v === BRIDGE_PROTOCOL_VERSION && o.ns === BRIDGE_NAMESPACE && typeof o.id === "string" && typeof o.method === "string";
242
+ }
243
+ function parseBridgeMessage(raw) {
244
+ try {
245
+ const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
246
+ return isBridgeEnvelope(parsed) ? parsed : null;
247
+ } catch (e) {
248
+ return null;
249
+ }
250
+ }
251
+ function serializeBridgeMessage(msg) {
252
+ return JSON.stringify(msg);
253
+ }
254
+ var FLUTTER_LEGACY_STACK_HANDLERS = {
255
+ push: "stackPush",
256
+ replace: "stackReplace",
257
+ pop: "stackPop",
258
+ reset: "stackReset"
259
+ };
260
+ var FLUTTER_UNIFIED_HANDLER = "webviewkitBridge";
261
+ var RN_BRIDGE_HANDLER = "webviewkitBridge";
262
+
263
+ // src/bridge/transport.ts
264
+ var LEGACY_HANDLER_BY_METHOD = {
265
+ [STACK_BRIDGE_METHODS.PUSH]: FLUTTER_LEGACY_STACK_HANDLERS.push,
266
+ [STACK_BRIDGE_METHODS.REPLACE]: FLUTTER_LEGACY_STACK_HANDLERS.replace,
267
+ [STACK_BRIDGE_METHODS.POP]: FLUTTER_LEGACY_STACK_HANDLERS.pop,
268
+ [STACK_BRIDGE_METHODS.RESET]: FLUTTER_LEGACY_STACK_HANDLERS.reset
269
+ };
270
+ function unavailable(host) {
271
+ throw new Error(`${host} bridge is not available`);
272
+ }
273
+ function createReactNativeTransport() {
274
+ return {
275
+ host: "react-native",
276
+ async send(envelope) {
277
+ var _a;
278
+ try {
279
+ const bridge = (_a = window.ReactNativeWebView) != null ? _a : unavailable("react-native");
280
+ bridge.postMessage(serializeBridgeMessage(envelope));
281
+ return void 0;
282
+ } catch (error) {
283
+ throw toBridgeError(error, BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE);
284
+ }
285
+ }
286
+ };
287
+ }
288
+ function createFlutterTransport(options) {
289
+ const useLegacy = options.flutterLegacyHandlers !== false;
290
+ return {
291
+ host: "flutter",
292
+ async send(envelope) {
293
+ var _a, _b;
294
+ const bridge = window.flutter_inappwebview;
295
+ if (!(bridge == null ? void 0 : bridge.callHandler)) {
296
+ throw toBridgeError(
297
+ new Error("flutter bridge is not available"),
298
+ BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE
299
+ );
300
+ }
301
+ const call = bridge.callHandler.bind(bridge);
302
+ const handler = useLegacy ? LEGACY_HANDLER_BY_METHOD[envelope.method] : null;
303
+ if (!handler) {
304
+ return call(FLUTTER_UNIFIED_HANDLER, serializeBridgeMessage(envelope));
305
+ }
306
+ if (envelope.method === STACK_BRIDGE_METHODS.POP) {
307
+ return call(handler);
308
+ }
309
+ const payload = envelope.payload;
310
+ return call(handler, (_a = payload == null ? void 0 : payload.url) != null ? _a : "", (_b = payload == null ? void 0 : payload.meta) != null ? _b : null);
311
+ }
312
+ };
313
+ }
314
+ var browserTransport = {
315
+ host: "browser",
316
+ async send() {
317
+ return void 0;
318
+ }
319
+ };
320
+ function createBridgeTransport(host = detectBridgeHost(), options = {}) {
321
+ if (host === "react-native") return createReactNativeTransport();
322
+ if (host === "flutter") return createFlutterTransport(options);
323
+ return browserTransport;
324
+ }
325
+
326
+ // src/bridge/url-policy.ts
327
+ function isSafeStackUrl(url) {
328
+ if (url.startsWith("/"))
329
+ return !url.startsWith("//") && !url.startsWith("/\\");
330
+ if (typeof window === "undefined") return false;
331
+ try {
332
+ const parsed = new URL(url);
333
+ return (parsed.protocol === "http:" || parsed.protocol === "https:") && parsed.origin === window.location.origin;
334
+ } catch (e) {
335
+ return false;
336
+ }
337
+ }
338
+ function toStackPath(url) {
339
+ if (url.startsWith("/") || typeof window === "undefined") return url;
340
+ try {
341
+ const parsed = new URL(url);
342
+ if (parsed.origin !== window.location.origin) return url;
343
+ return parsed.pathname + parsed.search + parsed.hash;
344
+ } catch (e) {
345
+ return url;
346
+ }
347
+ }
348
+ function assertStackUrl(payload, allowUrl = isSafeStackUrl) {
349
+ const url = payload == null ? void 0 : payload.url;
350
+ if (typeof url !== "string" || url.trim().length === 0) {
351
+ throw new BridgeError(
352
+ BRIDGE_ERROR_CODES.INVALID_PAYLOAD,
353
+ "payload.url must be a non-empty string"
354
+ );
355
+ }
356
+ if (!allowUrl(url)) {
357
+ throw new BridgeError(
358
+ BRIDGE_ERROR_CODES.URL_NOT_ALLOWED,
359
+ `url is not allowed: ${url}`
360
+ );
361
+ }
362
+ return toStackPath(url);
363
+ }
364
+
365
+ // src/bridge/client.ts
366
+ function withTimeout(promise, timeoutMs, method) {
367
+ let timer;
368
+ const timeout = new Promise((_, reject) => {
369
+ timer = setTimeout(
370
+ () => reject(
371
+ new BridgeError(
372
+ BRIDGE_ERROR_CODES.TIMEOUT,
373
+ `${method} timed out after ${timeoutMs}ms`
374
+ )
375
+ ),
376
+ timeoutMs
377
+ );
378
+ });
379
+ return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
380
+ }
381
+ var WebViewBridgeClient = class {
382
+ constructor(options = {}) {
383
+ var _a, _b, _c, _d;
384
+ this.host = (_b = (_a = options.transport) == null ? void 0 : _a.host) != null ? _b : detectBridgeHost();
385
+ this.transport = (_c = options.transport) != null ? _c : createBridgeTransport(this.host, options);
386
+ this.allowUrl = options.allowUrl;
387
+ this.timeoutMs = (_d = options.timeoutMs) != null ? _d : BRIDGE_TIMEOUT_MS;
388
+ }
389
+ /** 응답을 기다리지 않는 단방향 전송 */
390
+ async send(envelope) {
391
+ return this.transport.send(envelope);
392
+ }
393
+ async request(method, payload, options = {}) {
394
+ var _a;
395
+ const envelope = createBridgeEnvelope(method, payload);
396
+ const timeoutMs = (_a = options.timeoutMs) != null ? _a : this.timeoutMs;
397
+ const waitsForReply = options.expectResponse === true && this.host === "react-native";
398
+ const reply2 = waitsForReply ? waitForResponse(envelope.id, timeoutMs) : null;
399
+ try {
400
+ const sent = await withTimeout(this.send(envelope), timeoutMs, method);
401
+ if (!reply2) return { envelope, result: sent };
402
+ const response = await reply2;
403
+ return { envelope, result: response.payload };
404
+ } catch (error) {
405
+ cancelResponse(envelope.id);
406
+ throw error;
407
+ }
408
+ }
409
+ async stackRequest(method, url, meta, options) {
410
+ const path = assertStackUrl({ url }, this.allowUrl);
411
+ return this.request(method, { url: path, meta }, options);
412
+ }
413
+ stackPush(url, meta = null, options) {
414
+ return this.stackRequest(STACK_BRIDGE_METHODS.PUSH, url, meta, options);
415
+ }
416
+ stackReplace(url, meta = null, options) {
417
+ return this.stackRequest(STACK_BRIDGE_METHODS.REPLACE, url, meta, options);
418
+ }
419
+ stackPop(options) {
420
+ return this.request(STACK_BRIDGE_METHODS.POP, void 0, options);
421
+ }
422
+ async stackReset(url, meta = null, options) {
423
+ const path = assertStackUrl({ url }, this.allowUrl);
424
+ return this.request(
425
+ STACK_BRIDGE_METHODS.RESET,
426
+ { url: path, meta },
427
+ options
428
+ );
429
+ }
430
+ /** web → native 웹 스택 변경 알림 (응답 없음) */
431
+ notifyStackChanged(payload) {
432
+ return this.send(
433
+ createBridgeEnvelope(STACK_BRIDGE_METHODS.CHANGED, payload)
434
+ );
435
+ }
436
+ };
437
+ function createWebViewBridgeClient(options) {
438
+ return new WebViewBridgeClient(options);
439
+ }
440
+
441
+ // src/bridge/stack-router-bridge.ts
442
+ var cachedBridge = null;
443
+ function createStackRouterBridge(options) {
444
+ const host = detectBridgeHost();
445
+ if (!isNativeBridgeHost(host)) return null;
446
+ const client = createWebViewBridgeClient(options);
447
+ return {
448
+ push: (url, meta, requestOptions) => client.stackPush(url, meta != null ? meta : null, requestOptions),
449
+ replace: (url, meta, requestOptions) => client.stackReplace(url, meta != null ? meta : null, requestOptions),
450
+ pop: (requestOptions) => client.stackPop(requestOptions),
451
+ reset: (url, meta, requestOptions) => client.stackReset(url, meta != null ? meta : null, requestOptions)
452
+ };
453
+ }
454
+ function getStackRouterBridge() {
455
+ if (typeof window === "undefined") return null;
456
+ if (window.stackRouterBridge) return window.stackRouterBridge;
457
+ if (!cachedBridge) cachedBridge = createStackRouterBridge();
458
+ return cachedBridge;
459
+ }
460
+ function installStackRouterBridge(options) {
461
+ if (typeof window === "undefined") return null;
462
+ const bridge = createStackRouterBridge(options);
463
+ if (bridge) {
464
+ window.stackRouterBridge = bridge;
465
+ }
466
+ return bridge;
467
+ }
468
+ function resetStackRouterBridgeCache() {
469
+ cachedBridge = null;
470
+ }
471
+
472
+ // src/bridge/host.ts
473
+ var STACK_URL_METHODS = {
474
+ [STACK_BRIDGE_METHODS.PUSH]: "push",
475
+ [STACK_BRIDGE_METHODS.REPLACE]: "replace",
476
+ [STACK_BRIDGE_METHODS.RESET]: "reset"
477
+ };
478
+ async function route(envelope, options) {
479
+ var _a, _b, _c;
480
+ const custom = (_a = options.handlers) == null ? void 0 : _a[envelope.method];
481
+ if (custom) return Boolean(await custom(envelope.payload, envelope));
482
+ if (envelope.method === BACK_REQUEST_METHOD) {
483
+ return Boolean(await ((_b = options.onBackRequest) == null ? void 0 : _b.call(options)));
484
+ }
485
+ const stack = options.stack;
486
+ const urlMethod = STACK_URL_METHODS[envelope.method];
487
+ if (stack && urlMethod) {
488
+ const url = assertStackUrl(envelope.payload, options.allowUrl);
489
+ const meta = (_c = envelope.payload.meta) != null ? _c : null;
490
+ return Boolean(await stack[urlMethod](url, meta));
491
+ }
492
+ if (stack && envelope.method === STACK_BRIDGE_METHODS.POP) {
493
+ return Boolean(await stack.pop());
494
+ }
495
+ throw new BridgeError(
496
+ BRIDGE_ERROR_CODES.UNKNOWN_METHOD,
497
+ `No handler for ${envelope.method}`
498
+ );
499
+ }
500
+ async function reply(request, result, options) {
501
+ var _a, _b;
502
+ const host = detectBridgeHost();
503
+ if (!isNativeBridgeHost(host)) return;
504
+ const response = createBridgeResponse(request, {
505
+ payload: { handled: result.handled },
506
+ error: (_a = result.error) == null ? void 0 : _a.toBody()
507
+ });
508
+ try {
509
+ await createBridgeTransport(host, options.transport).send(response);
510
+ } catch (error) {
511
+ (_b = options.onError) == null ? void 0 : _b.call(
512
+ options,
513
+ toBridgeError(error, BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE),
514
+ response
515
+ );
516
+ }
517
+ }
518
+ async function dispatchEnvelope(envelope, options) {
519
+ var _a, _b;
520
+ if (envelope.method === BRIDGE_RESPONSE_METHOD) {
521
+ return settleResponse(envelope);
522
+ }
523
+ (_a = options.onMessage) == null ? void 0 : _a.call(options, envelope);
524
+ let handled = false;
525
+ let failure;
526
+ try {
527
+ handled = await route(envelope, options);
528
+ } catch (error) {
529
+ failure = toBridgeError(error, BRIDGE_ERROR_CODES.HANDLER_ERROR);
530
+ (_b = options.onError) == null ? void 0 : _b.call(options, failure, envelope);
531
+ }
532
+ if (options.replyToNative || envelope.method === BACK_REQUEST_METHOD) {
533
+ await reply(envelope, { handled, error: failure }, options);
534
+ }
535
+ return handled;
536
+ }
537
+ function handleBridgeMessage(raw, options) {
538
+ const envelope = parseBridgeMessage(raw);
539
+ if (!envelope) return Promise.resolve(false);
540
+ return dispatchEnvelope(envelope, options);
541
+ }
542
+ var isDev = () => {
543
+ var _a;
544
+ return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.NODE_ENV) !== "production";
545
+ };
546
+ function legacyCall(method, payload, options) {
547
+ return dispatchEnvelope(createBridgeEnvelope(method, payload), {
548
+ ...options,
549
+ replyToNative: false
550
+ });
551
+ }
552
+ function installBridgeHost(options) {
553
+ if (typeof window === "undefined") {
554
+ return () => void 0;
555
+ }
556
+ const installed = {};
557
+ const target = window;
558
+ const install = (key, value) => {
559
+ if (isDev() && target[key] !== void 0) {
560
+ console.warn(`[webviewkit] window.${key} is being overwritten`);
561
+ }
562
+ target[key] = value;
563
+ installed[key] = value;
564
+ };
565
+ install("webviewkitBridge", {
566
+ postMessage: (raw) => {
567
+ void handleBridgeMessage(raw, options);
568
+ }
569
+ });
570
+ if (options.legacyInboundHandlers !== false && options.stack) {
571
+ install(
572
+ "stackPush",
573
+ (url, meta) => legacyCall(STACK_BRIDGE_METHODS.PUSH, { url, meta }, options)
574
+ );
575
+ install(
576
+ "stackReplace",
577
+ (url, meta) => legacyCall(STACK_BRIDGE_METHODS.REPLACE, { url, meta }, options)
578
+ );
579
+ install(
580
+ "stackPop",
581
+ () => legacyCall(STACK_BRIDGE_METHODS.POP, void 0, options)
582
+ );
583
+ install(
584
+ "stackReset",
585
+ (url, meta) => legacyCall(STACK_BRIDGE_METHODS.RESET, { url, meta }, options)
586
+ );
587
+ }
588
+ const outbound = options.exposeStackRouterBridge === true ? createStackRouterBridge(options.transport) : options.exposeStackRouterBridge || null;
589
+ if (outbound) install("stackRouterBridge", outbound);
590
+ return () => {
591
+ Object.keys(installed).forEach((key) => {
592
+ if (target[key] === installed[key]) delete target[key];
593
+ });
594
+ };
595
+ }
596
+ function emitBridgeEnvelope(method, payload) {
597
+ return createBridgeEnvelope(method, payload);
598
+ }
599
+
600
+ // src/bridge/WebViewBridgeProvider.tsx
601
+ var import_react = require("react");
602
+ var import_jsx_runtime = require("@emotion/react/jsx-runtime");
603
+ function WebViewBridgeProvider({
604
+ children = null,
605
+ stack,
606
+ transport,
607
+ enableOutboundBridge = true,
608
+ hostOptions
609
+ }) {
610
+ const latest = (0, import_react.useRef)({ stack, transport, hostOptions });
611
+ latest.current = { stack, transport, hostOptions };
612
+ const hasStack = Boolean(stack);
613
+ (0, import_react.useEffect)(() => {
614
+ const call = (key) => (...args) => {
615
+ var _a;
616
+ const handler = (_a = latest.current.stack) == null ? void 0 : _a[key];
617
+ return handler ? handler(...args) : false;
618
+ };
619
+ const options = latest.current.hostOptions;
620
+ const cleanups = [];
621
+ cleanups.push(
622
+ installBridgeHost({
623
+ ...options,
624
+ onMessage: (envelope) => {
625
+ var _a, _b;
626
+ return (_b = (_a = latest.current.hostOptions) == null ? void 0 : _a.onMessage) == null ? void 0 : _b.call(_a, envelope);
627
+ },
628
+ onError: (error, envelope) => {
629
+ var _a, _b;
630
+ return (_b = (_a = latest.current.hostOptions) == null ? void 0 : _a.onError) == null ? void 0 : _b.call(_a, error, envelope);
631
+ },
632
+ onBackRequest: () => {
633
+ var _a, _b, _c;
634
+ return (_c = (_b = (_a = latest.current.hostOptions) == null ? void 0 : _a.onBackRequest) == null ? void 0 : _b.call(_a)) != null ? _c : false;
635
+ },
636
+ stack: hasStack ? {
637
+ push: call("push"),
638
+ replace: call("replace"),
639
+ pop: call("pop"),
640
+ reset: call("reset")
641
+ } : void 0,
642
+ legacyInboundHandlers: hasStack
643
+ })
644
+ );
645
+ const abort = new AbortController();
646
+ if (enableOutboundBridge) {
647
+ void waitForBridgeHost({ signal: abort.signal }).then(() => {
648
+ if (abort.signal.aborted) return;
649
+ const outbound = createStackRouterBridge(latest.current.transport);
650
+ if (!outbound) return;
651
+ window.stackRouterBridge = outbound;
652
+ cleanups.push(() => {
653
+ if (window.stackRouterBridge === outbound)
654
+ delete window.stackRouterBridge;
655
+ });
656
+ });
657
+ }
658
+ return () => {
659
+ abort.abort();
660
+ cleanups.forEach((cleanup) => cleanup());
661
+ };
662
+ }, [enableOutboundBridge, hasStack]);
663
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
664
+ }
665
+
666
+ // src/type.ts
667
+ var Direction = /* @__PURE__ */ ((Direction2) => {
668
+ Direction2["FORWARD"] = "forward";
669
+ Direction2["BACKWARD"] = "backward";
670
+ return Direction2;
671
+ })(Direction || {});
672
+ var HistoryAction = /* @__PURE__ */ ((HistoryAction2) => {
673
+ HistoryAction2["PUSH"] = "PUSH";
674
+ HistoryAction2["POP"] = "POP";
675
+ HistoryAction2["REPLACE"] = "REPLACE";
676
+ return HistoryAction2;
677
+ })(HistoryAction || {});
678
+
679
+ // src/history.ts
680
+ var isBrowser = () => typeof window !== "undefined";
681
+ var listeners = /* @__PURE__ */ new Set();
682
+ var currentPath = () => window.location.pathname + window.location.search;
683
+ var onPopState = (event) => {
684
+ var _a;
685
+ const state = {
686
+ path: currentPath(),
687
+ ...(_a = event.state) != null ? _a : {},
688
+ action: "POP" /* POP */
689
+ };
690
+ listeners.forEach((listener) => listener(state));
691
+ };
692
+ var history = {
693
+ push: (path, state = {}) => {
694
+ if (!isBrowser()) return;
695
+ window.history.pushState(
696
+ { ...state, path, action: "PUSH" /* PUSH */ },
697
+ "",
698
+ path
699
+ );
700
+ },
701
+ replace: (path, state = {}) => {
702
+ if (!isBrowser()) return;
703
+ window.history.replaceState(
704
+ { ...state, path, action: "REPLACE" /* REPLACE */ },
705
+ "",
706
+ path
707
+ );
708
+ },
709
+ /** `history.go(delta)` 후 popstate 가 오면 true, BACK_TIMEOUT_MS 안에 오지 않으면 false */
710
+ travel: (delta) => {
711
+ if (!isBrowser()) return Promise.resolve(false);
712
+ return new Promise((resolve) => {
713
+ const finish = (popped) => {
714
+ window.clearTimeout(timer);
715
+ window.removeEventListener("popstate", onPop);
716
+ resolve(popped);
717
+ };
718
+ const onPop = () => finish(true);
719
+ const timer = window.setTimeout(() => finish(false), BACK_TIMEOUT_MS);
720
+ window.addEventListener("popstate", onPop);
721
+ window.history.go(delta);
722
+ });
723
+ },
724
+ back: () => history.travel(-1),
725
+ forward: () => {
726
+ if (!isBrowser()) return;
727
+ window.history.forward();
728
+ },
729
+ go: (delta) => {
730
+ if (!isBrowser()) return;
731
+ window.history.go(delta);
732
+ },
733
+ getCurrentState: () => {
734
+ if (!isBrowser()) return { path: "/" };
735
+ const state = window.history.state;
736
+ return (state == null ? void 0 : state.path) ? state : { path: currentPath() };
737
+ },
738
+ addListener: (listener) => {
739
+ if (!isBrowser()) return () => false;
740
+ if (listeners.size === 0) {
741
+ window.addEventListener("popstate", onPopState);
742
+ }
743
+ listeners.add(listener);
744
+ return () => {
745
+ const removed = listeners.delete(listener);
746
+ if (listeners.size === 0) {
747
+ window.removeEventListener("popstate", onPopState);
748
+ }
749
+ return removed;
750
+ };
751
+ }
752
+ };
753
+
754
+ // src/stack-dev/stack-dev-roadmap.tsx
755
+ var import_react2 = __toESM(require("react"));
756
+ var import_jsx_runtime2 = require("@emotion/react/jsx-runtime");
757
+ function StackDevRoadmap({
758
+ pages,
759
+ currentPath: currentPath2,
760
+ visible = true
761
+ }) {
762
+ if (!visible || pages.length === 0) return null;
763
+ const depth = pages.length;
764
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
765
+ "div",
766
+ {
767
+ role: "status",
768
+ "aria-live": "polite",
769
+ "aria-label": `WebViewKit stack depth ${depth}`,
770
+ style: {
771
+ position: "fixed",
772
+ bottom: 12,
773
+ right: 12,
774
+ zIndex: 2147483646,
775
+ minWidth: 200,
776
+ maxWidth: 320,
777
+ padding: "10px 12px",
778
+ borderRadius: 10,
779
+ background: "rgba(7, 11, 18, 0.92)",
780
+ border: "1px solid rgba(0, 232, 184, 0.35)",
781
+ color: "#e8eef4",
782
+ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace',
783
+ fontSize: 11,
784
+ lineHeight: 1.45,
785
+ boxShadow: "0 8px 24px rgba(0,0,0,0.35)",
786
+ pointerEvents: "none"
787
+ },
788
+ children: [
789
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", gap: 8 }, children: [
790
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#00e8b8", fontWeight: 700 }, children: "WebViewKit" }),
791
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: "#94a3b8" }, children: [
792
+ "stack \xD7 ",
793
+ depth
794
+ ] })
795
+ ] }),
796
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
797
+ "div",
798
+ {
799
+ style: {
800
+ display: "flex",
801
+ alignItems: "center",
802
+ gap: 0,
803
+ marginTop: 10,
804
+ padding: "4px 0"
805
+ },
806
+ children: pages.map((page, index) => {
807
+ const isCurrent = page.path === currentPath2;
808
+ const isLast = index === pages.length - 1;
809
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.default.Fragment, { children: [
810
+ index > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
811
+ "span",
812
+ {
813
+ style: {
814
+ width: 14,
815
+ height: 2,
816
+ background: isLast ? "linear-gradient(90deg,#334155,#00e8b8)" : "#334155",
817
+ flexShrink: 0
818
+ }
819
+ }
820
+ ),
821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
822
+ "span",
823
+ {
824
+ title: page.path,
825
+ style: {
826
+ width: isCurrent ? 12 : 8,
827
+ height: isCurrent ? 12 : 8,
828
+ borderRadius: "50%",
829
+ flexShrink: 0,
830
+ background: isCurrent ? "#00e8b8" : "#475569",
831
+ boxShadow: isCurrent ? "0 0 10px rgba(0,232,184,0.85)" : "none",
832
+ transition: "all 0.2s ease"
833
+ }
834
+ }
835
+ )
836
+ ] }, `${page.path}-${index}`);
837
+ })
838
+ }
839
+ ),
840
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ol", { style: { margin: "8px 0 0", paddingLeft: 18, color: "#cbd5e1" }, children: pages.map((page, index) => {
841
+ const isCurrent = index === pages.length - 1;
842
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
843
+ "li",
844
+ {
845
+ style: {
846
+ fontWeight: isCurrent ? 600 : 400,
847
+ color: isCurrent ? "#00e8b8" : "#94a3b8"
848
+ },
849
+ children: [
850
+ page.path,
851
+ isCurrent ? " \u2190 top" : ""
852
+ ]
853
+ },
854
+ `${page.path}-${index}`
855
+ );
856
+ }) })
857
+ ]
858
+ }
859
+ );
860
+ }
861
+
862
+ // src/stack-router/_components/back-router.tsx
863
+ var import_styled4 = __toESM(require("@emotion/styled"));
864
+
865
+ // src/stack-router/stack-router-provider.tsx
866
+ var import_styled3 = __toESM(require("@emotion/styled"));
867
+ var import_react9 = require("react");
868
+
869
+ // src/stack-router/_components/header.tsx
870
+ var import_styled = __toESM(require("@emotion/styled"));
871
+ var import_jsx_runtime3 = require("@emotion/react/jsx-runtime");
872
+ var Header = ({ title }) => {
873
+ const { currentPath: currentPath2, canGoBack } = useStackRouter();
874
+ 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 })
877
+ ] });
878
+ };
879
+ var StyledHeader = import_styled.default.header`
880
+ width: 100%;
881
+ height: 64px;
882
+ flex-shrink: 0;
883
+ box-sizing: border-box;
884
+ background-color: var(--wvk-header-bg, #ffffff);
885
+ border-bottom: 1px solid var(--wvk-header-border, #e5e7eb);
886
+ display: flex;
887
+ align-items: center;
888
+ padding: 0 1rem;
889
+ `;
890
+ var StyledTitle = import_styled.default.h1`
891
+ margin: 0;
892
+ font-size: 1.25rem;
893
+ font-weight: 600;
894
+ color: var(--wvk-header-color, #111827);
895
+ `;
896
+ var header_default = Header;
897
+
898
+ // src/stack-router/_components/stack-page.tsx
899
+ var import_react3 = require("@emotion/react");
900
+ var import_styled2 = __toESM(require("@emotion/styled"));
901
+ var import_react4 = require("react");
902
+ var import_jsx_runtime4 = require("@emotion/react/jsx-runtime");
903
+ var IOS_EASING = "cubic-bezier(0.32, 0.72, 0, 1)";
904
+ var FADE_EASING = "ease";
905
+ var PARALLAX_OFFSET = "-30%";
906
+ var coverIn = import_react3.keyframes`
907
+ from { transform: translate3d(100%, 0, 0); }
908
+ to { transform: translate3d(0, 0, 0); }
909
+ `;
910
+ var coverOut = import_react3.keyframes`
911
+ from { transform: translate3d(0, 0, 0); }
912
+ to { transform: translate3d(100%, 0, 0); }
913
+ `;
914
+ var parallaxOut = import_react3.keyframes`
915
+ from { transform: translate3d(0, 0, 0); }
916
+ to { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }
917
+ `;
918
+ var parallaxIn = import_react3.keyframes`
919
+ from { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }
920
+ to { transform: translate3d(0, 0, 0); }
921
+ `;
922
+ var dimIn = import_react3.keyframes`
923
+ from { opacity: 0; }
924
+ to { opacity: 1; }
925
+ `;
926
+ var dimOut = import_react3.keyframes`
927
+ from { opacity: 1; }
928
+ to { opacity: 0; }
929
+ `;
930
+ var fadeIn = import_react3.keyframes`
931
+ from { opacity: 0; }
932
+ to { opacity: 1; }
933
+ `;
934
+ var fadeOut = import_react3.keyframes`
935
+ from { opacity: 1; }
936
+ to { opacity: 0; }
937
+ `;
938
+ var layerOf = (direction, pageState) => direction === "push" === (pageState === "enter") ? "upper" : "lower";
939
+ function slideStyles(direction, pageState, duration) {
940
+ const timing = `${duration}ms ${IOS_EASING} forwards`;
941
+ if (layerOf(direction, pageState) === "upper") {
942
+ return import_react3.css`
943
+ animation: ${direction === "push" ? coverIn : coverOut} ${timing};
944
+ box-shadow: var(--wvk-edge-shadow, -6px 0 24px rgba(0, 0, 0, 0.12));
945
+ `;
946
+ }
947
+ return import_react3.css`
948
+ animation: ${direction === "push" ? parallaxOut : parallaxIn} ${timing};
949
+ &::after {
950
+ content: "";
951
+ /* transform 중인 페이지 기준 fixed = 스크롤과 무관하게 페이지 전체를 덮음 */
952
+ position: fixed;
953
+ inset: 0;
954
+ pointer-events: none;
955
+ background: var(--wvk-dim-color, rgba(0, 0, 0, 0.12));
956
+ animation: ${direction === "push" ? dimIn : dimOut} ${timing};
957
+ }
958
+ `;
959
+ }
960
+ var PageWrapper = import_styled2.default.div`
961
+ position: absolute;
962
+ inset: 0;
963
+ overflow: auto;
964
+ -webkit-overflow-scrolling: touch;
965
+ background: var(--wvk-page-bg, #ffffff);
966
+ z-index: ${({ zIndex }) => zIndex};
967
+ visibility: ${({ pageState }) => pageState === "covered" ? "hidden" : "visible"};
968
+ ${({ pageState, direction, transitionType, duration }) => {
969
+ if (pageState !== "enter" && pageState !== "exit") return "";
970
+ if (transitionType === "none" || duration === 0) return "";
971
+ if (transitionType === "fade") {
972
+ return import_react3.css`
973
+ will-change: opacity;
974
+ animation: ${pageState === "enter" ? fadeIn : fadeOut} ${duration}ms
975
+ ${FADE_EASING} forwards;
976
+ `;
977
+ }
978
+ return import_react3.css`
979
+ will-change: transform;
980
+ ${slideStyles(direction, pageState, duration)}
981
+ `;
982
+ }}
983
+ `;
984
+ function StackPage({
985
+ isTop,
986
+ onAnimationEnd,
987
+ children,
988
+ ...wrapperProps
989
+ }) {
990
+ const ref = (0, import_react4.useRef)(null);
991
+ (0, import_react4.useLayoutEffect)(() => {
992
+ var _a;
993
+ (_a = ref.current) == null ? void 0 : _a.toggleAttribute("inert", !isTop);
994
+ }, [isTop]);
995
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
996
+ PageWrapper,
997
+ {
998
+ ref,
999
+ ...wrapperProps,
1000
+ "data-state": wrapperProps.pageState,
1001
+ "aria-hidden": isTop ? void 0 : true,
1002
+ onAnimationEnd: (event) => {
1003
+ if (event.target === event.currentTarget && !event.pseudoElement) {
1004
+ onAnimationEnd == null ? void 0 : onAnimationEnd();
1005
+ }
1006
+ },
1007
+ children
1008
+ }
1009
+ );
1010
+ }
1011
+
1012
+ // src/stack-router/activity-context.tsx
1013
+ var import_react5 = require("react");
1014
+ var ActivityContext = (0, import_react5.createContext)(null);
1015
+ function useActivity() {
1016
+ const context = (0, import_react5.useContext)(ActivityContext);
1017
+ if (!context) {
1018
+ throw new Error(
1019
+ "useActivity must be used inside a StackRouterProvider page"
1020
+ );
1021
+ }
1022
+ return context;
1023
+ }
1024
+ function useParams() {
1025
+ return useActivity().params;
1026
+ }
1027
+
1028
+ // src/stack-router/stack-reducer.ts
1029
+ var topOf = (entries) => entries[entries.length - 1];
1030
+ function createStackState(entry) {
1031
+ return { entries: [entry], leaving: [], transition: null };
1032
+ }
1033
+ function stackReducer(state, action) {
1034
+ switch (action.type) {
1035
+ case "PUSH": {
1036
+ const previousTop = topOf(state.entries);
1037
+ return {
1038
+ entries: [...state.entries, action.entry],
1039
+ leaving: [],
1040
+ transition: action.animate ? {
1041
+ type: "push",
1042
+ enterKey: action.entry.key,
1043
+ exitKey: previousTop.key
1044
+ } : null
1045
+ };
1046
+ }
1047
+ case "REPLACE":
1048
+ return {
1049
+ ...state,
1050
+ entries: [...state.entries.slice(0, -1), action.entry]
1051
+ };
1052
+ case "POP_TO": {
1053
+ const index = Math.max(0, action.index);
1054
+ if (index >= state.entries.length - 1) return state;
1055
+ const entries = state.entries.slice(0, index + 1);
1056
+ const leaving = state.entries.slice(index + 1);
1057
+ if (!action.animate) {
1058
+ return { entries, leaving: [], transition: null };
1059
+ }
1060
+ return {
1061
+ entries,
1062
+ leaving,
1063
+ transition: {
1064
+ type: "pop",
1065
+ enterKey: topOf(entries).key,
1066
+ exitKeys: leaving.map((entry) => entry.key)
1067
+ }
1068
+ };
1069
+ }
1070
+ case "RESET":
1071
+ return createStackState(action.entry);
1072
+ case "RESTORE":
1073
+ return { entries: action.entries, leaving: [], transition: null };
1074
+ case "END_TRANSITION":
1075
+ if (!state.transition && state.leaving.length === 0) return state;
1076
+ return { ...state, leaving: [], transition: null };
1077
+ default:
1078
+ return state;
1079
+ }
1080
+ }
1081
+ function getRenderedPages(state) {
1082
+ const { entries, leaving, transition } = state;
1083
+ const top = topOf(entries);
1084
+ return [...entries, ...leaving].map((entry) => {
1085
+ const isTop = entry.key === top.key;
1086
+ let pageState = isTop ? "idle" : "covered";
1087
+ if ((transition == null ? void 0 : transition.type) === "push") {
1088
+ if (entry.key === transition.enterKey) pageState = "enter";
1089
+ if (entry.key === transition.exitKey) pageState = "exit";
1090
+ }
1091
+ if ((transition == null ? void 0 : transition.type) === "pop") {
1092
+ if (entry.key === transition.enterKey) pageState = "enter";
1093
+ if (transition.exitKeys.includes(entry.key)) pageState = "exit";
1094
+ }
1095
+ return { entry, pageState, isTop };
1096
+ });
1097
+ }
1098
+
1099
+ // src/stack-router/use-prefers-reduced-motion.ts
1100
+ var import_react6 = require("react");
1101
+ var QUERY = "(prefers-reduced-motion: reduce)";
1102
+ var getMediaQuery = () => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia(QUERY) : null;
1103
+ function usePrefersReducedMotion() {
1104
+ const [reduced, setReduced] = (0, import_react6.useState)(
1105
+ () => {
1106
+ var _a, _b;
1107
+ return (_b = (_a = getMediaQuery()) == null ? void 0 : _a.matches) != null ? _b : false;
1108
+ }
1109
+ );
1110
+ (0, import_react6.useEffect)(() => {
1111
+ var _a;
1112
+ const mediaQuery = getMediaQuery();
1113
+ if (!mediaQuery) return;
1114
+ const onChange = () => setReduced(mediaQuery.matches);
1115
+ (_a = mediaQuery.addEventListener) == null ? void 0 : _a.call(mediaQuery, "change", onChange);
1116
+ return () => {
1117
+ var _a2;
1118
+ return (_a2 = mediaQuery.removeEventListener) == null ? void 0 : _a2.call(mediaQuery, "change", onChange);
1119
+ };
1120
+ }, []);
1121
+ return reduced;
1122
+ }
1123
+
1124
+ // src/stack-router/use-stack-bridge-sync.ts
1125
+ var import_react7 = require("react");
1126
+ function useStackBridgeSync(bridge, router, onBackAtRoot) {
1127
+ const enabled = Boolean(bridge);
1128
+ const options = typeof bridge === "object" ? bridge : {};
1129
+ const latest = (0, import_react7.useRef)({ router, options, onBackAtRoot });
1130
+ latest.current = { router, options, onBackAtRoot };
1131
+ (0, import_react7.useEffect)(() => {
1132
+ if (!enabled) return;
1133
+ return installBridgeHost({
1134
+ allowUrl: latest.current.options.allowUrl,
1135
+ onError: (error, envelope) => {
1136
+ var _a, _b;
1137
+ return (_b = (_a = latest.current.options).onError) == null ? void 0 : _b.call(_a, error, envelope);
1138
+ },
1139
+ stack: {
1140
+ push: (url) => latest.current.router.push(url),
1141
+ replace: (url) => latest.current.router.replace(url),
1142
+ reset: (url) => latest.current.router.reset(url),
1143
+ pop: () => latest.current.router.back()
1144
+ },
1145
+ onBackRequest: () => {
1146
+ var _a;
1147
+ const current = latest.current;
1148
+ if (current.router.canGoBack) return current.router.back();
1149
+ (_a = current.onBackAtRoot) == null ? void 0 : _a.call(current);
1150
+ return false;
1151
+ }
1152
+ });
1153
+ }, [enabled]);
1154
+ const { depth, currentPath: currentPath2 } = router;
1155
+ const emit = enabled && options.emitStackChanged !== false;
1156
+ (0, import_react7.useEffect)(() => {
1157
+ if (!emit || !isNativeBridgeHost(detectBridgeHost())) return;
1158
+ createWebViewBridgeClient().notifyStackChanged({ depth, path: currentPath2 }).catch((error) => {
1159
+ var _a, _b;
1160
+ return (_b = (_a = latest.current.options).onError) == null ? void 0 : _b.call(_a, error);
1161
+ });
1162
+ }, [emit, depth, currentPath2]);
1163
+ }
1164
+
1165
+ // src/stack-router/use-stack-navigation.ts
1166
+ var import_react8 = require("react");
1167
+
1168
+ // src/stack-router/match-path.ts
1169
+ var splitSegments = (pathname) => pathname.split("/").filter((segment) => segment.length > 0);
1170
+ var safeDecode = (value) => {
1171
+ try {
1172
+ return decodeURIComponent(value);
1173
+ } catch (e) {
1174
+ return value;
1175
+ }
1176
+ };
1177
+ function parseQuery(search) {
1178
+ const query = {};
1179
+ new URLSearchParams(search).forEach((value, key) => {
1180
+ query[key] = value;
1181
+ });
1182
+ return query;
1183
+ }
1184
+ function matchPath(pattern, url) {
1185
+ const [withoutHash] = url.split("#");
1186
+ const queryIndex = withoutHash.indexOf("?");
1187
+ const pathname = queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);
1188
+ const search = queryIndex === -1 ? "" : withoutHash.slice(queryIndex);
1189
+ const patternSegments = splitSegments(pattern);
1190
+ const pathSegments = splitSegments(pathname);
1191
+ if (patternSegments.length !== pathSegments.length) return null;
1192
+ const params = {};
1193
+ for (let i = 0; i < patternSegments.length; i += 1) {
1194
+ const expected = patternSegments[i];
1195
+ const actual = pathSegments[i];
1196
+ if (expected.startsWith(":")) {
1197
+ params[expected.slice(1)] = safeDecode(actual);
1198
+ } else if (expected !== actual) {
1199
+ return null;
1200
+ }
1201
+ }
1202
+ return { params, query: parseQuery(search) };
1203
+ }
1204
+ function findActivity(activities, url) {
1205
+ for (const activity of activities) {
1206
+ const match = matchPath(activity.path, url);
1207
+ if (match) return { activity, match };
1208
+ }
1209
+ return null;
1210
+ }
1211
+
1212
+ // src/stack-router/use-stack-navigation.ts
1213
+ var isDev2 = () => {
1214
+ var _a;
1215
+ return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.NODE_ENV) !== "production";
1216
+ };
1217
+ function createEntry(hit, path, data, key = createBridgeId()) {
1218
+ return {
1219
+ key,
1220
+ path,
1221
+ pattern: hit.activity.path,
1222
+ params: hit.match.params,
1223
+ query: hit.match.query,
1224
+ data
1225
+ };
1226
+ }
1227
+ var currentUrl = () => window.location.pathname + window.location.search;
1228
+ function useStackNavigation(options) {
1229
+ const optionsRef = (0, import_react8.useRef)(options);
1230
+ optionsRef.current = options;
1231
+ const [state, dispatch] = (0, import_react8.useReducer)(stackReducer, void 0, () => {
1232
+ const { initialActivity } = options;
1233
+ return createStackState(
1234
+ createEntry(
1235
+ { activity: initialActivity, match: { params: {}, query: {} } },
1236
+ initialActivity.path
1237
+ )
1238
+ );
1239
+ });
1240
+ const stateRef = (0, import_react8.useRef)(state);
1241
+ stateRef.current = state;
1242
+ const busyRef = (0, import_react8.useRef)(false);
1243
+ const resolve = (0, import_react8.useCallback)((path) => {
1244
+ const { activities, initialActivity } = optionsRef.current;
1245
+ return findActivity([...activities, initialActivity], path);
1246
+ }, []);
1247
+ const resolveOrNotify = (0, import_react8.useCallback)(
1248
+ (path) => {
1249
+ var _a, _b;
1250
+ const hit = resolve(path);
1251
+ if (!hit) {
1252
+ if (isDev2()) {
1253
+ console.warn(`[webviewkit] No activity matches "${path}"`);
1254
+ }
1255
+ (_b = (_a = optionsRef.current).onNotFound) == null ? void 0 : _b.call(_a, path);
1256
+ }
1257
+ return hit;
1258
+ },
1259
+ [resolve]
1260
+ );
1261
+ const animate = () => optionsRef.current.duration > 0;
1262
+ const push = (0, import_react8.useCallback)(
1263
+ (path, data) => {
1264
+ if (busyRef.current) return false;
1265
+ const hit = resolveOrNotify(path);
1266
+ if (!hit) return false;
1267
+ const entry = createEntry(hit, path, data);
1268
+ busyRef.current = true;
1269
+ history.push(path, {
1270
+ key: entry.key,
1271
+ index: stateRef.current.entries.length,
1272
+ data
1273
+ });
1274
+ dispatch({ type: "PUSH", entry, animate: animate() });
1275
+ return true;
1276
+ },
1277
+ [resolveOrNotify]
1278
+ );
1279
+ const replace = (0, import_react8.useCallback)(
1280
+ (path, data) => {
1281
+ if (busyRef.current) return false;
1282
+ const hit = resolveOrNotify(path);
1283
+ if (!hit) return false;
1284
+ const entry = createEntry(hit, path, data);
1285
+ history.replace(path, {
1286
+ key: entry.key,
1287
+ index: stateRef.current.entries.length - 1,
1288
+ data
1289
+ });
1290
+ dispatch({ type: "REPLACE", entry });
1291
+ return true;
1292
+ },
1293
+ [resolveOrNotify]
1294
+ );
1295
+ const reset = (0, import_react8.useCallback)(
1296
+ (path, data) => {
1297
+ if (busyRef.current) return false;
1298
+ const hit = resolveOrNotify(path);
1299
+ if (!hit) return false;
1300
+ const entry = createEntry(hit, path, data);
1301
+ history.replace(path, { key: entry.key, index: 0, data });
1302
+ dispatch({ type: "RESET", entry });
1303
+ return true;
1304
+ },
1305
+ [resolveOrNotify]
1306
+ );
1307
+ const pop = (0, import_react8.useCallback)((count = 1) => {
1308
+ var _a, _b;
1309
+ if (busyRef.current) return false;
1310
+ const { entries } = stateRef.current;
1311
+ if (entries.length <= 1) {
1312
+ (_b = (_a = optionsRef.current).onBackAtRoot) == null ? void 0 : _b.call(_a);
1313
+ return false;
1314
+ }
1315
+ const delta = Math.min(Math.max(1, count), entries.length - 1);
1316
+ const targetIndex = entries.length - 1 - delta;
1317
+ busyRef.current = true;
1318
+ dispatch({ type: "POP_TO", index: targetIndex, animate: animate() });
1319
+ void history.travel(-delta);
1320
+ return true;
1321
+ }, []);
1322
+ const back = (0, import_react8.useCallback)(() => pop(1), [pop]);
1323
+ const popTo = (0, import_react8.useCallback)(
1324
+ (path) => {
1325
+ const { entries } = stateRef.current;
1326
+ for (let i = entries.length - 2; i >= 0; i -= 1) {
1327
+ if (entries[i].path === path || entries[i].pattern === path) {
1328
+ return pop(entries.length - 1 - i);
1329
+ }
1330
+ }
1331
+ return false;
1332
+ },
1333
+ [pop]
1334
+ );
1335
+ const endTransition = (0, import_react8.useCallback)(() => {
1336
+ dispatch({ type: "END_TRANSITION" });
1337
+ }, []);
1338
+ (0, import_react8.useEffect)(() => {
1339
+ const onPop = (historyState) => {
1340
+ const { entries } = stateRef.current;
1341
+ const index = historyState.key ? entries.findIndex((entry2) => entry2.key === historyState.key) : -1;
1342
+ if (index !== -1) {
1343
+ if (index < entries.length - 1) {
1344
+ busyRef.current = true;
1345
+ dispatch({ type: "POP_TO", index, animate: animate() });
1346
+ }
1347
+ return;
1348
+ }
1349
+ const hit = resolveOrNotify(historyState.path);
1350
+ if (!hit) {
1351
+ busyRef.current = false;
1352
+ return;
1353
+ }
1354
+ const entry = createEntry(
1355
+ hit,
1356
+ historyState.path,
1357
+ historyState.data,
1358
+ historyState.key
1359
+ );
1360
+ if (typeof historyState.index === "number" && historyState.index === entries.length) {
1361
+ busyRef.current = true;
1362
+ dispatch({ type: "PUSH", entry, animate: animate() });
1363
+ return;
1364
+ }
1365
+ dispatch({ type: "RESET", entry });
1366
+ };
1367
+ const removeListener = history.addListener(onPop);
1368
+ return () => {
1369
+ removeListener();
1370
+ };
1371
+ }, [resolveOrNotify]);
1372
+ const restoredRef = (0, import_react8.useRef)(false);
1373
+ (0, import_react8.useEffect)(() => {
1374
+ if (restoredRef.current) return;
1375
+ restoredRef.current = true;
1376
+ const root = stateRef.current.entries[0];
1377
+ const url = currentUrl();
1378
+ const hit = url === root.path ? null : resolve(url);
1379
+ if (!hit || hit.activity === optionsRef.current.initialActivity) {
1380
+ history.replace(root.path, { key: root.key, index: 0 });
1381
+ return;
1382
+ }
1383
+ const savedData = history.getCurrentState().data;
1384
+ const top = createEntry(hit, url, savedData);
1385
+ if (optionsRef.current.restoreStack === "top-only") {
1386
+ history.replace(url, { key: top.key, index: 0, data: savedData });
1387
+ dispatch({ type: "RESTORE", entries: [top] });
1388
+ return;
1389
+ }
1390
+ history.replace(root.path, { key: root.key, index: 0 });
1391
+ history.push(url, { key: top.key, index: 1, data: savedData });
1392
+ dispatch({ type: "RESTORE", entries: [root, top] });
1393
+ }, [resolve]);
1394
+ (0, import_react8.useEffect)(() => {
1395
+ if (!state.transition) {
1396
+ busyRef.current = false;
1397
+ return;
1398
+ }
1399
+ const timer = setTimeout(
1400
+ endTransition,
1401
+ optionsRef.current.duration + TRANSITION_END_GRACE_MS
1402
+ );
1403
+ return () => clearTimeout(timer);
1404
+ }, [state, endTransition]);
1405
+ return { state, push, replace, reset, back, pop, popTo, endTransition };
1406
+ }
1407
+
1408
+ // src/stack-router/stack-router-provider.tsx
1409
+ var import_jsx_runtime5 = require("@emotion/react/jsx-runtime");
1410
+ var StackRouterContext = (0, import_react9.createContext)(null);
1411
+ var useStackRouter = () => {
1412
+ const context = (0, import_react9.useContext)(StackRouterContext);
1413
+ if (!context) {
1414
+ throw new Error("useStackRouter must be used within a StackRouterProvider");
1415
+ }
1416
+ return context;
1417
+ };
1418
+ var isDevEnv = () => {
1419
+ var _a;
1420
+ return typeof process !== "undefined" && ((_a = process.env) == null ? void 0 : _a.NODE_ENV) === "development";
1421
+ };
1422
+ var StackRouterProvider = ({
1423
+ initialActivity,
1424
+ Activities = [],
1425
+ maxWidth = "600px",
1426
+ isShowHeader = false,
1427
+ enableDevTools,
1428
+ transition = "slide",
1429
+ duration = STACK_TRANSITION_MS,
1430
+ restoreStack = "with-root",
1431
+ safeArea = false,
1432
+ onBackAtRoot,
1433
+ onNotFound,
1434
+ bridge
1435
+ }) => {
1436
+ var _a, _b;
1437
+ const reducedMotion = usePrefersReducedMotion();
1438
+ const effectiveDuration = transition === "none" || reducedMotion ? 0 : duration;
1439
+ const navigation = useStackNavigation({
1440
+ initialActivity,
1441
+ activities: Activities,
1442
+ duration: effectiveDuration,
1443
+ restoreStack,
1444
+ onBackAtRoot,
1445
+ onNotFound
1446
+ });
1447
+ const { state, endTransition } = navigation;
1448
+ const elementFor = (pattern) => {
1449
+ var _a2, _b2;
1450
+ return (_b2 = (_a2 = Activities.find((activity) => activity.path === pattern)) == null ? void 0 : _a2.element) != null ? _b2 : initialActivity.path === pattern ? initialActivity.element : null;
1451
+ };
1452
+ const top = state.entries[state.entries.length - 1];
1453
+ const value = (0, import_react9.useMemo)(
1454
+ () => ({
1455
+ currentPath: top.path,
1456
+ currentState: {
1457
+ path: top.path,
1458
+ data: top.data,
1459
+ key: top.key,
1460
+ index: state.entries.length - 1
1461
+ },
1462
+ depth: state.entries.length,
1463
+ canGoBack: state.entries.length > 1,
1464
+ isTransitioning: state.transition !== null,
1465
+ entries: state.entries,
1466
+ visiblePages: state.entries.map((entry) => ({
1467
+ path: entry.path,
1468
+ element: elementFor(entry.pattern)
1469
+ })),
1470
+ Activities,
1471
+ initialActivity,
1472
+ push: navigation.push,
1473
+ replace: navigation.replace,
1474
+ reset: navigation.reset,
1475
+ back: navigation.back,
1476
+ pop: navigation.pop,
1477
+ popTo: navigation.popTo,
1478
+ forward: () => window.history.forward()
1479
+ }),
1480
+ [state, Activities, initialActivity, navigation]
1481
+ );
1482
+ useStackBridgeSync(bridge, value, onBackAtRoot);
1483
+ const direction = (_b = (_a = state.transition) == null ? void 0 : _a.type) != null ? _b : "push";
1484
+ const pages = getRenderedPages(state);
1485
+ const showDevTools = enableDevTools != null ? enableDevTools : isDevEnv();
1486
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(StackRouterContext.Provider, { value, children: [
1487
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LayoutContainer, { safeArea, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Layout, { maxWidth, "data-testid": "layout", children: [
1488
+ isShowHeader && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(header_default, {}),
1489
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageContainer, { children: pages.map(({ entry, pageState, isTop }, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1490
+ ActivityContext.Provider,
1491
+ {
1492
+ value: {
1493
+ key: entry.key,
1494
+ path: entry.path,
1495
+ pattern: entry.pattern,
1496
+ params: entry.params,
1497
+ query: entry.query,
1498
+ data: entry.data,
1499
+ index,
1500
+ isTop
1501
+ },
1502
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1503
+ StackPage,
1504
+ {
1505
+ pageState,
1506
+ direction,
1507
+ transitionType: transition,
1508
+ duration: effectiveDuration,
1509
+ zIndex: index,
1510
+ isTop,
1511
+ onAnimationEnd: pageState === "enter" ? endTransition : void 0,
1512
+ children: elementFor(entry.pattern)
1513
+ }
1514
+ )
1515
+ },
1516
+ entry.key
1517
+ )) })
1518
+ ] }) }),
1519
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1520
+ StackDevRoadmap,
1521
+ {
1522
+ visible: showDevTools,
1523
+ pages: state.entries.map((entry) => ({ path: entry.path })),
1524
+ currentPath: top.path
1525
+ }
1526
+ )
1527
+ ] });
1528
+ };
1529
+ var stack_router_provider_default = StackRouterProvider;
1530
+ var LayoutContainer = import_styled3.default.div`
1531
+ width: 100%;
1532
+ height: 100vh;
1533
+ height: 100dvh;
1534
+ display: flex;
1535
+ justify-content: center;
1536
+ background: var(--wvk-page-bg, #ffffff);
1537
+ box-sizing: border-box;
1538
+ ${({ safeArea }) => safeArea ? `padding: env(safe-area-inset-top) env(safe-area-inset-right)
1539
+ env(safe-area-inset-bottom) env(safe-area-inset-left);` : ""}
1540
+ `;
1541
+ var Layout = import_styled3.default.div`
1542
+ width: 100%;
1543
+ max-width: ${({ maxWidth }) => maxWidth};
1544
+ height: 100%;
1545
+ display: flex;
1546
+ flex-direction: column;
1547
+ position: relative;
1548
+ overflow: hidden;
1549
+ `;
1550
+ var PageContainer = import_styled3.default.div`
1551
+ position: relative;
1552
+ flex: 1;
1553
+ width: 100%;
1554
+ overflow: hidden;
1555
+ `;
1556
+
1557
+ // src/stack-router/_components/back-router.tsx
1558
+ var import_jsx_runtime6 = require("@emotion/react/jsx-runtime");
1559
+ var BackRouter = ({ label = "\uB4A4\uB85C \uAC00\uAE30" }) => {
1560
+ const { back } = useStackRouter();
1561
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackButton, { type: "button", "aria-label": label, onClick: () => back(), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BackIcon, {}) });
1562
+ };
1563
+ var back_router_default = BackRouter;
1564
+ var BackButton = import_styled4.default.button`
1565
+ display: flex;
1566
+ align-items: center;
1567
+ justify-content: center;
1568
+ width: 40px;
1569
+ height: 40px;
1570
+ border: none;
1571
+ background: none;
1572
+ cursor: pointer;
1573
+ padding: 8px;
1574
+ border-radius: 50%;
1575
+ transition: all 0.2s;
1576
+ color: var(--wvk-back-color, #000000);
1577
+
1578
+ &:hover {
1579
+ color: var(--wvk-back-hover-color, #666666);
1580
+ }
1581
+
1582
+ &:active {
1583
+ color: var(--wvk-back-active-color, #999999);
1584
+ }
1585
+ `;
1586
+ var BackIcon = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1587
+ "svg",
1588
+ {
1589
+ width: "32",
1590
+ height: "32",
1591
+ viewBox: "0 0 24 24",
1592
+ fill: "none",
1593
+ xmlns: "http://www.w3.org/2000/svg",
1594
+ "aria-hidden": "true",
1595
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1596
+ "path",
1597
+ {
1598
+ d: "M12 20L4 12L12 4",
1599
+ stroke: "currentColor",
1600
+ strokeWidth: "2.5",
1601
+ strokeLinecap: "round",
1602
+ strokeLinejoin: "round"
1603
+ }
1604
+ )
1605
+ }
1606
+ );
1607
+ // Annotate the CommonJS export names for ESM import in node:
1608
+ 0 && (module.exports = {
1609
+ BACK_REQUEST_METHOD,
1610
+ BACK_TIMEOUT_MS,
1611
+ BRIDGE_ERROR_CODES,
1612
+ BRIDGE_NAMESPACE,
1613
+ BRIDGE_PROTOCOL_VERSION,
1614
+ BRIDGE_RESPONSE_METHOD,
1615
+ BRIDGE_TIMEOUT_MS,
1616
+ BackRouter,
1617
+ BridgeError,
1618
+ Direction,
1619
+ FLUTTER_LEGACY_STACK_HANDLERS,
1620
+ FLUTTER_READY_EVENT,
1621
+ FLUTTER_UNIFIED_HANDLER,
1622
+ HistoryAction,
1623
+ RN_BRIDGE_HANDLER,
1624
+ STACK_BRIDGE_METHODS,
1625
+ STACK_TRANSITION_MS,
1626
+ StackDevRoadmap,
1627
+ StackHeader,
1628
+ StackRouterProvider,
1629
+ WebViewBridgeClient,
1630
+ WebViewBridgeProvider,
1631
+ assertStackUrl,
1632
+ createBridgeEnvelope,
1633
+ createBridgeId,
1634
+ createBridgeResponse,
1635
+ createBridgeTransport,
1636
+ createStackRouterBridge,
1637
+ createWebViewBridgeClient,
1638
+ detectBridgeHost,
1639
+ emitBridgeEnvelope,
1640
+ findActivity,
1641
+ getStackRouterBridge,
1642
+ handleBridgeMessage,
1643
+ history,
1644
+ installBridgeHost,
1645
+ installStackRouterBridge,
1646
+ isBridgeEnvelope,
1647
+ isNativeBridgeHost,
1648
+ isSafeStackUrl,
1649
+ matchPath,
1650
+ parseBridgeMessage,
1651
+ parseQuery,
1652
+ resetStackRouterBridgeCache,
1653
+ serializeBridgeMessage,
1654
+ toStackPath,
1655
+ useActivity,
1656
+ useParams,
1657
+ useStackRouter,
1658
+ waitForBridgeHost
1659
+ });
1660
+ //# sourceMappingURL=index.js.map