@smoregg/sdk 0.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 (137) hide show
  1. package/dist/cjs/components/DirectionPad.cjs +68 -0
  2. package/dist/cjs/components/DirectionPad.cjs.map +1 -0
  3. package/dist/cjs/components/DirectionPad.module.css.cjs +12 -0
  4. package/dist/cjs/components/DirectionPad.module.css.cjs.map +1 -0
  5. package/dist/cjs/components/HoldButton.cjs +57 -0
  6. package/dist/cjs/components/HoldButton.cjs.map +1 -0
  7. package/dist/cjs/components/HoldButton.module.css.cjs +12 -0
  8. package/dist/cjs/components/HoldButton.module.css.cjs.map +1 -0
  9. package/dist/cjs/components/SwipeArea.cjs +58 -0
  10. package/dist/cjs/components/SwipeArea.cjs.map +1 -0
  11. package/dist/cjs/components/SwipeArea.module.css.cjs +12 -0
  12. package/dist/cjs/components/SwipeArea.module.css.cjs.map +1 -0
  13. package/dist/cjs/components/TapButton.cjs +58 -0
  14. package/dist/cjs/components/TapButton.cjs.map +1 -0
  15. package/dist/cjs/components/TapButton.module.css.cjs +12 -0
  16. package/dist/cjs/components/TapButton.module.css.cjs.map +1 -0
  17. package/dist/cjs/context/RoomProvider.cjs +118 -0
  18. package/dist/cjs/context/RoomProvider.cjs.map +1 -0
  19. package/dist/cjs/hooks/useExternalGames.cjs +49 -0
  20. package/dist/cjs/hooks/useExternalGames.cjs.map +1 -0
  21. package/dist/cjs/hooks/useGameHost.cjs +135 -0
  22. package/dist/cjs/hooks/useGameHost.cjs.map +1 -0
  23. package/dist/cjs/hooks/useGamePlayer.cjs +75 -0
  24. package/dist/cjs/hooks/useGamePlayer.cjs.map +1 -0
  25. package/dist/cjs/iframe/index.cjs +508 -0
  26. package/dist/cjs/iframe/index.cjs.map +1 -0
  27. package/dist/cjs/index.cjs +32 -0
  28. package/dist/cjs/index.cjs.map +1 -0
  29. package/dist/cjs/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs +33 -0
  30. package/dist/cjs/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs.map +1 -0
  31. package/dist/cjs/server/index.cjs +45 -0
  32. package/dist/cjs/server/index.cjs.map +1 -0
  33. package/dist/cjs/transport/DirectTransport.cjs +23 -0
  34. package/dist/cjs/transport/DirectTransport.cjs.map +1 -0
  35. package/dist/cjs/transport/PostMessageTransport.cjs +72 -0
  36. package/dist/cjs/transport/PostMessageTransport.cjs.map +1 -0
  37. package/dist/cjs/transport/protocol.cjs +10 -0
  38. package/dist/cjs/transport/protocol.cjs.map +1 -0
  39. package/dist/esm/components/DirectionPad.js +66 -0
  40. package/dist/esm/components/DirectionPad.js.map +1 -0
  41. package/dist/esm/components/DirectionPad.module.css.js +8 -0
  42. package/dist/esm/components/DirectionPad.module.css.js.map +1 -0
  43. package/dist/esm/components/HoldButton.js +55 -0
  44. package/dist/esm/components/HoldButton.js.map +1 -0
  45. package/dist/esm/components/HoldButton.module.css.js +8 -0
  46. package/dist/esm/components/HoldButton.module.css.js.map +1 -0
  47. package/dist/esm/components/SwipeArea.js +56 -0
  48. package/dist/esm/components/SwipeArea.js.map +1 -0
  49. package/dist/esm/components/SwipeArea.module.css.js +8 -0
  50. package/dist/esm/components/SwipeArea.module.css.js.map +1 -0
  51. package/dist/esm/components/TapButton.js +56 -0
  52. package/dist/esm/components/TapButton.js.map +1 -0
  53. package/dist/esm/components/TapButton.module.css.js +8 -0
  54. package/dist/esm/components/TapButton.module.css.js.map +1 -0
  55. package/dist/esm/context/RoomProvider.js +109 -0
  56. package/dist/esm/context/RoomProvider.js.map +1 -0
  57. package/dist/esm/hooks/useExternalGames.js +47 -0
  58. package/dist/esm/hooks/useExternalGames.js.map +1 -0
  59. package/dist/esm/hooks/useGameHost.js +133 -0
  60. package/dist/esm/hooks/useGameHost.js.map +1 -0
  61. package/dist/esm/hooks/useGamePlayer.js +73 -0
  62. package/dist/esm/hooks/useGamePlayer.js.map +1 -0
  63. package/dist/esm/iframe/index.js +502 -0
  64. package/dist/esm/iframe/index.js.map +1 -0
  65. package/dist/esm/index.js +11 -0
  66. package/dist/esm/index.js.map +1 -0
  67. package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js +29 -0
  68. package/dist/esm/node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js.map +1 -0
  69. package/dist/esm/server/index.js +43 -0
  70. package/dist/esm/server/index.js.map +1 -0
  71. package/dist/esm/transport/DirectTransport.js +21 -0
  72. package/dist/esm/transport/DirectTransport.js.map +1 -0
  73. package/dist/esm/transport/PostMessageTransport.js +70 -0
  74. package/dist/esm/transport/PostMessageTransport.js.map +1 -0
  75. package/dist/esm/transport/protocol.js +7 -0
  76. package/dist/esm/transport/protocol.js.map +1 -0
  77. package/dist/types/components/DirectionPad.d.ts +21 -0
  78. package/dist/types/components/DirectionPad.d.ts.map +1 -0
  79. package/dist/types/components/HoldButton.d.ts +22 -0
  80. package/dist/types/components/HoldButton.d.ts.map +1 -0
  81. package/dist/types/components/IframeGameBridge.d.ts +40 -0
  82. package/dist/types/components/IframeGameBridge.d.ts.map +1 -0
  83. package/dist/types/components/SwipeArea.d.ts +19 -0
  84. package/dist/types/components/SwipeArea.d.ts.map +1 -0
  85. package/dist/types/components/TapButton.d.ts +19 -0
  86. package/dist/types/components/TapButton.d.ts.map +1 -0
  87. package/dist/types/components/index.d.ts +8 -0
  88. package/dist/types/components/index.d.ts.map +1 -0
  89. package/dist/types/context/RoomProvider.d.ts +69 -0
  90. package/dist/types/context/RoomProvider.d.ts.map +1 -0
  91. package/dist/types/context/index.d.ts +3 -0
  92. package/dist/types/context/index.d.ts.map +1 -0
  93. package/dist/types/dev/DevSimulator.d.ts +31 -0
  94. package/dist/types/dev/DevSimulator.d.ts.map +1 -0
  95. package/dist/types/dev/index.d.ts +2 -0
  96. package/dist/types/dev/index.d.ts.map +1 -0
  97. package/dist/types/hooks/index.d.ts +4 -0
  98. package/dist/types/hooks/index.d.ts.map +1 -0
  99. package/dist/types/hooks/useExternalGames.d.ts +32 -0
  100. package/dist/types/hooks/useExternalGames.d.ts.map +1 -0
  101. package/dist/types/hooks/useGameHost.d.ts +40 -0
  102. package/dist/types/hooks/useGameHost.d.ts.map +1 -0
  103. package/dist/types/hooks/useGamePlayer.d.ts +17 -0
  104. package/dist/types/hooks/useGamePlayer.d.ts.map +1 -0
  105. package/dist/types/iframe/IframeRoomProvider.d.ts +31 -0
  106. package/dist/types/iframe/IframeRoomProvider.d.ts.map +1 -0
  107. package/dist/types/iframe/index.d.ts +18 -0
  108. package/dist/types/iframe/index.d.ts.map +1 -0
  109. package/dist/types/iframe/vanilla.d.ts +40 -0
  110. package/dist/types/iframe/vanilla.d.ts.map +1 -0
  111. package/dist/types/index.d.ts +34 -0
  112. package/dist/types/index.d.ts.map +1 -0
  113. package/dist/types/server/createGameRelay.d.ts +26 -0
  114. package/dist/types/server/createGameRelay.d.ts.map +1 -0
  115. package/dist/types/server/index.d.ts +3 -0
  116. package/dist/types/server/index.d.ts.map +1 -0
  117. package/dist/types/transport/DirectTransport.d.ts +14 -0
  118. package/dist/types/transport/DirectTransport.d.ts.map +1 -0
  119. package/dist/types/transport/PostMessageTransport.d.ts +20 -0
  120. package/dist/types/transport/PostMessageTransport.d.ts.map +1 -0
  121. package/dist/types/transport/index.d.ts +6 -0
  122. package/dist/types/transport/index.d.ts.map +1 -0
  123. package/dist/types/transport/protocol.d.ts +50 -0
  124. package/dist/types/transport/protocol.d.ts.map +1 -0
  125. package/dist/types/transport/types.d.ts +14 -0
  126. package/dist/types/transport/types.d.ts.map +1 -0
  127. package/dist/types/types.d.ts +33 -0
  128. package/dist/types/types.d.ts.map +1 -0
  129. package/dist/umd/smore-sdk-iframe.umd.js +511 -0
  130. package/dist/umd/smore-sdk-iframe.umd.js.map +1 -0
  131. package/dist/umd/smore-sdk-iframe.umd.min.js +2 -0
  132. package/dist/umd/smore-sdk-iframe.umd.min.js.map +1 -0
  133. package/dist/umd/smore-sdk.umd.js +709 -0
  134. package/dist/umd/smore-sdk.umd.js.map +1 -0
  135. package/dist/umd/smore-sdk.umd.min.js +2 -0
  136. package/dist/umd/smore-sdk.umd.min.js.map +1 -0
  137. package/package.json +87 -0
