@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,68 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var DirectionPad_module = require('./DirectionPad.module.css.cjs');
6
+
7
+ function DirectionPad({
8
+ onDirection,
9
+ leftRightOnly = false,
10
+ upDownOnly = false,
11
+ className
12
+ }) {
13
+ const pressedRef = react.useRef(/* @__PURE__ */ new Set());
14
+ const handlePress = react.useCallback((direction) => {
15
+ if (pressedRef.current.has(direction)) return;
16
+ pressedRef.current.add(direction);
17
+ if (navigator.vibrate) {
18
+ navigator.vibrate(10);
19
+ }
20
+ onDirection(direction);
21
+ }, [onDirection]);
22
+ const handleRelease = react.useCallback((direction) => {
23
+ pressedRef.current.delete(direction);
24
+ }, []);
25
+ const createButton = (direction, label) => /* @__PURE__ */ jsxRuntime.jsx(
26
+ "button",
27
+ {
28
+ className: `${DirectionPad_module.default.dirButton} ${DirectionPad_module.default[direction]}`,
29
+ onTouchStart: (e) => {
30
+ e.preventDefault();
31
+ handlePress(direction);
32
+ },
33
+ onTouchEnd: (e) => {
34
+ e.preventDefault();
35
+ handleRelease(direction);
36
+ },
37
+ onTouchCancel: () => handleRelease(direction),
38
+ onMouseDown: () => handlePress(direction),
39
+ onMouseUp: () => handleRelease(direction),
40
+ onMouseLeave: () => handleRelease(direction),
41
+ children: label
42
+ },
43
+ direction
44
+ );
45
+ if (leftRightOnly) {
46
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${DirectionPad_module.default.padContainer} ${DirectionPad_module.default.horizontal} ${className || ""}`, children: [
47
+ createButton("left", "\u25C0"),
48
+ createButton("right", "\u25B6")
49
+ ] });
50
+ }
51
+ if (upDownOnly) {
52
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${DirectionPad_module.default.padContainer} ${DirectionPad_module.default.vertical} ${className || ""}`, children: [
53
+ createButton("up", "\u25B2"),
54
+ createButton("down", "\u25BC")
55
+ ] });
56
+ }
57
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${DirectionPad_module.default.padContainer} ${DirectionPad_module.default.full} ${className || ""}`, children: [
58
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DirectionPad_module.default.row, children: createButton("up", "\u25B2") }),
59
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: DirectionPad_module.default.row, children: [
60
+ createButton("left", "\u25C0"),
61
+ createButton("right", "\u25B6")
62
+ ] }),
63
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: DirectionPad_module.default.row, children: createButton("down", "\u25BC") })
64
+ ] });
65
+ }
66
+
67
+ exports.DirectionPad = DirectionPad;
68
+ //# sourceMappingURL=DirectionPad.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DirectionPad.cjs","sources":["../../../src/components/DirectionPad.tsx"],"sourcesContent":["/**\n * S'MORE Game SDK - DirectionPad Component\n *\n * 4-direction or 2-direction control pad\n */\n\nimport { useCallback, useRef } from 'react';\nimport type { DirectionPadProps } from '../types';\nimport styles from './DirectionPad.module.css';\n\n/**\n * DirectionPad - For directional input\n *\n * @example\n * ```tsx\n * // 4 directions\n * <DirectionPad onDirection={(dir) => send('move', { direction: dir })} />\n *\n * // Left/Right only\n * <DirectionPad leftRightOnly onDirection={(dir) => send('move', { direction: dir })} />\n * ```\n */\nexport function DirectionPad({\n onDirection,\n leftRightOnly = false,\n upDownOnly = false,\n className,\n}: DirectionPadProps) {\n const pressedRef = useRef<Set<string>>(new Set());\n\n const handlePress = useCallback((direction: 'up' | 'down' | 'left' | 'right') => {\n if (pressedRef.current.has(direction)) return;\n pressedRef.current.add(direction);\n\n // Haptic feedback\n if (navigator.vibrate) {\n navigator.vibrate(10);\n }\n\n onDirection(direction);\n }, [onDirection]);\n\n const handleRelease = useCallback((direction: string) => {\n pressedRef.current.delete(direction);\n }, []);\n\n const createButton = (direction: 'up' | 'down' | 'left' | 'right', label: string) => (\n <button\n key={direction}\n className={`${styles.dirButton} ${styles[direction]}`}\n onTouchStart={(e) => {\n e.preventDefault();\n handlePress(direction);\n }}\n onTouchEnd={(e) => {\n e.preventDefault();\n handleRelease(direction);\n }}\n onTouchCancel={() => handleRelease(direction)}\n onMouseDown={() => handlePress(direction)}\n onMouseUp={() => handleRelease(direction)}\n onMouseLeave={() => handleRelease(direction)}\n >\n {label}\n </button>\n );\n\n if (leftRightOnly) {\n return (\n <div className={`${styles.padContainer} ${styles.horizontal} ${className || ''}`}>\n {createButton('left', '◀')}\n {createButton('right', '▶')}\n </div>\n );\n }\n\n if (upDownOnly) {\n return (\n <div className={`${styles.padContainer} ${styles.vertical} ${className || ''}`}>\n {createButton('up', '▲')}\n {createButton('down', '▼')}\n </div>\n );\n }\n\n return (\n <div className={`${styles.padContainer} ${styles.full} ${className || ''}`}>\n <div className={styles.row}>\n {createButton('up', '▲')}\n </div>\n <div className={styles.row}>\n {createButton('left', '◀')}\n {createButton('right', '▶')}\n </div>\n <div className={styles.row}>\n {createButton('down', '▼')}\n </div>\n </div>\n );\n}\n\nexport default DirectionPad;\n"],"names":["useRef","useCallback","jsx","styles","jsxs"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var styleInject_es = require('../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs');
6
+
7
+ var css_248z = ".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}";
8
+ var styles = {"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"};
9
+ styleInject_es.default(css_248z);
10
+
11
+ exports.default = styles;
12
+ //# sourceMappingURL=DirectionPad.module.css.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DirectionPad.module.css.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var HoldButton_module = require('./HoldButton.module.css.cjs');
6
+
7
+ function HoldButton({
8
+ onHoldStart,
9
+ onHoldEnd,
10
+ children,
11
+ className,
12
+ disabled = false
13
+ }) {
14
+ const isHolding = react.useRef(false);
15
+ const buttonRef = react.useRef(null);
16
+ const startHold = react.useCallback(() => {
17
+ if (disabled || isHolding.current) return;
18
+ isHolding.current = true;
19
+ buttonRef.current?.classList.add(HoldButton_module.default.pressed);
20
+ if (navigator.vibrate) {
21
+ navigator.vibrate(10);
22
+ }
23
+ onHoldStart();
24
+ }, [onHoldStart, disabled]);
25
+ const endHold = react.useCallback(() => {
26
+ if (!isHolding.current) return;
27
+ isHolding.current = false;
28
+ buttonRef.current?.classList.remove(HoldButton_module.default.pressed);
29
+ onHoldEnd();
30
+ }, [onHoldEnd]);
31
+ const handleTouchStart = react.useCallback((e) => {
32
+ e.preventDefault();
33
+ startHold();
34
+ }, [startHold]);
35
+ const handleTouchEnd = react.useCallback((e) => {
36
+ e.preventDefault();
37
+ endHold();
38
+ }, [endHold]);
39
+ return /* @__PURE__ */ jsxRuntime.jsx(
40
+ "button",
41
+ {
42
+ ref: buttonRef,
43
+ className: `${HoldButton_module.default.holdButton} ${className || ""} ${disabled ? HoldButton_module.default.disabled : ""}`,
44
+ onTouchStart: handleTouchStart,
45
+ onTouchEnd: handleTouchEnd,
46
+ onTouchCancel: handleTouchEnd,
47
+ onMouseDown: startHold,
48
+ onMouseUp: endHold,
49
+ onMouseLeave: endHold,
50
+ disabled,
51
+ children
52
+ }
53
+ );
54
+ }
55
+
56
+ exports.HoldButton = HoldButton;
57
+ //# sourceMappingURL=HoldButton.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HoldButton.cjs","sources":["../../../src/components/HoldButton.tsx"],"sourcesContent":["/**\n * S'MORE Game SDK - HoldButton Component\n *\n * Button that detects hold start/end events\n */\n\nimport { useRef, useCallback } from 'react';\nimport type React from 'react';\nimport type { HoldButtonProps } from '../types';\nimport styles from './HoldButton.module.css';\n\n/**\n * HoldButton - For hold/release input patterns\n *\n * @example\n * ```tsx\n * <HoldButton\n * onHoldStart={() => send('charge', { type: 'start' })}\n * onHoldEnd={() => send('charge', { type: 'end' })}\n * >\n * HOLD\n * </HoldButton>\n * ```\n */\nexport function HoldButton({\n onHoldStart,\n onHoldEnd,\n children,\n className,\n disabled = false,\n}: HoldButtonProps) {\n const isHolding = useRef(false);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n const startHold = useCallback(() => {\n if (disabled || isHolding.current) return;\n isHolding.current = true;\n buttonRef.current?.classList.add(styles.pressed || '');\n\n // Haptic feedback\n if (navigator.vibrate) {\n navigator.vibrate(10);\n }\n\n onHoldStart();\n }, [onHoldStart, disabled]);\n\n const endHold = useCallback(() => {\n if (!isHolding.current) return;\n isHolding.current = false;\n buttonRef.current?.classList.remove(styles.pressed || '');\n onHoldEnd();\n }, [onHoldEnd]);\n\n const handleTouchStart = useCallback((e: React.TouchEvent) => {\n e.preventDefault();\n startHold();\n }, [startHold]);\n\n const handleTouchEnd = useCallback((e: React.TouchEvent) => {\n e.preventDefault();\n endHold();\n }, [endHold]);\n\n return (\n <button\n ref={buttonRef}\n className={`${styles.holdButton} ${className || ''} ${disabled ? styles.disabled : ''}`}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n onTouchCancel={handleTouchEnd}\n onMouseDown={startHold}\n onMouseUp={endHold}\n onMouseLeave={endHold}\n disabled={disabled}\n >\n {children}\n </button>\n );\n}\n\nexport default HoldButton;\n"],"names":["useRef","useCallback","styles","jsx"],"mappings":";;;;;;AAwBO,SAAS,UAAA,CAAW;AAAA,EACzB,WAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA,GAAW;AACb,CAAA,EAAoB;AAClB,EAAA,MAAM,SAAA,GAAYA,aAAO,KAAK,CAAA;AAC9B,EAAA,MAAM,SAAA,GAAYA,aAA0B,IAAI,CAAA;AAEhD,EAAA,MAAM,SAAA,GAAYC,kBAAY,MAAM;AAClC,IAAA,IAAI,QAAA,IAAY,UAAU,OAAA,EAAS;AACnC,IAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AACpB,IAAA,SAAA,CAAU,OAAA,EAAS,SAAA,CAAU,GAAA,CAAIC,yBAAA,CAAO,OAAa,CAAA;AAGrD,IAAA,IAAI,UAAU,OAAA,EAAS;AACrB,MAAA,SAAA,CAAU,QAAQ,EAAE,CAAA;AAAA,IACtB;AAEA,IAAA,WAAA,EAAY;AAAA,EACd,CAAA,EAAG,CAAC,WAAA,EAAa,QAAQ,CAAC,CAAA;AAE1B,EAAA,MAAM,OAAA,GAAUD,kBAAY,MAAM;AAChC,IAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACxB,IAAA,SAAA,CAAU,OAAA,GAAU,KAAA;AACpB,IAAA,SAAA,CAAU,OAAA,EAAS,SAAA,CAAU,MAAA,CAAOC,yBAAA,CAAO,OAAa,CAAA;AACxD,IAAA,SAAA,EAAU;AAAA,EACZ,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,gBAAA,GAAmBD,iBAAA,CAAY,CAAC,CAAA,KAAwB;AAC5D,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,SAAA,EAAU;AAAA,EACZ,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,cAAA,GAAiBA,iBAAA,CAAY,CAAC,CAAA,KAAwB;AAC1D,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,uBACEE,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAW,CAAA,EAAGD,yBAAA,CAAO,UAAU,CAAA,CAAA,EAAI,SAAA,IAAa,EAAE,CAAA,CAAA,EAAI,QAAA,GAAWA,yBAAA,CAAO,QAAA,GAAW,EAAE,CAAA,CAAA;AAAA,MACrF,YAAA,EAAc,gBAAA;AAAA,MACd,UAAA,EAAY,cAAA;AAAA,MACZ,aAAA,EAAe,cAAA;AAAA,MACf,WAAA,EAAa,SAAA;AAAA,MACb,SAAA,EAAW,OAAA;AAAA,MACX,YAAA,EAAc,OAAA;AAAA,MACd,QAAA;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;;;;"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var styleInject_es = require('../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs');
6
+
7
+ var css_248z = ".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}";
8
+ var styles = {"holdButton":"HoldButton-module_holdButton__tu4mi","pressed":"HoldButton-module_pressed__JWIRG","disabled":"HoldButton-module_disabled__4QwwT"};
9
+ styleInject_es.default(css_248z);
10
+
11
+ exports.default = styles;
12
+ //# sourceMappingURL=HoldButton.module.css.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HoldButton.module.css.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var SwipeArea_module = require('./SwipeArea.module.css.cjs');
6
+
7
+ function SwipeArea({
8
+ onSwipe,
9
+ threshold = 50,
10
+ children,
11
+ className
12
+ }) {
13
+ const touchStart = react.useRef(null);
14
+ const handleTouchStart = react.useCallback((e) => {
15
+ const touch = e.touches[0];
16
+ if (!touch) return;
17
+ touchStart.current = { x: touch.clientX, y: touch.clientY };
18
+ }, []);
19
+ const handleTouchEnd = react.useCallback((e) => {
20
+ if (!touchStart.current) return;
21
+ const touch = e.changedTouches[0];
22
+ if (!touch) return;
23
+ const deltaX = touch.clientX - touchStart.current.x;
24
+ const deltaY = touch.clientY - touchStart.current.y;
25
+ const absX = Math.abs(deltaX);
26
+ const absY = Math.abs(deltaY);
27
+ if (absX < threshold && absY < threshold) {
28
+ touchStart.current = null;
29
+ return;
30
+ }
31
+ let direction;
32
+ if (absX > absY) {
33
+ direction = deltaX > 0 ? "right" : "left";
34
+ } else {
35
+ direction = deltaY > 0 ? "down" : "up";
36
+ }
37
+ if (navigator.vibrate) {
38
+ navigator.vibrate(15);
39
+ }
40
+ onSwipe(direction);
41
+ touchStart.current = null;
42
+ }, [onSwipe, threshold]);
43
+ return /* @__PURE__ */ jsxRuntime.jsx(
44
+ "div",
45
+ {
46
+ className: `${SwipeArea_module.default.swipeArea} ${className || ""}`,
47
+ onTouchStart: handleTouchStart,
48
+ onTouchEnd: handleTouchEnd,
49
+ onTouchCancel: () => {
50
+ touchStart.current = null;
51
+ },
52
+ children
53
+ }
54
+ );
55
+ }
56
+
57
+ exports.SwipeArea = SwipeArea;
58
+ //# sourceMappingURL=SwipeArea.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwipeArea.cjs","sources":["../../../src/components/SwipeArea.tsx"],"sourcesContent":["/**\n * S'MORE Game SDK - SwipeArea Component\n *\n * Detects swipe gestures\n */\n\nimport { useRef, useCallback } from 'react';\nimport type React from 'react';\nimport type { SwipeAreaProps } from '../types';\nimport styles from './SwipeArea.module.css';\n\n/**\n * SwipeArea - For swipe gesture input\n *\n * @example\n * ```tsx\n * <SwipeArea onSwipe={(dir) => send('swipe', { direction: dir })}>\n * <div>Swipe here!</div>\n * </SwipeArea>\n * ```\n */\nexport function SwipeArea({\n onSwipe,\n threshold = 50,\n children,\n className,\n}: SwipeAreaProps) {\n const touchStart = useRef<{ x: number; y: number } | null>(null);\n\n const handleTouchStart = useCallback((e: React.TouchEvent) => {\n const touch = e.touches[0];\n if (!touch) return;\n touchStart.current = { x: touch.clientX, y: touch.clientY };\n }, []);\n\n const handleTouchEnd = useCallback((e: React.TouchEvent) => {\n if (!touchStart.current) return;\n\n const touch = e.changedTouches[0];\n if (!touch) return;\n const deltaX = touch.clientX - touchStart.current.x;\n const deltaY = touch.clientY - touchStart.current.y;\n\n const absX = Math.abs(deltaX);\n const absY = Math.abs(deltaY);\n\n // Check if swipe exceeds threshold\n if (absX < threshold && absY < threshold) {\n touchStart.current = null;\n return;\n }\n\n // Determine direction\n let direction: 'up' | 'down' | 'left' | 'right';\n if (absX > absY) {\n direction = deltaX > 0 ? 'right' : 'left';\n } else {\n direction = deltaY > 0 ? 'down' : 'up';\n }\n\n // Haptic feedback\n if (navigator.vibrate) {\n navigator.vibrate(15);\n }\n\n onSwipe(direction);\n touchStart.current = null;\n }, [onSwipe, threshold]);\n\n return (\n <div\n className={`${styles.swipeArea} ${className || ''}`}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n onTouchCancel={() => { touchStart.current = null; }}\n >\n {children}\n </div>\n );\n}\n\nexport default SwipeArea;\n"],"names":["useRef","useCallback","jsx","styles"],"mappings":";;;;;;AAqBO,SAAS,SAAA,CAAU;AAAA,EACxB,OAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,QAAA;AAAA,EACA;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,UAAA,GAAaA,aAAwC,IAAI,CAAA;AAE/D,EAAA,MAAM,gBAAA,GAAmBC,iBAAA,CAAY,CAAC,CAAA,KAAwB;AAC5D,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AACzB,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,UAAA,CAAW,UAAU,EAAE,CAAA,EAAG,MAAM,OAAA,EAAS,CAAA,EAAG,MAAM,OAAA,EAAQ;AAAA,EAC5D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,cAAA,GAAiBA,iBAAA,CAAY,CAAC,CAAA,KAAwB;AAC1D,IAAA,IAAI,CAAC,WAAW,OAAA,EAAS;AAEzB,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,cAAA,CAAe,CAAC,CAAA;AAChC,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,GAAU,UAAA,CAAW,OAAA,CAAQ,CAAA;AAClD,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,OAAA,GAAU,UAAA,CAAW,OAAA,CAAQ,CAAA;AAElD,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAC5B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAG5B,IAAA,IAAI,IAAA,GAAO,SAAA,IAAa,IAAA,GAAO,SAAA,EAAW;AACxC,MAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,MAAA;AAAA,IACF;AAGA,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,SAAA,GAAY,MAAA,GAAS,IAAI,OAAA,GAAU,MAAA;AAAA,IACrC,CAAA,MAAO;AACL,MAAA,SAAA,GAAY,MAAA,GAAS,IAAI,MAAA,GAAS,IAAA;AAAA,IACpC;AAGA,IAAA,IAAI,UAAU,OAAA,EAAS;AACrB,MAAA,SAAA,CAAU,QAAQ,EAAE,CAAA;AAAA,IACtB;AAEA,IAAA,OAAA,CAAQ,SAAS,CAAA;AACjB,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AAAA,EACvB,CAAA,EAAG,CAAC,OAAA,EAAS,SAAS,CAAC,CAAA;AAEvB,EAAA,uBACEC,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,WAAW,CAAA,EAAGC,wBAAA,CAAO,SAAS,CAAA,CAAA,EAAI,aAAa,EAAE,CAAA,CAAA;AAAA,MACjD,YAAA,EAAc,gBAAA;AAAA,MACd,UAAA,EAAY,cAAA;AAAA,MACZ,eAAe,MAAM;AAAE,QAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AAAA,MAAM,CAAA;AAAA,MAEjD;AAAA;AAAA,GACH;AAEJ;;;;"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var styleInject_es = require('../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs');
6
+
7
+ var css_248z = ".SwipeArea-module_swipeArea__yob7L{height:100%;touch-action:none;user-select:none;-webkit-user-select:none;width:100%}";
8
+ var styles = {"swipeArea":"SwipeArea-module_swipeArea__yob7L"};
9
+ styleInject_es.default(css_248z);
10
+
11
+ exports.default = styles;
12
+ //# sourceMappingURL=SwipeArea.module.css.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SwipeArea.module.css.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var TapButton_module = require('./TapButton.module.css.cjs');
6
+
7
+ function TapButton({
8
+ onTap,
9
+ children,
10
+ className,
11
+ disabled = false
12
+ }) {
13
+ const isPressed = react.useRef(false);
14
+ const buttonRef = react.useRef(null);
15
+ const handleTouchStart = react.useCallback((e) => {
16
+ if (disabled) return;
17
+ e.preventDefault();
18
+ isPressed.current = true;
19
+ buttonRef.current?.classList.add(TapButton_module.default.pressed);
20
+ if (navigator.vibrate) {
21
+ navigator.vibrate(10);
22
+ }
23
+ onTap();
24
+ }, [onTap, disabled]);
25
+ const handleTouchEnd = react.useCallback((e) => {
26
+ e.preventDefault();
27
+ isPressed.current = false;
28
+ buttonRef.current?.classList.remove(TapButton_module.default.pressed);
29
+ }, []);
30
+ const handleMouseDown = react.useCallback(() => {
31
+ if (disabled) return;
32
+ isPressed.current = true;
33
+ buttonRef.current?.classList.add(TapButton_module.default.pressed);
34
+ onTap();
35
+ }, [onTap, disabled]);
36
+ const handleMouseUp = react.useCallback(() => {
37
+ isPressed.current = false;
38
+ buttonRef.current?.classList.remove(TapButton_module.default.pressed);
39
+ }, []);
40
+ return /* @__PURE__ */ jsxRuntime.jsx(
41
+ "button",
42
+ {
43
+ ref: buttonRef,
44
+ className: `${TapButton_module.default.tapButton} ${className || ""} ${disabled ? TapButton_module.default.disabled : ""}`,
45
+ onTouchStart: handleTouchStart,
46
+ onTouchEnd: handleTouchEnd,
47
+ onTouchCancel: handleTouchEnd,
48
+ onMouseDown: handleMouseDown,
49
+ onMouseUp: handleMouseUp,
50
+ onMouseLeave: handleMouseUp,
51
+ disabled,
52
+ children
53
+ }
54
+ );
55
+ }
56
+
57
+ exports.TapButton = TapButton;
58
+ //# sourceMappingURL=TapButton.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TapButton.cjs","sources":["../../../src/components/TapButton.tsx"],"sourcesContent":["/**\n * S'MORE Game SDK - TapButton Component\n *\n * Optimized touch button with haptic feedback\n */\n\nimport { useRef, useCallback } from 'react';\nimport type React from 'react';\nimport type { TapButtonProps } from '../types';\nimport styles from './TapButton.module.css';\n\n/**\n * TapButton - Optimized for mobile touch input\n *\n * @example\n * ```tsx\n * <TapButton onTap={() => send('tap')}>\n * TAP!\n * </TapButton>\n * ```\n */\nexport function TapButton({\n onTap,\n children,\n className,\n disabled = false,\n}: TapButtonProps) {\n const isPressed = useRef(false);\n const buttonRef = useRef<HTMLButtonElement>(null);\n\n const handleTouchStart = useCallback((e: React.TouchEvent) => {\n if (disabled) return;\n e.preventDefault();\n isPressed.current = true;\n buttonRef.current?.classList.add(styles.pressed || '');\n\n // Haptic feedback\n if (navigator.vibrate) {\n navigator.vibrate(10);\n }\n\n onTap();\n }, [onTap, disabled]);\n\n const handleTouchEnd = useCallback((e: React.TouchEvent) => {\n e.preventDefault();\n isPressed.current = false;\n buttonRef.current?.classList.remove(styles.pressed || '');\n }, []);\n\n const handleMouseDown = useCallback(() => {\n if (disabled) return;\n isPressed.current = true;\n buttonRef.current?.classList.add(styles.pressed || '');\n onTap();\n }, [onTap, disabled]);\n\n const handleMouseUp = useCallback(() => {\n isPressed.current = false;\n buttonRef.current?.classList.remove(styles.pressed || '');\n }, []);\n\n return (\n <button\n ref={buttonRef}\n className={`${styles.tapButton} ${className || ''} ${disabled ? styles.disabled : ''}`}\n onTouchStart={handleTouchStart}\n onTouchEnd={handleTouchEnd}\n onTouchCancel={handleTouchEnd}\n onMouseDown={handleMouseDown}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n disabled={disabled}\n >\n {children}\n </button>\n );\n}\n\nexport default TapButton;\n"],"names":["useRef","useCallback","styles","jsx"],"mappings":";;;;;;AAqBO,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA,GAAW;AACb,CAAA,EAAmB;AACjB,EAAA,MAAM,SAAA,GAAYA,aAAO,KAAK,CAAA;AAC9B,EAAA,MAAM,SAAA,GAAYA,aAA0B,IAAI,CAAA;AAEhD,EAAA,MAAM,gBAAA,GAAmBC,iBAAA,CAAY,CAAC,CAAA,KAAwB;AAC5D,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AACpB,IAAA,SAAA,CAAU,OAAA,EAAS,SAAA,CAAU,GAAA,CAAIC,wBAAA,CAAO,OAAa,CAAA;AAGrD,IAAA,IAAI,UAAU,OAAA,EAAS;AACrB,MAAA,SAAA,CAAU,QAAQ,EAAE,CAAA;AAAA,IACtB;AAEA,IAAA,KAAA,EAAM;AAAA,EACR,CAAA,EAAG,CAAC,KAAA,EAAO,QAAQ,CAAC,CAAA;AAEpB,EAAA,MAAM,cAAA,GAAiBD,iBAAA,CAAY,CAAC,CAAA,KAAwB;AAC1D,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,SAAA,CAAU,OAAA,GAAU,KAAA;AACpB,IAAA,SAAA,CAAU,OAAA,EAAS,SAAA,CAAU,MAAA,CAAOC,wBAAA,CAAO,OAAa,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,eAAA,GAAkBD,kBAAY,MAAM;AACxC,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,SAAA,CAAU,OAAA,GAAU,IAAA;AACpB,IAAA,SAAA,CAAU,OAAA,EAAS,SAAA,CAAU,GAAA,CAAIC,wBAAA,CAAO,OAAa,CAAA;AACrD,IAAA,KAAA,EAAM;AAAA,EACR,CAAA,EAAG,CAAC,KAAA,EAAO,QAAQ,CAAC,CAAA;AAEpB,EAAA,MAAM,aAAA,GAAgBD,kBAAY,MAAM;AACtC,IAAA,SAAA,CAAU,OAAA,GAAU,KAAA;AACpB,IAAA,SAAA,CAAU,OAAA,EAAS,SAAA,CAAU,MAAA,CAAOC,wBAAA,CAAO,OAAa,CAAA;AAAA,EAC1D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,uBACEC,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,SAAA;AAAA,MACL,SAAA,EAAW,CAAA,EAAGD,wBAAA,CAAO,SAAS,CAAA,CAAA,EAAI,SAAA,IAAa,EAAE,CAAA,CAAA,EAAI,QAAA,GAAWA,wBAAA,CAAO,QAAA,GAAW,EAAE,CAAA,CAAA;AAAA,MACpF,YAAA,EAAc,gBAAA;AAAA,MACd,UAAA,EAAY,cAAA;AAAA,MACZ,aAAA,EAAe,cAAA;AAAA,MACf,WAAA,EAAa,eAAA;AAAA,MACb,SAAA,EAAW,aAAA;AAAA,MACX,YAAA,EAAc,aAAA;AAAA,MACd,QAAA;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;;;;"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var styleInject_es = require('../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.cjs');
6
+
7
+ var css_248z = ".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}";
8
+ var styles = {"tapButton":"TapButton-module_tapButton__dqJr9","pressed":"TapButton-module_pressed__Z2nfR","disabled":"TapButton-module_disabled__3bR6q"};
9
+ styleInject_es.default(css_248z);
10
+
11
+ exports.default = styles;
12
+ //# sourceMappingURL=TapButton.module.css.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TapButton.module.css.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
@@ -0,0 +1,118 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var DirectTransport = require('../transport/DirectTransport.cjs');
6
+
7
+ const TransportContext = react.createContext(null);
8
+ function useTransport() {
9
+ const transport = react.useContext(TransportContext);
10
+ if (!transport) {
11
+ throw new Error("useTransport must be used within a RoomProvider that supplies a Transport");
12
+ }
13
+ return transport;
14
+ }
15
+ const RoomContext = react.createContext(null);
16
+ const HostRoomProvider = ({
17
+ roomCode,
18
+ players,
19
+ leaderId,
20
+ socket,
21
+ children
22
+ }) => {
23
+ const connectedPlayers = react.useMemo(
24
+ () => players.filter((p) => p.connected !== false),
25
+ [players]
26
+ );
27
+ const hostState = react.useMemo(
28
+ () => ({ roomCode, players, connectedPlayers, leaderId, socket }),
29
+ [roomCode, players, connectedPlayers, leaderId, socket]
30
+ );
31
+ const value = react.useMemo(
32
+ () => ({
33
+ roomCode,
34
+ players,
35
+ connectedPlayers,
36
+ leaderId,
37
+ side: "host",
38
+ host: hostState,
39
+ player: null
40
+ }),
41
+ [roomCode, players, connectedPlayers, leaderId, hostState]
42
+ );
43
+ const transport = react.useMemo(() => new DirectTransport.DirectTransport(socket), [socket]);
44
+ return /* @__PURE__ */ jsxRuntime.jsx(TransportContext.Provider, { value: transport, children: /* @__PURE__ */ jsxRuntime.jsx(RoomContext.Provider, { value, children }) });
45
+ };
46
+ const PlayerRoomProvider = ({
47
+ roomCode,
48
+ players,
49
+ leaderId,
50
+ mySessionId,
51
+ isLeader,
52
+ socket,
53
+ isConnected,
54
+ children
55
+ }) => {
56
+ const connectedPlayers = react.useMemo(
57
+ () => players.filter((p) => p.connected !== false),
58
+ [players]
59
+ );
60
+ const playerState = react.useMemo(
61
+ () => ({
62
+ roomCode,
63
+ players,
64
+ connectedPlayers,
65
+ leaderId,
66
+ mySessionId,
67
+ isLeader,
68
+ socket,
69
+ isConnected
70
+ }),
71
+ [roomCode, players, connectedPlayers, leaderId, mySessionId, isLeader, socket, isConnected]
72
+ );
73
+ const value = react.useMemo(
74
+ () => ({
75
+ roomCode,
76
+ players,
77
+ connectedPlayers,
78
+ leaderId,
79
+ side: "player",
80
+ host: null,
81
+ player: playerState
82
+ }),
83
+ [roomCode, players, connectedPlayers, leaderId, playerState]
84
+ );
85
+ const transport = react.useMemo(() => new DirectTransport.DirectTransport(socket), [socket]);
86
+ return /* @__PURE__ */ jsxRuntime.jsx(TransportContext.Provider, { value: transport, children: /* @__PURE__ */ jsxRuntime.jsx(RoomContext.Provider, { value, children }) });
87
+ };
88
+ function useRoom() {
89
+ const context = react.useContext(RoomContext);
90
+ if (!context) {
91
+ throw new Error("useRoom must be used within HostRoomProvider or PlayerRoomProvider");
92
+ }
93
+ return context;
94
+ }
95
+ function useHostRoom() {
96
+ const context = useRoom();
97
+ if (context.side !== "host" || !context.host) {
98
+ throw new Error("useHostRoom must be used within HostRoomProvider");
99
+ }
100
+ return context.host;
101
+ }
102
+ function usePlayerRoom() {
103
+ const context = useRoom();
104
+ if (context.side !== "player" || !context.player) {
105
+ throw new Error("usePlayerRoom must be used within PlayerRoomProvider");
106
+ }
107
+ return context.player;
108
+ }
109
+
110
+ exports.HostRoomProvider = HostRoomProvider;
111
+ exports.PlayerRoomProvider = PlayerRoomProvider;
112
+ exports.RoomContext = RoomContext;
113
+ exports.TransportContext = TransportContext;
114
+ exports.useHostRoom = useHostRoom;
115
+ exports.usePlayerRoom = usePlayerRoom;
116
+ exports.useRoom = useRoom;
117
+ exports.useTransport = useTransport;
118
+ //# sourceMappingURL=RoomProvider.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoomProvider.cjs","sources":["../../../src/context/RoomProvider.tsx"],"sourcesContent":["/**\n * RoomProvider - SDK Room Context\n *\n * Foundation context that all other SDK hooks depend on.\n * Provides room state (players, roomCode, leaderId) for both host and player sides.\n *\n * Also provides a Transport abstraction via TransportContext.\n * - HostRoomProvider / PlayerRoomProvider create a DirectTransport from the socket.\n * - IframeRoomProvider (external) provides a PostMessageTransport.\n *\n * Usage:\n * - Host: <HostRoomProvider roomCode={...} players={...} leaderId={...} socket={...}>\n * - Player: <PlayerRoomProvider roomCode={...} players={...} leaderId={...} mySessionId={...} isLeader={...} socket={...} isConnected={...}>\n */\n\nimport React, { createContext, useContext, useMemo } from 'react';\nimport type { Player } from '@smore/shared';\nimport type { Socket } from 'socket.io-client';\nimport type { Transport } from '../transport/types';\nimport { DirectTransport } from '../transport/DirectTransport';\n\n// ===== Transport Context =====\n\nconst TransportContext = createContext<Transport | null>(null);\n\nexport function useTransport(): Transport {\n const transport = useContext(TransportContext);\n if (!transport) {\n throw new Error('useTransport must be used within a RoomProvider that supplies a Transport');\n }\n return transport;\n}\n\nexport { TransportContext };\n\n// ===== State Types =====\n\nexport interface RoomState {\n roomCode: string;\n players: Player[];\n connectedPlayers: Player[];\n leaderId: string | null;\n}\n\nexport interface HostRoomState extends RoomState {\n socket: Socket;\n}\n\nexport interface PlayerRoomState extends RoomState {\n mySessionId: string;\n isLeader: boolean;\n socket: Socket;\n isConnected: boolean;\n}\n\nexport interface RoomContextValue {\n roomCode: string;\n players: Player[];\n connectedPlayers: Player[];\n leaderId: string | null;\n side: 'host' | 'player';\n host: HostRoomState | null;\n player: PlayerRoomState | null;\n}\n\n// ===== Context =====\n\nexport const RoomContext = createContext<RoomContextValue | null>(null);\n\n// ===== Host Provider =====\n\ninterface HostRoomProviderProps {\n roomCode: string;\n players: Player[];\n leaderId: string | null;\n socket: Socket;\n children: React.ReactNode;\n}\n\nexport const HostRoomProvider: React.FC<HostRoomProviderProps> = ({\n roomCode,\n players,\n leaderId,\n socket,\n children,\n}) => {\n const connectedPlayers = useMemo(\n () => players.filter((p) => p.connected !== false),\n [players]\n );\n\n const hostState: HostRoomState = useMemo(\n () => ({ roomCode, players, connectedPlayers, leaderId, socket }),\n [roomCode, players, connectedPlayers, leaderId, socket]\n );\n\n const value: RoomContextValue = useMemo(\n () => ({\n roomCode,\n players,\n connectedPlayers,\n leaderId,\n side: 'host' as const,\n host: hostState,\n player: null,\n }),\n [roomCode, players, connectedPlayers, leaderId, hostState]\n );\n\n const transport = useMemo(() => new DirectTransport(socket), [socket]);\n\n return (\n <TransportContext.Provider value={transport}>\n <RoomContext.Provider value={value}>{children}</RoomContext.Provider>\n </TransportContext.Provider>\n );\n};\n\n// ===== Player Provider =====\n\ninterface PlayerRoomProviderProps {\n roomCode: string;\n players: Player[];\n leaderId: string | null;\n mySessionId: string;\n isLeader: boolean;\n socket: Socket;\n isConnected: boolean;\n children: React.ReactNode;\n}\n\nexport const PlayerRoomProvider: React.FC<PlayerRoomProviderProps> = ({\n roomCode,\n players,\n leaderId,\n mySessionId,\n isLeader,\n socket,\n isConnected,\n children,\n}) => {\n const connectedPlayers = useMemo(\n () => players.filter((p) => p.connected !== false),\n [players]\n );\n\n const playerState: PlayerRoomState = useMemo(\n () => ({\n roomCode,\n players,\n connectedPlayers,\n leaderId,\n mySessionId,\n isLeader,\n socket,\n isConnected,\n }),\n [roomCode, players, connectedPlayers, leaderId, mySessionId, isLeader, socket, isConnected]\n );\n\n const value: RoomContextValue = useMemo(\n () => ({\n roomCode,\n players,\n connectedPlayers,\n leaderId,\n side: 'player' as const,\n host: null,\n player: playerState,\n }),\n [roomCode, players, connectedPlayers, leaderId, playerState]\n );\n\n const transport = useMemo(() => new DirectTransport(socket), [socket]);\n\n return (\n <TransportContext.Provider value={transport}>\n <RoomContext.Provider value={value}>{children}</RoomContext.Provider>\n </TransportContext.Provider>\n );\n};\n\n// ===== Hooks =====\n\nexport function useRoom(): RoomContextValue {\n const context = useContext(RoomContext);\n if (!context) {\n throw new Error('useRoom must be used within HostRoomProvider or PlayerRoomProvider');\n }\n return context;\n}\n\nexport function useHostRoom(): HostRoomState {\n const context = useRoom();\n if (context.side !== 'host' || !context.host) {\n throw new Error('useHostRoom must be used within HostRoomProvider');\n }\n return context.host;\n}\n\nexport function usePlayerRoom(): PlayerRoomState {\n const context = useRoom();\n if (context.side !== 'player' || !context.player) {\n throw new Error('usePlayerRoom must be used within PlayerRoomProvider');\n }\n return context.player;\n}\n"],"names":["createContext","useContext","useMemo","DirectTransport","jsx"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ function useExternalGames(config) {
6
+ const { serverUrl, enabled = true } = config;
7
+ const [games, setGames] = react.useState([]);
8
+ const [loading, setLoading] = react.useState(false);
9
+ const [error, setError] = react.useState(null);
10
+ const [refreshKey, setRefreshKey] = react.useState(0);
11
+ react.useEffect(() => {
12
+ if (!enabled) return;
13
+ let cancelled = false;
14
+ setLoading(true);
15
+ fetch(`${serverUrl}/api/games`).then((res) => res.json()).then((data) => {
16
+ if (cancelled) return;
17
+ const external = (data.games || []).map((g) => ({
18
+ id: g.id,
19
+ title: g.title,
20
+ description: g.description || "",
21
+ minPlayers: g.minPlayers || 2,
22
+ maxPlayers: g.maxPlayers || 8,
23
+ thumbnail: g.thumbnail || "/thumbnails/g8.jpeg",
24
+ categories: g.categories || ["party"],
25
+ type: "external",
26
+ hostUrl: g.hostUrl,
27
+ playerUrl: g.playerUrl,
28
+ available: !!(g.hostUrl && g.playerUrl),
29
+ rating: 4,
30
+ heroRequired: false
31
+ }));
32
+ setGames(external);
33
+ setError(null);
34
+ }).catch((err) => {
35
+ if (cancelled) return;
36
+ setError(err.message);
37
+ }).finally(() => {
38
+ if (!cancelled) setLoading(false);
39
+ });
40
+ return () => {
41
+ cancelled = true;
42
+ };
43
+ }, [serverUrl, enabled, refreshKey]);
44
+ const refresh = () => setRefreshKey((k) => k + 1);
45
+ return { games, loading, error, refresh };
46
+ }
47
+
48
+ exports.useExternalGames = useExternalGames;
49
+ //# sourceMappingURL=useExternalGames.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useExternalGames.cjs","sources":["../../../src/hooks/useExternalGames.ts"],"sourcesContent":["/**\n * useExternalGames - Fetches external games from the server API.\n *\n * Returns a list of GameMetadata-compatible objects for external (iframe) games.\n * Consumers merge this with their local GAMES array.\n */\n\nimport { useState, useEffect } from 'react';\n\nexport interface ExternalGameMetadata {\n id: string;\n title: string;\n description: string;\n minPlayers: number;\n maxPlayers: number;\n thumbnail: string;\n categories: string[];\n type: 'external';\n hostUrl: string | null;\n playerUrl: string | null;\n available: boolean;\n rating: number;\n heroRequired: boolean;\n}\n\nexport interface UseExternalGamesConfig {\n serverUrl: string;\n enabled?: boolean;\n}\n\nexport function useExternalGames(config: UseExternalGamesConfig): {\n games: ExternalGameMetadata[];\n loading: boolean;\n error: string | null;\n refresh: () => void;\n} {\n const { serverUrl, enabled = true } = config;\n const [games, setGames] = useState<ExternalGameMetadata[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [refreshKey, setRefreshKey] = useState(0);\n\n useEffect(() => {\n if (!enabled) return;\n\n let cancelled = false;\n setLoading(true);\n\n fetch(`${serverUrl}/api/games`)\n .then((res) => res.json())\n .then((data) => {\n if (cancelled) return;\n const external: ExternalGameMetadata[] = (data.games || []).map((g: any) => ({\n id: g.id,\n title: g.title,\n description: g.description || '',\n minPlayers: g.minPlayers || 2,\n maxPlayers: g.maxPlayers || 8,\n thumbnail: g.thumbnail || '/thumbnails/g8.jpeg',\n categories: g.categories || ['party'],\n type: 'external' as const,\n hostUrl: g.hostUrl,\n playerUrl: g.playerUrl,\n available: !!(g.hostUrl && g.playerUrl),\n rating: 4.0,\n heroRequired: false,\n }));\n setGames(external);\n setError(null);\n })\n .catch((err) => {\n if (cancelled) return;\n setError(err.message);\n })\n .finally(() => {\n if (!cancelled) setLoading(false);\n });\n\n return () => { cancelled = true; };\n }, [serverUrl, enabled, refreshKey]);\n\n const refresh = () => setRefreshKey((k) => k + 1);\n\n return { games, loading, error, refresh };\n}\n"],"names":["useState","useEffect"],"mappings":";;;;AA8BO,SAAS,iBAAiB,MAAA,EAK/B;AACA,EAAA,MAAM,EAAE,SAAA,EAAW,OAAA,GAAU,IAAA,EAAK,GAAI,MAAA;AACtC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,cAAA,CAAiC,EAAE,CAAA;AAC7D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAwB,IAAI,CAAA;AACtD,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,eAAS,CAAC,CAAA;AAE9C,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,UAAA,CAAW,IAAI,CAAA;AAEf,IAAA,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA,UAAA,CAAY,CAAA,CAC3B,IAAA,CAAK,CAAC,GAAA,KAAQ,GAAA,CAAI,IAAA,EAAM,CAAA,CACxB,IAAA,CAAK,CAAC,IAAA,KAAS;AACd,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,MAAM,YAAoC,IAAA,CAAK,KAAA,IAAS,EAAC,EAAG,GAAA,CAAI,CAAC,CAAA,MAAY;AAAA,QAC3E,IAAI,CAAA,CAAE,EAAA;AAAA,QACN,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,WAAA,EAAa,EAAE,WAAA,IAAe,EAAA;AAAA,QAC9B,UAAA,EAAY,EAAE,UAAA,IAAc,CAAA;AAAA,QAC5B,UAAA,EAAY,EAAE,UAAA,IAAc,CAAA;AAAA,QAC5B,SAAA,EAAW,EAAE,SAAA,IAAa,qBAAA;AAAA,QAC1B,UAAA,EAAY,CAAA,CAAE,UAAA,IAAc,CAAC,OAAO,CAAA;AAAA,QACpC,IAAA,EAAM,UAAA;AAAA,QACN,SAAS,CAAA,CAAE,OAAA;AAAA,QACX,WAAW,CAAA,CAAE,SAAA;AAAA,QACb,SAAA,EAAW,CAAC,EAAE,CAAA,CAAE,WAAW,CAAA,CAAE,SAAA,CAAA;AAAA,QAC7B,MAAA,EAAQ,CAAA;AAAA,QACR,YAAA,EAAc;AAAA,OAChB,CAAE,CAAA;AACF,MAAA,QAAA,CAAS,QAAQ,CAAA;AACjB,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAQ;AACd,MAAA,IAAI,SAAA,EAAW;AACf,MAAA,QAAA,CAAS,IAAI,OAAO,CAAA;AAAA,IACtB,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,CAAC,SAAA,EAAW,UAAA,CAAW,KAAK,CAAA;AAAA,IAClC,CAAC,CAAA;AAEH,IAAA,OAAO,MAAM;AAAE,MAAA,SAAA,GAAY,IAAA;AAAA,IAAM,CAAA;AAAA,EACnC,CAAA,EAAG,CAAC,SAAA,EAAW,OAAA,EAAS,UAAU,CAAC,CAAA;AAEnC,EAAA,MAAM,UAAU,MAAM,aAAA,CAAc,CAAC,CAAA,KAAM,IAAI,CAAC,CAAA;AAEhD,EAAA,OAAO,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,OAAA,EAAQ;AAC1C;;;;"}