@@ -0,0 +1,709 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react/jsx-runtime'), require('react')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'react/jsx-runtime', 'react'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.SmoreSDK = {}, global.ReactJSXRuntime, global.React));
5
+ })(this, (function (exports, jsxRuntime, react) { 'use strict';
6
+
7
+ function styleInject(css, ref) {
8
+ if ( ref === void 0 ) ref = {};
9
+ var insertAt = ref.insertAt;
10
+
11
+ if (!css || typeof document === 'undefined') { return; }
12
+
13
+ var head = document.head || document.getElementsByTagName('head')[0];
14
+ var style = document.createElement('style');
15
+ style.type = 'text/css';
16
+
17
+ if (insertAt === 'top') {
18
+ if (head.firstChild) {
19
+ head.insertBefore(style, head.firstChild);
20
+ } else {
21
+ head.appendChild(style);
22
+ }
23
+ } else {
24
+ head.appendChild(style);
25
+ }
26
+
27
+ if (style.styleSheet) {
28
+ style.styleSheet.cssText = css;
29
+ } else {
30
+ style.appendChild(document.createTextNode(css));
31
+ }
32
+ }
33
+
34
+ var css_248z$3 = ".TapButton-module_tapButton__dqJr9{-webkit-tap-highlight-color:transparent;align-items:center;background:var(--color-primary,#6366f1);border:none;border-radius:16px;color:#fff;cursor:pointer;display:flex;font-size:18px;font-weight:700;justify-content:center;min-height:80px;min-width:80px;padding:16px 24px;touch-action:manipulation;transition:transform .1s ease,background .1s ease;user-select:none;-webkit-user-select:none}.TapButton-module_pressed__Z2nfR,.TapButton-module_tapButton__dqJr9:active{background:var(--color-primary-dark,#4f46e5);transform:scale(.95)}.TapButton-module_disabled__3bR6q{cursor:not-allowed;opacity:.5}.TapButton-module_disabled__3bR6q.TapButton-module_pressed__Z2nfR,.TapButton-module_disabled__3bR6q:active{background:var(--color-primary,#6366f1);transform:none}";
35
+ var styles$3 = {"tapButton":"TapButton-module_tapButton__dqJr9","pressed":"TapButton-module_pressed__Z2nfR","disabled":"TapButton-module_disabled__3bR6q"};
36
+ styleInject(css_248z$3);
37
+
38
+ function TapButton({
39
+ onTap,
40
+ children,
41
+ className,
42
+ disabled = false
43
+ }) {
44
+ const isPressed = react.useRef(false);
45
+ const buttonRef = react.useRef(null);
46
+ const handleTouchStart = react.useCallback((e) => {
47
+ if (disabled) return;
48
+ e.preventDefault();
49
+ isPressed.current = true;
50
+ buttonRef.current?.classList.add(styles$3.pressed);
51
+ if (navigator.vibrate) {
52
+ navigator.vibrate(10);
53
+ }
54
+ onTap();
55
+ }, [onTap, disabled]);
56
+ const handleTouchEnd = react.useCallback((e) => {
57
+ e.preventDefault();
58
+ isPressed.current = false;
59
+ buttonRef.current?.classList.remove(styles$3.pressed);
60
+ }, []);
61
+ const handleMouseDown = react.useCallback(() => {
62
+ if (disabled) return;
63
+ isPressed.current = true;
64
+ buttonRef.current?.classList.add(styles$3.pressed);
65
+ onTap();
66
+ }, [onTap, disabled]);
67
+ const handleMouseUp = react.useCallback(() => {
68
+ isPressed.current = false;
69
+ buttonRef.current?.classList.remove(styles$3.pressed);
70
+ }, []);
71
+ return /* @__PURE__ */ jsxRuntime.jsx(
72
+ "button",
73
+ {
74
+ ref: buttonRef,
75
+ className: `${styles$3.tapButton} ${className || ""} ${disabled ? styles$3.disabled : ""}`,
76
+ onTouchStart: handleTouchStart,
77
+ onTouchEnd: handleTouchEnd,
78
+ onTouchCancel: handleTouchEnd,
79
+ onMouseDown: handleMouseDown,
80
+ onMouseUp: handleMouseUp,
81
+ onMouseLeave: handleMouseUp,
82
+ disabled,
83
+ children
84
+ }
85
+ );
86
+ }
87
+
88
+ var css_248z$2 = ".HoldButton-module_holdButton__tu4mi{-webkit-tap-highlight-color:transparent;align-items:center;background:var(--color-secondary,#f59e0b);border:none;border-radius:16px;color:#fff;cursor:pointer;display:flex;font-size:18px;font-weight:700;justify-content:center;min-height:80px;min-width:80px;padding:16px 24px;touch-action:manipulation;transition:transform .1s ease,background .1s ease;user-select:none;-webkit-user-select:none}.HoldButton-module_holdButton__tu4mi:active,.HoldButton-module_pressed__JWIRG{background:var(--color-secondary-dark,#d97706);transform:scale(.95)}.HoldButton-module_disabled__4QwwT{cursor:not-allowed;opacity:.5}.HoldButton-module_disabled__4QwwT.HoldButton-module_pressed__JWIRG,.HoldButton-module_disabled__4QwwT:active{background:var(--color-secondary,#f59e0b);transform:none}";
89
+ var styles$2 = {"holdButton":"HoldButton-module_holdButton__tu4mi","pressed":"HoldButton-module_pressed__JWIRG","disabled":"HoldButton-module_disabled__4QwwT"};
90
+ styleInject(css_248z$2);
91
+
92
+ function HoldButton({
93
+ onHoldStart,
94
+ onHoldEnd,
95
+ children,
96
+ className,
97
+ disabled = false
98
+ }) {
99
+ const isHolding = react.useRef(false);
100
+ const buttonRef = react.useRef(null);
101
+ const startHold = react.useCallback(() => {
102
+ if (disabled || isHolding.current) return;
103
+ isHolding.current = true;
104
+ buttonRef.current?.classList.add(styles$2.pressed);
105
+ if (navigator.vibrate) {
106
+ navigator.vibrate(10);
107
+ }
108
+ onHoldStart();
109
+ }, [onHoldStart, disabled]);
110
+ const endHold = react.useCallback(() => {
111
+ if (!isHolding.current) return;
112
+ isHolding.current = false;
113
+ buttonRef.current?.classList.remove(styles$2.pressed);
114
+ onHoldEnd();
115
+ }, [onHoldEnd]);
116
+ const handleTouchStart = react.useCallback((e) => {
117
+ e.preventDefault();
118
+ startHold();
119
+ }, [startHold]);
120
+ const handleTouchEnd = react.useCallback((e) => {
121
+ e.preventDefault();
122
+ endHold();
123
+ }, [endHold]);
124
+ return /* @__PURE__ */ jsxRuntime.jsx(
125
+ "button",
126
+ {
127
+ ref: buttonRef,
128
+ className: `${styles$2.holdButton} ${className || ""} ${disabled ? styles$2.disabled : ""}`,
129
+ onTouchStart: handleTouchStart,
130
+ onTouchEnd: handleTouchEnd,
131
+ onTouchCancel: handleTouchEnd,
132
+ onMouseDown: startHold,
133
+ onMouseUp: endHold,
134
+ onMouseLeave: endHold,
135
+ disabled,
136
+ children
137
+ }
138
+ );
139
+ }
140
+
141
+ var css_248z$1 = ".DirectionPad-module_padContainer__iL-rh{align-items:center;display:flex;flex-direction:column;gap:8px;user-select:none;-webkit-user-select:none}.DirectionPad-module_horizontal__kI4j7{flex-direction:row;gap:16px}.DirectionPad-module_vertical__b8Xec{flex-direction:column;gap:16px}.DirectionPad-module_row__mzuUr{display:flex;gap:8px}.DirectionPad-module_dirButton__QCCHz{-webkit-tap-highlight-color:transparent;align-items:center;background:var(--color-surface,#374151);border:none;border-radius:12px;color:#fff;cursor:pointer;display:flex;font-size:24px;height:70px;justify-content:center;touch-action:manipulation;transition:transform .1s ease,background .1s ease;width:70px}.DirectionPad-module_dirButton__QCCHz:active{background:var(--color-primary,#6366f1);transform:scale(.9)}.DirectionPad-module_horizontal__kI4j7 .DirectionPad-module_dirButton__QCCHz,.DirectionPad-module_vertical__b8Xec .DirectionPad-module_dirButton__QCCHz{font-size:32px;height:100px;width:100px}";
142
+ var styles$1 = {"padContainer":"DirectionPad-module_padContainer__iL-rh","horizontal":"DirectionPad-module_horizontal__kI4j7","vertical":"DirectionPad-module_vertical__b8Xec","row":"DirectionPad-module_row__mzuUr","dirButton":"DirectionPad-module_dirButton__QCCHz"};
143
+ styleInject(css_248z$1);
144
+
145
+ function DirectionPad({
146
+ onDirection,
147
+ leftRightOnly = false,
148
+ upDownOnly = false,
149
+ className
150
+ }) {
151
+ const pressedRef = react.useRef(/* @__PURE__ */ new Set());
152
+ const handlePress = react.useCallback((direction) => {
153
+ if (pressedRef.current.has(direction)) return;
154
+ pressedRef.current.add(direction);
155
+ if (navigator.vibrate) {
156
+ navigator.vibrate(10);
157
+ }
158
+ onDirection(direction);
159
+ }, [onDirection]);
160
+ const handleRelease = react.useCallback((direction) => {
161
+ pressedRef.current.delete(direction);
162
+ }, []);
163
+ const createButton = (direction, label) => /* @__PURE__ */ jsxRuntime.jsx(
164
+ "button",
165
+ {
166
+ className: `${styles$1.dirButton} ${styles$1[direction]}`,
167
+ onTouchStart: (e) => {
168
+ e.preventDefault();
169
+ handlePress(direction);
170
+ },
171
+ onTouchEnd: (e) => {
172
+ e.preventDefault();
173
+ handleRelease(direction);
174
+ },
175
+ onTouchCancel: () => handleRelease(direction),
176
+ onMouseDown: () => handlePress(direction),
177
+ onMouseUp: () => handleRelease(direction),
178
+ onMouseLeave: () => handleRelease(direction),
179
+ children: label
180
+ },
181
+ direction
182
+ );
183
+ if (leftRightOnly) {
184
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles$1.padContainer} ${styles$1.horizontal} ${className || ""}`, children: [
185
+ createButton("left", "\u25C0"),
186
+ createButton("right", "\u25B6")
187
+ ] });
188
+ }
189
+ if (upDownOnly) {
190
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles$1.padContainer} ${styles$1.vertical} ${className || ""}`, children: [
191
+ createButton("up", "\u25B2"),
192
+ createButton("down", "\u25BC")
193
+ ] });
194
+ }
195
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles$1.padContainer} ${styles$1.full} ${className || ""}`, children: [
196
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles$1.row, children: createButton("up", "\u25B2") }),
197
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles$1.row, children: [
198
+ createButton("left", "\u25C0"),
199
+ createButton("right", "\u25B6")
200
+ ] }),
201
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles$1.row, children: createButton("down", "\u25BC") })
202
+ ] });
203
+ }
204
+
205
+ var css_248z = ".SwipeArea-module_swipeArea__yob7L{height:100%;touch-action:none;user-select:none;-webkit-user-select:none;width:100%}";
206
+ var styles = {"swipeArea":"SwipeArea-module_swipeArea__yob7L"};
207
+ styleInject(css_248z);
208
+
209
+ function SwipeArea({
210
+ onSwipe,
211
+ threshold = 50,
212
+ children,
213
+ className
214
+ }) {
215
+ const touchStart = react.useRef(null);
216
+ const handleTouchStart = react.useCallback((e) => {
217
+ const touch = e.touches[0];
218
+ if (!touch) return;
219
+ touchStart.current = { x: touch.clientX, y: touch.clientY };
220
+ }, []);
221
+ const handleTouchEnd = react.useCallback((e) => {
222
+ if (!touchStart.current) return;
223
+ const touch = e.changedTouches[0];
224
+ if (!touch) return;
225
+ const deltaX = touch.clientX - touchStart.current.x;
226
+ const deltaY = touch.clientY - touchStart.current.y;
227
+ const absX = Math.abs(deltaX);
228
+ const absY = Math.abs(deltaY);
229
+ if (absX < threshold && absY < threshold) {
230
+ touchStart.current = null;
231
+ return;
232
+ }
233
+ let direction;
234
+ if (absX > absY) {
235
+ direction = deltaX > 0 ? "right" : "left";
236
+ } else {
237
+ direction = deltaY > 0 ? "down" : "up";
238
+ }
239
+ if (navigator.vibrate) {
240
+ navigator.vibrate(15);
241
+ }
242
+ onSwipe(direction);
243
+ touchStart.current = null;
244
+ }, [onSwipe, threshold]);
245
+ return /* @__PURE__ */ jsxRuntime.jsx(
246
+ "div",
247
+ {
248
+ className: `${styles.swipeArea} ${className || ""}`,
249
+ onTouchStart: handleTouchStart,
250
+ onTouchEnd: handleTouchEnd,
251
+ onTouchCancel: () => {
252
+ touchStart.current = null;
253
+ },
254
+ children
255
+ }
256
+ );
257
+ }
258
+
259
+ class DirectTransport {
260
+ constructor(socket) {
261
+ this.socket = socket;
262
+ }
263
+ emit(event, ...args) {
264
+ this.socket.emit(event, ...args);
265
+ }
266
+ on(event, handler) {
267
+ this.socket.on(event, handler);
268
+ }
269
+ off(event, handler) {
270
+ if (handler) {
271
+ this.socket.off(event, handler);
272
+ } else {
273
+ this.socket.off(event);
274
+ }
275
+ }
276
+ }
277
+
278
+ const TransportContext = react.createContext(null);
279
+ function useTransport() {
280
+ const transport = react.useContext(TransportContext);
281
+ if (!transport) {
282
+ throw new Error("useTransport must be used within a RoomProvider that supplies a Transport");
283
+ }
284
+ return transport;
285
+ }
286
+ const RoomContext = react.createContext(null);
287
+ const HostRoomProvider = ({
288
+ roomCode,
289
+ players,
290
+ leaderId,
291
+ socket,
292
+ children
293
+ }) => {
294
+ const connectedPlayers = react.useMemo(
295
+ () => players.filter((p) => p.connected !== false),
296
+ [players]
297
+ );
298
+ const hostState = react.useMemo(
299
+ () => ({ roomCode, players, connectedPlayers, leaderId, socket }),
300
+ [roomCode, players, connectedPlayers, leaderId, socket]
301
+ );
302
+ const value = react.useMemo(
303
+ () => ({
304
+ roomCode,
305
+ players,
306
+ connectedPlayers,
307
+ leaderId,
308
+ side: "host",
309
+ host: hostState,
310
+ player: null
311
+ }),
312
+ [roomCode, players, connectedPlayers, leaderId, hostState]
313
+ );
314
+ const transport = react.useMemo(() => new DirectTransport(socket), [socket]);
315
+ return /* @__PURE__ */ jsxRuntime.jsx(TransportContext.Provider, { value: transport, children: /* @__PURE__ */ jsxRuntime.jsx(RoomContext.Provider, { value, children }) });
316
+ };
317
+ const PlayerRoomProvider = ({
318
+ roomCode,
319
+ players,
320
+ leaderId,
321
+ mySessionId,
322
+ isLeader,
323
+ socket,
324
+ isConnected,
325
+ children
326
+ }) => {
327
+ const connectedPlayers = react.useMemo(
328
+ () => players.filter((p) => p.connected !== false),
329
+ [players]
330
+ );
331
+ const playerState = react.useMemo(
332
+ () => ({
333
+ roomCode,
334
+ players,
335
+ connectedPlayers,
336
+ leaderId,
337
+ mySessionId,
338
+ isLeader,
339
+ socket,
340
+ isConnected
341
+ }),
342
+ [roomCode, players, connectedPlayers, leaderId, mySessionId, isLeader, socket, isConnected]
343
+ );
344
+ const value = react.useMemo(
345
+ () => ({
346
+ roomCode,
347
+ players,
348
+ connectedPlayers,
349
+ leaderId,
350
+ side: "player",
351
+ host: null,
352
+ player: playerState
353
+ }),
354
+ [roomCode, players, connectedPlayers, leaderId, playerState]
355
+ );
356
+ const transport = react.useMemo(() => new DirectTransport(socket), [socket]);
357
+ return /* @__PURE__ */ jsxRuntime.jsx(TransportContext.Provider, { value: transport, children: /* @__PURE__ */ jsxRuntime.jsx(RoomContext.Provider, { value, children }) });
358
+ };
359
+ function useRoom() {
360
+ const context = react.useContext(RoomContext);
361
+ if (!context) {
362
+ throw new Error("useRoom must be used within HostRoomProvider or PlayerRoomProvider");
363
+ }
364
+ return context;
365
+ }
366
+ function useHostRoom() {
367
+ const context = useRoom();
368
+ if (context.side !== "host" || !context.host) {
369
+ throw new Error("useHostRoom must be used within HostRoomProvider");
370
+ }
371
+ return context.host;
372
+ }
373
+ function usePlayerRoom() {
374
+ const context = useRoom();
375
+ if (context.side !== "player" || !context.player) {
376
+ throw new Error("usePlayerRoom must be used within PlayerRoomProvider");
377
+ }
378
+ return context.player;
379
+ }
380
+
381
+ const SMORE_MSG_PREFIX = "smore:";
382
+ function isSmoreMessage(data) {
383
+ return data && typeof data === "object" && typeof data.type === "string" && data.type.startsWith(SMORE_MSG_PREFIX);
384
+ }
385
+
386
+ class PostMessageTransport {
387
+ handlers = /* @__PURE__ */ new Map();
388
+ ackCallbacks = /* @__PURE__ */ new Map();
389
+ ackCounter = 0;
390
+ parentOrigin;
391
+ boundMessageHandler;
392
+ constructor(parentOrigin = "*") {
393
+ this.parentOrigin = parentOrigin;
394
+ this.boundMessageHandler = this.handleMessage.bind(this);
395
+ window.addEventListener("message", this.boundMessageHandler);
396
+ }
397
+ emit(event, ...args) {
398
+ let data = args[0];
399
+ let ackId;
400
+ if (args.length >= 2 && typeof args[args.length - 1] === "function") {
401
+ data = args.length === 2 ? args[0] : args[0];
402
+ const callback = args[args.length - 1];
403
+ ackId = `ack_${++this.ackCounter}`;
404
+ this.ackCallbacks.set(ackId, callback);
405
+ }
406
+ window.parent.postMessage(
407
+ { type: "smore:emit", payload: { event, data, ackId } },
408
+ this.parentOrigin
409
+ );
410
+ }
411
+ on(event, handler) {
412
+ let set = this.handlers.get(event);
413
+ if (!set) {
414
+ set = /* @__PURE__ */ new Set();
415
+ this.handlers.set(event, set);
416
+ }
417
+ set.add(handler);
418
+ }
419
+ off(event, handler) {
420
+ if (!handler) {
421
+ this.handlers.delete(event);
422
+ return;
423
+ }
424
+ this.handlers.get(event)?.delete(handler);
425
+ }
426
+ destroy() {
427
+ window.removeEventListener("message", this.boundMessageHandler);
428
+ this.handlers.clear();
429
+ this.ackCallbacks.clear();
430
+ }
431
+ handleMessage(e) {
432
+ if (this.parentOrigin !== "*" && e.origin !== this.parentOrigin) return;
433
+ const msg = e.data;
434
+ if (!isSmoreMessage(msg)) return;
435
+ if (msg.type === "smore:event") {
436
+ const { event, data } = msg.payload;
437
+ const set = this.handlers.get(event);
438
+ if (set) {
439
+ set.forEach((handler) => handler(data));
440
+ }
441
+ } else if (msg.type === "smore:ack") {
442
+ const { ackId, data } = msg.payload;
443
+ const cb = this.ackCallbacks.get(ackId);
444
+ if (cb) {
445
+ this.ackCallbacks.delete(ackId);
446
+ cb(data);
447
+ }
448
+ }
449
+ }
450
+ }
451
+
452
+ function useGameHost(config) {
453
+ const { gameId, onInput, onStateRequest, onPlayerLeave, onPlayerDisconnect, onPlayerReconnect, listeners } = config;
454
+ const hostRoom = useHostRoom();
455
+ const transport = useTransport();
456
+ const onInputRef = react.useRef(onInput);
457
+ const onStateRequestRef = react.useRef(onStateRequest);
458
+ const onPlayerLeaveRef = react.useRef(onPlayerLeave);
459
+ const onPlayerDisconnectRef = react.useRef(onPlayerDisconnect);
460
+ const onPlayerReconnectRef = react.useRef(onPlayerReconnect);
461
+ react.useEffect(() => {
462
+ onInputRef.current = onInput;
463
+ }, [onInput]);
464
+ react.useEffect(() => {
465
+ onStateRequestRef.current = onStateRequest;
466
+ }, [onStateRequest]);
467
+ react.useEffect(() => {
468
+ onPlayerLeaveRef.current = onPlayerLeave;
469
+ }, [onPlayerLeave]);
470
+ react.useEffect(() => {
471
+ onPlayerDisconnectRef.current = onPlayerDisconnect;
472
+ }, [onPlayerDisconnect]);
473
+ react.useEffect(() => {
474
+ onPlayerReconnectRef.current = onPlayerReconnect;
475
+ }, [onPlayerReconnect]);
476
+ react.useEffect(() => {
477
+ if (!transport || !onInputRef.current) return;
478
+ const registeredEvents = [];
479
+ const inputMap = onInputRef.current;
480
+ for (const key of Object.keys(inputMap)) {
481
+ const eventName = `${gameId}:${key}`;
482
+ const handler = (data) => {
483
+ const currentHandler = onInputRef.current?.[key];
484
+ if (currentHandler) {
485
+ currentHandler(data?.sessionId ?? data?.playerId, data);
486
+ }
487
+ };
488
+ transport.on(eventName, handler);
489
+ registeredEvents.push({ event: eventName, handler });
490
+ }
491
+ return () => {
492
+ for (const { event, handler } of registeredEvents) {
493
+ transport.off(event, handler);
494
+ }
495
+ };
496
+ }, [gameId, transport]);
497
+ react.useEffect(() => {
498
+ if (!transport) return;
499
+ const handler = (data) => {
500
+ const stateFn = onStateRequestRef.current;
501
+ if (!stateFn) return;
502
+ const gameState = stateFn(data.requesterId);
503
+ transport.emit("game:state-response", {
504
+ targetSessionId: data.requesterId,
505
+ gameState: {
506
+ gameId,
507
+ ...gameState
508
+ }
509
+ });
510
+ };
511
+ transport.on("game:state-request", handler);
512
+ return () => {
513
+ transport.off("game:state-request", handler);
514
+ };
515
+ }, [transport, gameId]);
516
+ react.useEffect(() => {
517
+ if (!transport) return;
518
+ const onLeft = (data) => {
519
+ onPlayerLeaveRef.current?.(data?.sessionId ?? data?.playerId);
520
+ };
521
+ const onDisconnected = (data) => {
522
+ onPlayerDisconnectRef.current?.(data?.sessionId ?? data?.playerId);
523
+ };
524
+ const onReconnected = (data) => {
525
+ onPlayerReconnectRef.current?.(data?.sessionId ?? data?.playerId);
526
+ };
527
+ transport.on("room:player-left", onLeft);
528
+ transport.on("room:player-disconnected", onDisconnected);
529
+ transport.on("room:player-reconnected", onReconnected);
530
+ return () => {
531
+ transport.off("room:player-left", onLeft);
532
+ transport.off("room:player-disconnected", onDisconnected);
533
+ transport.off("room:player-reconnected", onReconnected);
534
+ };
535
+ }, [transport]);
536
+ const listenersRef = react.useRef(listeners);
537
+ listenersRef.current = listeners;
538
+ react.useEffect(() => {
539
+ if (!transport || !listenersRef.current) return;
540
+ const entries = Object.entries(listenersRef.current);
541
+ const handlers = entries.map(([event, handler]) => {
542
+ transport.on(event, handler);
543
+ return () => {
544
+ transport.off(event, handler);
545
+ };
546
+ });
547
+ return () => handlers.forEach((fn) => fn());
548
+ }, [transport, listeners]);
549
+ const broadcast = react.useCallback(
550
+ (event, data) => {
551
+ transport?.emit(event, data);
552
+ },
553
+ [transport]
554
+ );
555
+ const sendToPlayer = react.useCallback(
556
+ (sessionId, event, data) => {
557
+ transport?.emit("game:state-to-player", {
558
+ targetSessionId: sessionId,
559
+ gameId,
560
+ event,
561
+ state: data
562
+ });
563
+ },
564
+ [transport, gameId]
565
+ );
566
+ const emitGameOver = react.useCallback(
567
+ (results) => {
568
+ transport?.emit("room:game-over", { gameId, results });
569
+ },
570
+ [transport, gameId]
571
+ );
572
+ return {
573
+ room: hostRoom,
574
+ broadcast,
575
+ sendToPlayer,
576
+ emitGameOver
577
+ };
578
+ }
579
+
580
+ function useGamePlayer(config) {
581
+ const room = usePlayerRoom();
582
+ const transport = useTransport();
583
+ const { isConnected } = room;
584
+ const { gameId, listeners } = config;
585
+ const [gameState, setGameState] = react.useState(null);
586
+ const listenersRef = react.useRef(listeners);
587
+ listenersRef.current = listeners;
588
+ react.useEffect(() => {
589
+ if (!transport || !listenersRef.current) return;
590
+ const cleanups = [];
591
+ Object.entries(listenersRef.current).forEach(([event, handler]) => {
592
+ transport.on(event, handler);
593
+ cleanups.push(() => transport.off(event, handler));
594
+ });
595
+ return () => cleanups.forEach((fn) => fn());
596
+ }, [transport, listeners]);
597
+ react.useEffect(() => {
598
+ if (!transport) return;
599
+ const handler = (state) => {
600
+ if (state.gameId !== gameId) return;
601
+ setGameState(state);
602
+ };
603
+ transport.on("game:state-response", handler);
604
+ return () => {
605
+ transport.off("game:state-response", handler);
606
+ };
607
+ }, [transport, gameId]);
608
+ react.useEffect(() => {
609
+ if (!transport) return;
610
+ const handler = (data) => {
611
+ if (data.gameId !== gameId) return;
612
+ setGameState(data.state);
613
+ };
614
+ transport.on("game:state-to-player", handler);
615
+ return () => {
616
+ transport.off("game:state-to-player", handler);
617
+ };
618
+ }, [transport, gameId]);
619
+ react.useEffect(() => {
620
+ if (!transport) return;
621
+ const handler = () => {
622
+ if (!document.hidden) {
623
+ transport.emit("game:request-state", { gameId });
624
+ }
625
+ };
626
+ document.addEventListener("visibilitychange", handler);
627
+ return () => document.removeEventListener("visibilitychange", handler);
628
+ }, [transport, gameId]);
629
+ const emit = react.useCallback((event, data, callback) => {
630
+ if (!transport) return;
631
+ if (callback) {
632
+ transport.emit(event, data, callback);
633
+ } else {
634
+ transport.emit(event, data);
635
+ }
636
+ }, [transport]);
637
+ const sendTapInput = react.useCallback((action) => {
638
+ if (!transport) return;
639
+ transport.emit(`${gameId}:${action}`);
640
+ }, [transport, gameId]);
641
+ const sendHoldInput = react.useCallback((action, type) => {
642
+ if (!transport) return;
643
+ transport.emit(`${gameId}:${action}:${type}`);
644
+ }, [transport, gameId]);
645
+ return { room, emit, sendTapInput, sendHoldInput, isConnected, gameState };
646
+ }
647
+
648
+ function useExternalGames(config) {
649
+ const { serverUrl, enabled = true } = config;
650
+ const [games, setGames] = react.useState([]);
651
+ const [loading, setLoading] = react.useState(false);
652
+ const [error, setError] = react.useState(null);
653
+ const [refreshKey, setRefreshKey] = react.useState(0);
654
+ react.useEffect(() => {
655
+ if (!enabled) return;
656
+ let cancelled = false;
657
+ setLoading(true);
658
+ fetch(`${serverUrl}/api/games`).then((res) => res.json()).then((data) => {
659
+ if (cancelled) return;
660
+ const external = (data.games || []).map((g) => ({
661
+ id: g.id,
662
+ title: g.title,
663
+ description: g.description || "",
664
+ minPlayers: g.minPlayers || 2,
665
+ maxPlayers: g.maxPlayers || 8,
666
+ thumbnail: g.thumbnail || "/thumbnails/g8.jpeg",
667
+ categories: g.categories || ["party"],
668
+ type: "external",
669
+ hostUrl: g.hostUrl,
670
+ playerUrl: g.playerUrl,
671
+ available: !!(g.hostUrl && g.playerUrl),
672
+ rating: 4,
673
+ heroRequired: false
674
+ }));
675
+ setGames(external);
676
+ setError(null);
677
+ }).catch((err) => {
678
+ if (cancelled) return;
679
+ setError(err.message);
680
+ }).finally(() => {
681
+ if (!cancelled) setLoading(false);
682
+ });
683
+ return () => {
684
+ cancelled = true;
685
+ };
686
+ }, [serverUrl, enabled, refreshKey]);
687
+ const refresh = () => setRefreshKey((k) => k + 1);
688
+ return { games, loading, error, refresh };
689
+ }
690
+
691
+ exports.DirectTransport = DirectTransport;
692
+ exports.DirectionPad = DirectionPad;
693
+ exports.HoldButton = HoldButton;
694
+ exports.HostRoomProvider = HostRoomProvider;
695
+ exports.PlayerRoomProvider = PlayerRoomProvider;
696
+ exports.PostMessageTransport = PostMessageTransport;
697
+ exports.SwipeArea = SwipeArea;
698
+ exports.TapButton = TapButton;
699
+ exports.TransportContext = TransportContext;
700
+ exports.useExternalGames = useExternalGames;
701
+ exports.useGameHost = useGameHost;
702
+ exports.useGamePlayer = useGamePlayer;
703
+ exports.useHostRoom = useHostRoom;
704
+ exports.usePlayerRoom = usePlayerRoom;
705
+ exports.useRoom = useRoom;
706
+ exports.useTransport = useTransport;
707
+
708
+ }));
709
+ //# sourceMappingURL=smore-sdk.umd.js.map