@puzzmo/sdk 1.0.15 → 1.0.17

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 (39) hide show
  1. package/README.md +33 -0
  2. package/dist/{createSimulator-IMuPxYe-.js → createSimulator-BwucCTnM.js} +174 -25
  3. package/dist/createSimulator-BwucCTnM.js.map +1 -0
  4. package/dist/{createSimulator-CGTMmToi.cjs → createSimulator-HQPoM1pd.cjs} +85 -4
  5. package/dist/createSimulator-HQPoM1pd.cjs.map +1 -0
  6. package/dist/fonts.cjs +3 -0
  7. package/dist/fonts.cjs.map +1 -0
  8. package/dist/fonts.d.ts +26 -0
  9. package/dist/fonts.d.ts.map +1 -0
  10. package/dist/fonts.js +29 -0
  11. package/dist/fonts.js.map +1 -0
  12. package/dist/simulator/createSimulator.d.ts +11 -14
  13. package/dist/simulator/createSimulator.d.ts.map +1 -1
  14. package/dist/simulator/index.cjs +1 -1
  15. package/dist/simulator/index.js +1 -1
  16. package/dist/simulator/standalone.cjs +1 -1
  17. package/dist/simulator/standalone.js +1 -1
  18. package/dist/simulator/styles.d.ts +1 -1
  19. package/dist/simulator/styles.d.ts.map +1 -1
  20. package/dist/simulator/views/AuthView.d.ts.map +1 -1
  21. package/dist/simulator/views/KeyboardView.d.ts +3 -0
  22. package/dist/simulator/views/KeyboardView.d.ts.map +1 -0
  23. package/dist/simulator/views/index.d.ts +1 -0
  24. package/dist/simulator/views/index.d.ts.map +1 -1
  25. package/dist/svgJSX.cjs +2 -0
  26. package/dist/svgJSX.cjs.map +1 -0
  27. package/dist/svgJSX.d.ts +16 -0
  28. package/dist/svgJSX.d.ts.map +1 -0
  29. package/dist/svgJSX.js +60 -0
  30. package/dist/svgJSX.js.map +1 -0
  31. package/dist/vite.cjs +3 -3
  32. package/dist/vite.cjs.map +1 -1
  33. package/dist/vite.d.ts +18 -4
  34. package/dist/vite.d.ts.map +1 -1
  35. package/dist/vite.js +91 -47
  36. package/dist/vite.js.map +1 -1
  37. package/package.json +12 -1
  38. package/dist/createSimulator-CGTMmToi.cjs.map +0 -1
  39. package/dist/createSimulator-IMuPxYe-.js.map +0 -1
@@ -1,3 +1,10 @@
1
+ import type { SimulatorConfig, FixtureImports } from "./types";
2
+ export type { SimulatorConfig, FixtureImports };
3
+ interface SimulatorInstance {
4
+ updateFixtures: (fixtures: FixtureImports) => void;
5
+ sendToGame: (type: any, data: any) => void;
6
+ loadPuzzle: () => Promise<any>;
7
+ }
1
8
  /**
2
9
  * Simulator - A development UI for testing games with the Puzzmo Proto SDK.
3
10
  *
@@ -12,10 +19,12 @@
12
19
  * // vite.config.ts
13
20
  * import { puzzmoSimulator } from "@puzzmo/sdk/vite"
14
21
  * export default defineConfig({
15
- * plugins: [puzzmoSimulator({ slug: "my-game", fixturesGlob: "/fixtures/puzzles/**\/*.json" })]
22
+ * plugins: [puzzmoSimulator({})]
16
23
  * })
17
24
  * ```
18
25
  *
26
+ * The plugin automatically reads the game slug from the nearest puzzmo.json.
27
+ *
19
28
  * The plugin handles making sure it is removed on vite builds.
20
29
  *
21
30
  * Usage with manual imports:
@@ -29,17 +38,5 @@
29
38
  * The fixtures folder structure should be: fixtures/puzzles/{category}/{puzzle}.json
30
39
  * This will show dropdowns in the Ctrl tab to select category and puzzle.
31
40
  */
32
- import type { SimulatorConfig, FixtureImports } from "./types";
33
- export type { SimulatorConfig, FixtureImports };
34
- interface SimulatorInstance {
35
- updateFixtures: (fixtures: FixtureImports) => void;
36
- sendToGame: (type: any, data: any) => void;
37
- loadPuzzle: () => Promise<any>;
38
- }
39
- /**
40
- * Creates the Simulator UI and message handling.
41
- * If called multiple times, updates the existing instance with new settings (e.g., fixtures).
42
- */
43
- declare function createSimulator(config?: SimulatorConfig): SimulatorInstance;
44
- export { createSimulator };
41
+ export declare function createSimulator(config?: SimulatorConfig): SimulatorInstance;
45
42
  //# sourceMappingURL=createSimulator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createSimulator.d.ts","sourceRoot":"","sources":["../../src/simulator/createSimulator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EAAE,eAAe,EAA4D,cAAc,EAAE,MAAM,SAAS,CAAA;AAkBxH,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,CAAA;AAG/C,UAAU,iBAAiB;IACzB,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAA;IAClD,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1C,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;CAC/B;AAGD;;;GAGG;AACH,iBAAS,eAAe,CAAC,MAAM,GAAE,eAAoB,GAAG,iBAAiB,CAsgBxE;AAED,OAAO,EAAE,eAAe,EAAE,CAAA"}
1
+ {"version":3,"file":"createSimulator.d.ts","sourceRoot":"","sources":["../../src/simulator/createSimulator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAA4D,cAAc,EAAE,MAAM,SAAS,CAAA;AAmBxH,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,CAAA;AAG/C,UAAU,iBAAiB;IACzB,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAA;IAClD,UAAU,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;IAC1C,UAAU,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;CAC/B;AAGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,wBAAgB,eAAe,CAAC,MAAM,GAAE,eAAoB,GAAG,iBAAiB,CAugB/E"}
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../createSimulator-CGTMmToi.cjs`);exports.createSimulator=e.t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`../createSimulator-HQPoM1pd.cjs`);exports.createSimulator=e.t;
@@ -1,2 +1,2 @@
1
- import { t as e } from "../createSimulator-IMuPxYe-.js";
1
+ import { t as e } from "../createSimulator-BwucCTnM.js";
2
2
  export { e as createSimulator };
@@ -1,2 +1,2 @@
1
- const e=require(`../createSimulator-CGTMmToi.cjs`);var t=()=>{var t;e.t((t=window.SIMULATOR_CONFIG)==null?{}:t)};document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,t):t();
1
+ const e=require(`../createSimulator-HQPoM1pd.cjs`);var t=()=>{var t;e.t((t=window.SIMULATOR_CONFIG)==null?{}:t)};document.readyState===`loading`?document.addEventListener(`DOMContentLoaded`,t):t();
2
2
  //# sourceMappingURL=standalone.cjs.map
@@ -1,4 +1,4 @@
1
- import { t as e } from "../createSimulator-IMuPxYe-.js";
1
+ import { t as e } from "../createSimulator-BwucCTnM.js";
2
2
  /**
3
3
  * Standalone entry point for the simulator.
4
4
  *
@@ -1,2 +1,2 @@
1
- export declare const simulatorStyles = "\n :root {\n --sim-bg: #1a1a2e;\n --sim-bg-alt: #16213e;\n --sim-panel: #0f0f1a;\n --sim-border: #3a3a5c;\n --sim-border-light: #5a5a8c;\n --sim-accent: #ffd700;\n --sim-accent-hover: #ffed4a;\n --sim-text: #e8e8e8;\n --sim-text-dim: #888899;\n --sim-success: #4ade80;\n --sim-error: #f87171;\n --sim-warning: #fbbf24;\n --sim-blue: #60a5fa;\n }\n #simulator {\n position: fixed;\n bottom: 4px;\n left: 4px;\n z-index: 999999;\n font: 11px/1.4 \"Menlo\", \"Monaco\", \"Consolas\", monospace;\n user-select: none;\n }\n #simulator-panel {\n background: var(--sim-panel);\n border: 2px solid var(--sim-border);\n border-radius: 4px;\n color: var(--sim-text);\n width: 420px;\n box-shadow: 4px 4px 0 rgba(0,0,0,0.5);\n }\n #simulator-panel.collapsed {\n width: auto;\n }\n #simulator-header {\n display: flex;\n align-items: center;\n padding: 4px 8px;\n background: var(--sim-bg);\n border-bottom: 2px solid var(--sim-border);\n gap: 0;\n }\n #simulator-panel.collapsed #simulator-header {\n border-bottom: none;\n cursor: pointer;\n }\n #simulator-panel.collapsed #simulator-header:hover {\n background: var(--sim-bg-alt);\n }\n .header-sep {\n color: var(--sim-border-light);\n margin: 0 8px;\n opacity: 0.6;\n }\n .header-spacer {\n flex: 1;\n }\n #simulator-title {\n color: var(--sim-accent);\n text-transform: uppercase;\n letter-spacing: 1px;\n font-size: 10px;\n font-weight: bold;\n }\n #simulator-header-controls {\n display: flex;\n gap: 2px;\n }\n .header-icon-btn {\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 2px;\n color: var(--sim-text);\n cursor: pointer;\n padding: 0;\n }\n .header-icon-btn:hover:not(:disabled) {\n background: var(--sim-border);\n color: var(--sim-accent);\n }\n .header-icon-btn:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n .header-icon-btn.active {\n background: var(--sim-accent);\n color: var(--sim-panel);\n }\n #simulator-header-status {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 9px;\n color: var(--sim-text-dim);\n }\n #simulator-header-indicator {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sim-text-dim);\n flex-shrink: 0;\n }\n #simulator-header-indicator.ready {\n background: var(--sim-success);\n box-shadow: 0 0 4px var(--sim-success);\n }\n #simulator-header-indicator.waiting {\n background: var(--sim-warning);\n box-shadow: 0 0 4px var(--sim-warning);\n }\n #simulator-header-indicator.paused {\n background: var(--sim-error);\n box-shadow: 0 0 4px var(--sim-error);\n }\n #simulator-timer {\n font-size: 11px;\n color: var(--sim-text);\n font-family: \"Menlo\", monospace;\n font-weight: bold;\n font-variant-numeric: tabular-nums;\n min-width: 38px;\n }\n #simulator-timer .penalty {\n color: var(--sim-error);\n margin-left: 2px;\n }\n /* Collapsed state - show minimal bar */\n #simulator-panel.collapsed .header-sep,\n #simulator-panel.collapsed #simulator-header-controls,\n #simulator-panel.collapsed #simulator-header-status,\n #simulator-panel.collapsed #simulator-header-settings,\n #simulator-panel.collapsed #simulator-toggle {\n display: none;\n }\n #simulator-panel.collapsed #simulator-title {\n cursor: pointer;\n }\n #simulator-panel.collapsed #simulator-timer {\n margin-left: 8px;\n }\n #simulator-body {\n display: flex;\n flex-direction: row;\n }\n #simulator-panel.collapsed #simulator-body {\n display: none;\n }\n #simulator-tabs {\n display: flex;\n flex-direction: column;\n background: var(--sim-bg);\n padding: 4px;\n gap: 2px;\n border-right: 2px solid var(--sim-border);\n }\n .simulator-tab {\n padding: 2px 3px;\n background: var(--sim-bg-alt);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text-dim);\n cursor: pointer;\n font: inherit;\n text-transform: uppercase;\n font-size: 9px;\n font-weight: bold;\n letter-spacing: 0.5px;\n min-height: 0;\n }\n .simulator-tab:hover {\n color: var(--sim-text);\n background: var(--sim-border);\n }\n .simulator-tab.active {\n color: var(--sim-panel);\n background: var(--sim-accent);\n border-color: var(--sim-accent);\n }\n .simulator-tab {\n position: relative;\n }\n .simulator-tab-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 14px;\n height: 14px;\n padding: 0 3px;\n background: var(--sim-blue);\n color: #fff;\n font-size: 8px;\n font-weight: bold;\n border-radius: 7px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 2px rgba(0,0,0,0.3);\n line-height: 1;\n text-align: center;\n box-sizing: border-box;\n }\n .simulator-tab-badge:empty {\n display: none;\n }\n #simulator-content {\n padding: 6px;\n background: var(--sim-panel);\n height: 500px;\n flex: 1;\n overflow-y: auto;\n }\n #simulator-content.hidden {\n display: none;\n }\n #simulator-content::-webkit-scrollbar {\n width: 8px;\n }\n #simulator-content::-webkit-scrollbar-track {\n background: var(--sim-bg);\n }\n #simulator-content::-webkit-scrollbar-thumb {\n background: var(--sim-border);\n border-radius: 2px;\n }\n .simulator-btn {\n padding: 4px 8px;\n background: var(--sim-bg-alt);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: inherit;\n font-size: 10px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 1px;\n cursor: pointer;\n }\n .simulator-btn:hover {\n background: var(--sim-border);\n border-color: var(--sim-border-light);\n }\n .simulator-btn:active {\n transform: translate(1px, 1px);\n }\n .simulator-btn.primary {\n background: var(--sim-accent);\n border-color: var(--sim-accent);\n color: var(--sim-panel);\n }\n .simulator-btn.primary:hover {\n background: var(--sim-accent-hover);\n border-color: var(--sim-accent-hover);\n }\n .simulator-btn.danger {\n background: var(--sim-error);\n border-color: var(--sim-error);\n color: #fff;\n }\n .simulator-btn.danger:hover {\n background: #ef4444;\n border-color: #ef4444;\n }\n .simulator-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n transform: none;\n }\n .simulator-btn.subtle {\n background: transparent;\n border-color: transparent;\n color: var(--sim-text-dim);\n }\n .simulator-btn.subtle:hover:not(:disabled) {\n background: var(--sim-bg-alt);\n border-color: var(--sim-border);\n color: var(--sim-text);\n }\n #simulator-status {\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 4px 0 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n #simulator-status .indicator {\n width: 8px;\n height: 8px;\n border-radius: 2px;\n background: var(--sim-text-dim);\n }\n #simulator-status .indicator.ready {\n background: var(--sim-success);\n box-shadow: 0 0 6px var(--sim-success);\n }\n #simulator-status .indicator.waiting {\n background: var(--sim-warning);\n box-shadow: 0 0 6px var(--sim-warning);\n }\n #simulator-status .indicator.paused {\n background: var(--sim-error);\n box-shadow: 0 0 6px var(--sim-error);\n }\n .simulator-row {\n display: flex;\n gap: 4px;\n margin-top: 4px;\n }\n .simulator-row .simulator-btn {\n flex: 1;\n }\n .simulator-divider {\n height: 2px;\n background: var(--sim-border);\n margin: 8px 0;\n }\n .simulator-field {\n margin-bottom: 6px;\n }\n .simulator-select {\n width: 100%;\n padding: 4px 6px;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: inherit;\n font-size: 10px;\n cursor: pointer;\n }\n .simulator-select:focus {\n outline: none;\n border-color: var(--sim-accent);\n }\n .simulator-select option {\n background: var(--sim-bg);\n color: var(--sim-text);\n }\n .simulator-fixtures {\n margin-bottom: 8px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--sim-border);\n }\n .simulator-label {\n display: block;\n color: var(--sim-accent);\n text-transform: uppercase;\n font-size: 9px;\n font-weight: bold;\n letter-spacing: 1px;\n margin-bottom: 4px;\n }\n .simulator-textarea {\n width: 100%;\n min-height: 40px;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: 10px/1.4 \"Menlo\", monospace;\n padding: 4px;\n resize: none;\n box-sizing: border-box;\n overflow-y: auto;\n }\n .simulator-textarea.auto-resize {\n resize: none;\n overflow-y: auto;\n }\n .simulator-textarea:focus {\n outline: none;\n border-color: var(--sim-accent);\n }\n .simulator-input {\n width: 100%;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: 10px/1.4 \"Menlo\", monospace;\n padding: 4px 6px;\n box-sizing: border-box;\n }\n .simulator-input:focus {\n outline: none;\n border-color: var(--sim-accent);\n }\n .simulator-input::placeholder {\n color: var(--sim-text-dim);\n }\n .simulator-tab-content {\n display: none;\n }\n .simulator-tab-content.active {\n display: block;\n }\n .msgs-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .msgs-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n #simulator-msgs-log {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1;\n overflow-y: auto;\n }\n .simulator-msg {\n padding: 3px 4px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n font-size: 10px;\n }\n .simulator-msg.out {\n border-left: 2px solid var(--sim-accent);\n }\n .simulator-msg.in {\n border-left: 2px solid var(--sim-blue);\n }\n .simulator-msg-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 2px;\n }\n .simulator-msg-type {\n font-weight: bold;\n color: var(--sim-text);\n }\n .simulator-msg.out .simulator-msg-type {\n color: var(--sim-accent);\n }\n .simulator-msg.in .simulator-msg-type {\n color: var(--sim-blue);\n }\n .simulator-msg-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n }\n .simulator-msg-data {\n color: var(--sim-text-dim);\n font-size: 9px;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 60px;\n overflow: hidden;\n cursor: pointer;\n border-radius: 2px;\n padding: 2px 4px;\n background: var(--sim-bg-alt);\n }\n .simulator-msg-data:hover {\n background: var(--sim-border);\n }\n .simulator-msg.expanded {\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n .simulator-msg.expanded .simulator-msg-data {\n max-height: none;\n flex: 1;\n overflow-y: auto;\n }\n .simulator-empty {\n color: var(--sim-text-dim);\n font-size: 10px;\n text-align: center;\n padding: 20px;\n }\n .simulator-value {\n color: var(--sim-text);\n font-size: 10px;\n padding: 4px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n }\n .simulator-deeds {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .simulator-deed {\n display: flex;\n justify-content: space-between;\n padding: 3px 4px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n font-size: 10px;\n }\n .simulator-deed-name {\n color: var(--sim-text);\n }\n .simulator-deed-value {\n color: var(--sim-accent);\n font-weight: bold;\n }\n .thumb-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .thumb-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n #simulator-thumb-preview {\n background: var(--sim-thumb-bg, transparent);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n aspect-ratio: 1;\n width: 100%;\n box-sizing: border-box;\n }\n #simulator-thumb-preview svg {\n width: 100%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n }\n #simulator-thumb-fn {\n font-size: 10px;\n color: var(--sim-text-dim);\n margin-top: 4px;\n }\n .theme-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .theme-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n .simulator-themes {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .simulator-theme-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n cursor: pointer;\n }\n .simulator-theme-item:hover {\n border-color: var(--sim-border-light);\n }\n .simulator-theme-item.selected {\n border-color: var(--sim-accent);\n background: var(--sim-bg-alt);\n }\n .simulator-theme-preview {\n width: 48px;\n height: 32px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-template-rows: repeat(2, 1fr);\n gap: 1px;\n border-radius: 2px;\n overflow: hidden;\n flex-shrink: 0;\n }\n .simulator-theme-preview-cell {\n width: 100%;\n height: 100%;\n }\n .simulator-theme-name {\n font-size: 10px;\n color: var(--sim-text);\n flex: 1;\n }\n .simulator-theme-type {\n font-size: 9px;\n color: var(--sim-text-dim);\n text-transform: uppercase;\n }\n /* Auth tab styles */\n .simulator-section {\n margin-bottom: 12px;\n }\n .simulator-section-title {\n color: var(--sim-accent);\n text-transform: uppercase;\n font-size: 10px;\n font-weight: bold;\n letter-spacing: 1px;\n margin-bottom: 6px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--sim-border);\n }\n .auth-header-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n }\n .auth-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 4px 0;\n }\n .auth-status.authenticated {\n color: var(--sim-success);\n }\n .simulator-btn.small {\n padding: 2px 6px;\n font-size: 9px;\n }\n .simulator-btn.tiny {\n padding: 3px 2px;\n font-size: 8px;\n border-width: 1px;\n line-height: 1;\n min-height: 0;\n height: auto;\n }\n .auth-title-row {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .auth-title-row > span:first-child {\n flex: 1;\n }\n .auth-title-row .simulator-btn.active {\n background: var(--sim-accent);\n color: black;\n }\n .auth-description {\n font-size: 10px;\n color: var(--sim-text-dim);\n margin: 6px 0;\n line-height: 1.4;\n }\n .auth-user-info {\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n margin-bottom: 8px;\n }\n .auth-user-info div {\n margin-bottom: 4px;\n }\n .auth-user-info div:last-child {\n margin-bottom: 0;\n }\n .auth-user-info code {\n color: var(--sim-text);\n background: var(--sim-bg-alt);\n padding: 1px 4px;\n border-radius: 2px;\n }\n .auth-warning {\n color: var(--sim-warning);\n font-style: italic;\n }\n .auth-error {\n margin-top: 8px;\n }\n .auth-error .error,\n .auth-api-result .error {\n color: var(--sim-error);\n font-size: 10px;\n padding: 6px;\n background: rgba(248, 113, 113, 0.1);\n border: 1px solid var(--sim-error);\n border-radius: 2px;\n }\n .auth-api-result {\n margin-top: 8px;\n }\n .auth-api-result pre {\n font-size: 9px;\n color: var(--sim-text);\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n padding: 6px;\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 150px;\n overflow-y: auto;\n }\n .auth-api-result .loading {\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n }\n /* Data view styles */\n .data-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .data-subtabs {\n display: flex;\n gap: 2px;\n margin-bottom: 8px;\n flex-shrink: 0;\n }\n .data-subtab {\n padding: 4px 10px;\n background: var(--sim-bg-alt);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text-dim);\n cursor: pointer;\n font: inherit;\n font-size: 9px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .data-subtab:hover {\n color: var(--sim-text);\n background: var(--sim-border);\n }\n .data-subtab.active {\n color: var(--sim-panel);\n background: var(--sim-accent);\n border-color: var(--sim-accent);\n }\n .data-subtab-content {\n display: none;\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n }\n .data-subtab-content.active {\n display: flex;\n flex-direction: column;\n }\n /* History tab styles */\n .history-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n .history-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .history-item {\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n display: flex;\n flex-direction: row;\n gap: 8px;\n }\n .history-item:hover {\n border-color: var(--sim-border-light);\n }\n .history-item-thumb {\n width: 80px;\n height: 80px;\n flex-shrink: 0;\n background: var(--history-thumb-bg, var(--sim-bg-alt));\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n }\n .history-item-thumb svg {\n width: 100%;\n height: 100%;\n }\n .history-item-thumb:empty {\n display: none;\n }\n .history-item-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n .history-item-header {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .history-item-num {\n color: var(--sim-accent);\n font-weight: bold;\n font-size: 9px;\n }\n .history-item-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n flex: 1;\n }\n .history-item-preview {\n font-size: 9px;\n color: var(--sim-text);\n word-break: break-all;\n line-height: 1.3;\n background: var(--sim-bg-alt);\n padding: 3px 4px;\n border-radius: 2px;\n flex: 1;\n overflow: hidden;\n }\n /* Saves tab styles */\n .save-new {\n display: flex;\n gap: 4px;\n margin-bottom: 8px;\n flex-shrink: 0;\n }\n .save-new .simulator-input {\n flex: 1;\n }\n .saves-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .save-item {\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n }\n .save-item:hover {\n border-color: var(--sim-border-light);\n }\n .save-item-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n }\n .save-item-name {\n color: var(--sim-text);\n font-weight: bold;\n font-size: 10px;\n }\n .save-item-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n }\n .save-item-actions {\n display: flex;\n gap: 4px;\n }\n /* Features view styles */\n .features-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .features-slug-input {\n display: flex;\n gap: 4px;\n margin-bottom: 8px;\n }\n .features-slug-input .simulator-input {\n flex: 1;\n }\n .features-content {\n flex: 1;\n overflow-y: auto;\n }\n .features-loading {\n color: var(--sim-text-dim);\n font-size: 10px;\n text-align: center;\n padding: 20px;\n }\n .features-error {\n color: var(--sim-error);\n font-size: 10px;\n padding: 8px;\n background: rgba(248, 113, 113, 0.1);\n border: 1px solid var(--sim-error);\n border-radius: 2px;\n }\n .features-empty {\n color: var(--sim-text-dim);\n font-size: 10px;\n text-align: center;\n padding: 20px;\n }\n .features-auth-required {\n color: var(--sim-text-dim);\n font-size: 10px;\n padding: 12px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n line-height: 1.5;\n }\n .features-auth-required p {\n margin: 0 0 8px 0;\n }\n .features-auth-required p:last-child {\n margin-bottom: 0;\n }\n .features-game-name {\n color: var(--sim-accent);\n font-size: 11px;\n font-weight: bold;\n margin-bottom: 8px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--sim-border);\n }\n .feature-group {\n margin-bottom: 12px;\n }\n .feature-group-title {\n color: var(--sim-text);\n font-size: 10px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n padding-bottom: 2px;\n border-bottom: 1px solid var(--sim-border);\n }\n .feature-group-items {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .feature-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .feature-item:hover {\n border-color: var(--sim-border-light);\n background: var(--sim-bg-alt);\n }\n .feature-item.updating {\n opacity: 0.5;\n pointer-events: none;\n }\n .feature-status {\n font-size: 14px;\n width: 18px;\n text-align: center;\n flex-shrink: 0;\n }\n .feature-item.enabled .feature-status {\n color: var(--sim-success);\n }\n .feature-item.disabled .feature-status {\n color: var(--sim-error);\n opacity: 0.5;\n }\n .feature-title {\n font-size: 10px;\n color: var(--sim-text);\n flex: 1;\n }\n .feature-item.disabled .feature-title {\n color: var(--sim-text-dim);\n }\n /* Checkpoints view styles */\n .checkpoints-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .checkpoints-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n .checkpoints-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .checkpoint-item {\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-left: 3px solid var(--sim-accent);\n border-radius: 2px;\n }\n .checkpoint-item:hover {\n border-color: var(--sim-border-light);\n border-left-color: var(--sim-accent);\n }\n .checkpoint-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .checkpoint-item .simulator-deeds {\n margin-top: 4px;\n }\n .checkpoint-name {\n color: var(--sim-accent);\n font-weight: bold;\n font-size: 10px;\n }\n .checkpoint-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n }\n";
1
+ export declare const simulatorStyles = "\n :root {\n --sim-bg: #1a1a2e;\n --sim-bg-alt: #16213e;\n --sim-panel: #0f0f1a;\n --sim-border: #3a3a5c;\n --sim-border-light: #5a5a8c;\n --sim-accent: #ffd700;\n --sim-accent-hover: #ffed4a;\n --sim-text: #e8e8e8;\n --sim-text-dim: #888899;\n --sim-success: #4ade80;\n --sim-error: #f87171;\n --sim-warning: #fbbf24;\n --sim-blue: #60a5fa;\n }\n #simulator {\n position: fixed;\n bottom: 4px;\n left: 4px;\n z-index: 999999;\n font: 11px/1.4 \"Menlo\", \"Monaco\", \"Consolas\", monospace;\n user-select: none;\n }\n #simulator-panel {\n background: var(--sim-panel);\n border: 2px solid var(--sim-border);\n border-radius: 4px;\n color: var(--sim-text);\n width: 420px;\n max-width: calc(100vw - 8px);\n box-shadow: 4px 4px 0 rgba(0,0,0,0.5);\n }\n #simulator-panel.collapsed {\n width: auto;\n }\n #simulator-header {\n display: flex;\n align-items: center;\n padding: 4px 8px;\n background: var(--sim-bg);\n border-bottom: 2px solid var(--sim-border);\n gap: 0;\n }\n #simulator-panel.collapsed #simulator-header {\n border-bottom: none;\n cursor: pointer;\n }\n #simulator-panel.collapsed #simulator-header:hover {\n background: var(--sim-bg-alt);\n }\n .header-sep {\n color: var(--sim-border-light);\n margin: 0 8px;\n opacity: 0.6;\n }\n .header-spacer {\n flex: 1;\n }\n #simulator-title {\n color: var(--sim-accent);\n text-transform: uppercase;\n letter-spacing: 1px;\n font-size: 10px;\n font-weight: bold;\n }\n #simulator-header-controls {\n display: flex;\n gap: 2px;\n }\n .header-icon-btn {\n width: 20px;\n height: 20px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: none;\n border-radius: 2px;\n color: var(--sim-text);\n cursor: pointer;\n padding: 0;\n }\n .header-icon-btn:hover:not(:disabled) {\n background: var(--sim-border);\n color: var(--sim-accent);\n }\n .header-icon-btn:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n .header-icon-btn.active {\n background: var(--sim-accent);\n color: var(--sim-panel);\n }\n #simulator-header-status {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 9px;\n color: var(--sim-text-dim);\n }\n #simulator-header-indicator {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--sim-text-dim);\n flex-shrink: 0;\n }\n #simulator-header-indicator.ready {\n background: var(--sim-success);\n box-shadow: 0 0 4px var(--sim-success);\n }\n #simulator-header-indicator.waiting {\n background: var(--sim-warning);\n box-shadow: 0 0 4px var(--sim-warning);\n }\n #simulator-header-indicator.paused {\n background: var(--sim-error);\n box-shadow: 0 0 4px var(--sim-error);\n }\n #simulator-timer {\n font-size: 11px;\n color: var(--sim-text);\n font-family: \"Menlo\", monospace;\n font-weight: bold;\n font-variant-numeric: tabular-nums;\n min-width: 38px;\n }\n #simulator-timer .penalty {\n color: var(--sim-error);\n margin-left: 2px;\n }\n /* Collapsed state - show minimal bar */\n #simulator-panel.collapsed .header-sep,\n #simulator-panel.collapsed #simulator-header-controls,\n #simulator-panel.collapsed #simulator-header-status,\n #simulator-panel.collapsed #simulator-header-settings,\n #simulator-panel.collapsed #simulator-toggle {\n display: none;\n }\n #simulator-panel.collapsed #simulator-title {\n cursor: pointer;\n }\n #simulator-panel.collapsed #simulator-timer {\n margin-left: 8px;\n }\n #simulator-body {\n display: flex;\n flex-direction: row;\n }\n #simulator-panel.collapsed #simulator-body {\n display: none;\n }\n #simulator-tabs {\n display: flex;\n flex-direction: column;\n background: var(--sim-bg);\n padding: 4px;\n gap: 2px;\n border-right: 2px solid var(--sim-border);\n }\n .simulator-tab {\n padding: 2px 3px;\n background: var(--sim-bg-alt);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text-dim);\n cursor: pointer;\n font: inherit;\n text-transform: uppercase;\n font-size: 9px;\n font-weight: bold;\n letter-spacing: 0.5px;\n min-height: 0;\n }\n .simulator-tab:hover {\n color: var(--sim-text);\n background: var(--sim-border);\n }\n .simulator-tab.active {\n color: var(--sim-panel);\n background: var(--sim-accent);\n border-color: var(--sim-accent);\n }\n .simulator-tab {\n position: relative;\n }\n .simulator-tab-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 14px;\n height: 14px;\n padding: 0 3px;\n background: var(--sim-blue);\n color: #fff;\n font-size: 8px;\n font-weight: bold;\n border-radius: 7px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 1px 2px rgba(0,0,0,0.3);\n line-height: 1;\n text-align: center;\n box-sizing: border-box;\n }\n .simulator-tab-badge:empty {\n display: none;\n }\n #simulator-content {\n padding: 6px;\n background: var(--sim-panel);\n height: 500px;\n flex: 1;\n overflow-y: auto;\n }\n #simulator-content.hidden {\n display: none;\n }\n #simulator-content::-webkit-scrollbar {\n width: 8px;\n }\n #simulator-content::-webkit-scrollbar-track {\n background: var(--sim-bg);\n }\n #simulator-content::-webkit-scrollbar-thumb {\n background: var(--sim-border);\n border-radius: 2px;\n }\n .simulator-btn {\n padding: 4px 8px;\n background: var(--sim-bg-alt);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: inherit;\n font-size: 10px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 1px;\n cursor: pointer;\n }\n .simulator-btn:hover {\n background: var(--sim-border);\n border-color: var(--sim-border-light);\n }\n .simulator-btn:active {\n transform: translate(1px, 1px);\n }\n .simulator-btn.primary {\n background: var(--sim-accent);\n border-color: var(--sim-accent);\n color: var(--sim-panel);\n }\n .simulator-btn.primary:hover {\n background: var(--sim-accent-hover);\n border-color: var(--sim-accent-hover);\n }\n .simulator-btn.danger {\n background: var(--sim-error);\n border-color: var(--sim-error);\n color: #fff;\n }\n .simulator-btn.danger:hover {\n background: #ef4444;\n border-color: #ef4444;\n }\n .simulator-btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n transform: none;\n }\n .simulator-btn.subtle {\n background: transparent;\n border-color: transparent;\n color: var(--sim-text-dim);\n }\n .simulator-btn.subtle:hover:not(:disabled) {\n background: var(--sim-bg-alt);\n border-color: var(--sim-border);\n color: var(--sim-text);\n }\n #simulator-status {\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 4px 0 6px;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n #simulator-status .indicator {\n width: 8px;\n height: 8px;\n border-radius: 2px;\n background: var(--sim-text-dim);\n }\n #simulator-status .indicator.ready {\n background: var(--sim-success);\n box-shadow: 0 0 6px var(--sim-success);\n }\n #simulator-status .indicator.waiting {\n background: var(--sim-warning);\n box-shadow: 0 0 6px var(--sim-warning);\n }\n #simulator-status .indicator.paused {\n background: var(--sim-error);\n box-shadow: 0 0 6px var(--sim-error);\n }\n .simulator-row {\n display: flex;\n gap: 4px;\n margin-top: 4px;\n }\n .simulator-row .simulator-btn {\n flex: 1;\n }\n .simulator-divider {\n height: 2px;\n background: var(--sim-border);\n margin: 8px 0;\n }\n .simulator-field {\n margin-bottom: 6px;\n }\n .simulator-select {\n width: 100%;\n padding: 4px 6px;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: inherit;\n font-size: 10px;\n cursor: pointer;\n }\n .simulator-select:focus {\n outline: none;\n border-color: var(--sim-accent);\n }\n .simulator-select option {\n background: var(--sim-bg);\n color: var(--sim-text);\n }\n .simulator-fixtures {\n margin-bottom: 8px;\n padding-bottom: 8px;\n border-bottom: 2px solid var(--sim-border);\n }\n .simulator-label {\n display: block;\n color: var(--sim-accent);\n text-transform: uppercase;\n font-size: 9px;\n font-weight: bold;\n letter-spacing: 1px;\n margin-bottom: 4px;\n }\n .simulator-textarea {\n width: 100%;\n min-height: 40px;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: 10px/1.4 \"Menlo\", monospace;\n padding: 4px;\n resize: none;\n box-sizing: border-box;\n overflow-y: auto;\n }\n .simulator-textarea.auto-resize {\n resize: none;\n overflow-y: auto;\n }\n .simulator-textarea:focus {\n outline: none;\n border-color: var(--sim-accent);\n }\n .simulator-input {\n width: 100%;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text);\n font: 10px/1.4 \"Menlo\", monospace;\n padding: 4px 6px;\n box-sizing: border-box;\n }\n .simulator-input:focus {\n outline: none;\n border-color: var(--sim-accent);\n }\n .simulator-input::placeholder {\n color: var(--sim-text-dim);\n }\n .simulator-tab-content {\n display: none;\n }\n .simulator-tab-content.active {\n display: block;\n }\n .msgs-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .msgs-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n #simulator-msgs-log {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1;\n overflow-y: auto;\n }\n .simulator-msg {\n padding: 3px 4px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n font-size: 10px;\n }\n .simulator-msg.out {\n border-left: 2px solid var(--sim-accent);\n }\n .simulator-msg.in {\n border-left: 2px solid var(--sim-blue);\n }\n .simulator-msg-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 2px;\n }\n .simulator-msg-type {\n font-weight: bold;\n color: var(--sim-text);\n }\n .simulator-msg.out .simulator-msg-type {\n color: var(--sim-accent);\n }\n .simulator-msg.in .simulator-msg-type {\n color: var(--sim-blue);\n }\n .simulator-msg-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n }\n .simulator-msg-data {\n color: var(--sim-text-dim);\n font-size: 9px;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 60px;\n overflow: hidden;\n cursor: pointer;\n border-radius: 2px;\n padding: 2px 4px;\n background: var(--sim-bg-alt);\n }\n .simulator-msg-data:hover {\n background: var(--sim-border);\n }\n .simulator-msg.expanded {\n flex: 1;\n display: flex;\n flex-direction: column;\n }\n .simulator-msg.expanded .simulator-msg-data {\n max-height: none;\n flex: 1;\n overflow-y: auto;\n }\n .simulator-empty {\n color: var(--sim-text-dim);\n font-size: 10px;\n text-align: center;\n padding: 20px;\n }\n .simulator-value {\n color: var(--sim-text);\n font-size: 10px;\n padding: 4px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n }\n .simulator-deeds {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .simulator-deed {\n display: flex;\n justify-content: space-between;\n padding: 3px 4px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n font-size: 10px;\n }\n .simulator-deed-name {\n color: var(--sim-text);\n }\n .simulator-deed-value {\n color: var(--sim-accent);\n font-weight: bold;\n }\n .thumb-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .thumb-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n #simulator-thumb-preview {\n background: var(--sim-thumb-bg, transparent);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n padding: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n aspect-ratio: 1;\n width: 100%;\n box-sizing: border-box;\n }\n #simulator-thumb-preview svg {\n width: 100%;\n height: 100%;\n max-width: 100%;\n max-height: 100%;\n }\n #simulator-thumb-fn {\n font-size: 10px;\n color: var(--sim-text-dim);\n margin-top: 4px;\n }\n .theme-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .theme-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n .simulator-themes {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .simulator-theme-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px;\n background: var(--sim-bg);\n border: 2px solid var(--sim-border);\n border-radius: 2px;\n cursor: pointer;\n }\n .simulator-theme-item:hover {\n border-color: var(--sim-border-light);\n }\n .simulator-theme-item.selected {\n border-color: var(--sim-accent);\n background: var(--sim-bg-alt);\n }\n .simulator-theme-preview {\n width: 48px;\n height: 32px;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-template-rows: repeat(2, 1fr);\n gap: 1px;\n border-radius: 2px;\n overflow: hidden;\n flex-shrink: 0;\n }\n .simulator-theme-preview-cell {\n width: 100%;\n height: 100%;\n }\n .simulator-theme-name {\n font-size: 10px;\n color: var(--sim-text);\n flex: 1;\n }\n .simulator-theme-type {\n font-size: 9px;\n color: var(--sim-text-dim);\n text-transform: uppercase;\n }\n /* Auth tab styles */\n .simulator-section {\n margin-bottom: 12px;\n }\n .simulator-section-title {\n color: var(--sim-accent);\n text-transform: uppercase;\n font-size: 10px;\n font-weight: bold;\n letter-spacing: 1px;\n margin-bottom: 6px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--sim-border);\n }\n .auth-header-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 6px;\n }\n .auth-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 4px 0;\n }\n .auth-status.authenticated {\n color: var(--sim-success);\n }\n .simulator-btn.small {\n padding: 2px 6px;\n font-size: 9px;\n }\n .simulator-btn.tiny {\n padding: 3px 2px;\n font-size: 8px;\n border-width: 1px;\n line-height: 1;\n min-height: 0;\n height: auto;\n }\n .auth-title-row {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .auth-title-row > span:first-child {\n flex: 1;\n }\n .auth-title-row .simulator-btn.active {\n background: var(--sim-accent);\n color: black;\n }\n .auth-description {\n font-size: 10px;\n color: var(--sim-text-dim);\n margin: 6px 0;\n line-height: 1.4;\n }\n .auth-user-info {\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n margin-bottom: 8px;\n }\n .auth-user-info div {\n margin-bottom: 4px;\n }\n .auth-user-info div:last-child {\n margin-bottom: 0;\n }\n .auth-user-info code {\n color: var(--sim-text);\n background: var(--sim-bg-alt);\n padding: 1px 4px;\n border-radius: 2px;\n }\n .auth-warning {\n color: var(--sim-warning);\n font-style: italic;\n }\n .auth-error {\n margin-top: 8px;\n }\n .auth-error .error,\n .auth-api-result .error {\n color: var(--sim-error);\n font-size: 10px;\n padding: 6px;\n background: rgba(248, 113, 113, 0.1);\n border: 1px solid var(--sim-error);\n border-radius: 2px;\n }\n .auth-api-result {\n margin-top: 8px;\n }\n .auth-api-result pre {\n font-size: 9px;\n color: var(--sim-text);\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n padding: 6px;\n margin: 0;\n white-space: pre-wrap;\n word-break: break-all;\n max-height: 150px;\n overflow-y: auto;\n }\n .auth-api-result .loading {\n font-size: 10px;\n color: var(--sim-text-dim);\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n }\n /* Data view styles */\n .data-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .data-subtabs {\n display: flex;\n gap: 2px;\n margin-bottom: 8px;\n flex-shrink: 0;\n }\n .data-subtab {\n padding: 4px 10px;\n background: var(--sim-bg-alt);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n color: var(--sim-text-dim);\n cursor: pointer;\n font: inherit;\n font-size: 9px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n .data-subtab:hover {\n color: var(--sim-text);\n background: var(--sim-border);\n }\n .data-subtab.active {\n color: var(--sim-panel);\n background: var(--sim-accent);\n border-color: var(--sim-accent);\n }\n .data-subtab-content {\n display: none;\n flex: 1;\n overflow-y: auto;\n overflow-x: hidden;\n }\n .data-subtab-content.active {\n display: flex;\n flex-direction: column;\n }\n /* History tab styles */\n .history-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n .history-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .history-item {\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n display: flex;\n flex-direction: row;\n gap: 8px;\n }\n .history-item:hover {\n border-color: var(--sim-border-light);\n }\n .history-item-thumb {\n width: 80px;\n height: 80px;\n flex-shrink: 0;\n background: var(--history-thumb-bg, var(--sim-bg-alt));\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n display: flex;\n align-items: center;\n justify-content: center;\n overflow: hidden;\n }\n .history-item-thumb svg {\n width: 100%;\n height: 100%;\n }\n .history-item-thumb:empty {\n display: none;\n }\n .history-item-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n .history-item-header {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n .history-item-num {\n color: var(--sim-accent);\n font-weight: bold;\n font-size: 9px;\n }\n .history-item-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n flex: 1;\n }\n .history-item-preview {\n font-size: 9px;\n color: var(--sim-text);\n word-break: break-all;\n line-height: 1.3;\n background: var(--sim-bg-alt);\n padding: 3px 4px;\n border-radius: 2px;\n flex: 1;\n overflow: hidden;\n }\n /* Saves tab styles */\n .save-new {\n display: flex;\n gap: 4px;\n margin-bottom: 8px;\n flex-shrink: 0;\n }\n .save-new .simulator-input {\n flex: 1;\n }\n .saves-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .save-item {\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n }\n .save-item:hover {\n border-color: var(--sim-border-light);\n }\n .save-item-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n }\n .save-item-name {\n color: var(--sim-text);\n font-weight: bold;\n font-size: 10px;\n }\n .save-item-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n }\n .save-item-actions {\n display: flex;\n gap: 4px;\n }\n /* Features view styles */\n .features-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .features-slug-input {\n display: flex;\n gap: 4px;\n margin-bottom: 8px;\n }\n .features-slug-input .simulator-input {\n flex: 1;\n }\n .features-content {\n flex: 1;\n overflow-y: auto;\n }\n .features-loading {\n color: var(--sim-text-dim);\n font-size: 10px;\n text-align: center;\n padding: 20px;\n }\n .features-error {\n color: var(--sim-error);\n font-size: 10px;\n padding: 8px;\n background: rgba(248, 113, 113, 0.1);\n border: 1px solid var(--sim-error);\n border-radius: 2px;\n }\n .features-empty {\n color: var(--sim-text-dim);\n font-size: 10px;\n text-align: center;\n padding: 20px;\n }\n .features-auth-required {\n color: var(--sim-text-dim);\n font-size: 10px;\n padding: 12px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n line-height: 1.5;\n }\n .features-auth-required p {\n margin: 0 0 8px 0;\n }\n .features-auth-required p:last-child {\n margin-bottom: 0;\n }\n .features-game-name {\n color: var(--sim-accent);\n font-size: 11px;\n font-weight: bold;\n margin-bottom: 8px;\n padding-bottom: 4px;\n border-bottom: 1px solid var(--sim-border);\n }\n .feature-group {\n margin-bottom: 12px;\n }\n .feature-group-title {\n color: var(--sim-text);\n font-size: 10px;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 6px;\n padding-bottom: 2px;\n border-bottom: 1px solid var(--sim-border);\n }\n .feature-group-items {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n .feature-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-radius: 2px;\n cursor: pointer;\n transition: all 0.15s ease;\n }\n .feature-item:hover {\n border-color: var(--sim-border-light);\n background: var(--sim-bg-alt);\n }\n .feature-item.updating {\n opacity: 0.5;\n pointer-events: none;\n }\n .feature-status {\n font-size: 14px;\n width: 18px;\n text-align: center;\n flex-shrink: 0;\n }\n .feature-item.enabled .feature-status {\n color: var(--sim-success);\n }\n .feature-item.disabled .feature-status {\n color: var(--sim-error);\n opacity: 0.5;\n }\n .feature-title {\n font-size: 10px;\n color: var(--sim-text);\n flex: 1;\n }\n .feature-item.disabled .feature-title {\n color: var(--sim-text-dim);\n }\n /* Checkpoints view styles */\n .checkpoints-view-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n }\n .checkpoints-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 6px;\n flex-shrink: 0;\n }\n .checkpoints-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n overflow-y: auto;\n }\n .checkpoint-item {\n padding: 6px;\n background: var(--sim-bg);\n border: 1px solid var(--sim-border);\n border-left: 3px solid var(--sim-accent);\n border-radius: 2px;\n }\n .checkpoint-item:hover {\n border-color: var(--sim-border-light);\n border-left-color: var(--sim-accent);\n }\n .checkpoint-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .checkpoint-item .simulator-deeds {\n margin-top: 4px;\n }\n .checkpoint-name {\n color: var(--sim-accent);\n font-weight: bold;\n font-size: 10px;\n }\n .checkpoint-time {\n color: var(--sim-text-dim);\n font-size: 9px;\n }\n /* Keyboard view styles */\n .keyboard-view-container {\n padding: 4px;\n }\n .sim-kb-empty {\n color: var(--sim-text-dim);\n text-align: center;\n padding: 16px 8px;\n font-size: 10px;\n line-height: 1.6;\n }\n .sim-kb-empty code {\n background: var(--sim-bg);\n padding: 1px 4px;\n border-radius: 2px;\n font-size: 10px;\n }\n .sim-kb {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n .sim-kb-row {\n display: flex;\n justify-content: center;\n gap: 3px;\n }\n .sim-kb-key {\n min-width: 28px;\n height: 30px;\n padding: 0 4px;\n border: 1px solid var(--sim-border);\n border-radius: 3px;\n background: var(--sim-bg);\n color: var(--sim-text);\n font: inherit;\n font-size: 11px;\n text-transform: uppercase;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .sim-kb-key:hover {\n background: var(--sim-bg-alt);\n border-color: var(--sim-border-light);\n }\n .sim-kb-key:active {\n background: var(--sim-accent);\n color: var(--sim-panel);\n }\n .sim-kb-key.highlight {\n background: var(--sim-bg-alt);\n border-color: var(--sim-accent);\n color: var(--sim-accent);\n font-size: 9px;\n }\n .sim-kb-key.highlight:active {\n background: var(--sim-accent);\n color: var(--sim-panel);\n }\n .sim-kb-key.l {\n min-width: 40px;\n }\n .sim-kb-key.xl {\n min-width: 52px;\n }\n .sim-kb-key.grow {\n flex: 1;\n }\n .sim-kb-key.disabled {\n opacity: 0.3;\n cursor: default;\n }\n";
2
2
  //# sourceMappingURL=styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/simulator/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,8rwBAijC3B,CAAA"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/simulator/styles.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,wxzBA4nC3B,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"AuthView.d.ts","sourceRoot":"","sources":["../../../src/simulator/views/AuthView.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,UAAU,CAAA;AA8Q/D,wBAAgB,cAAc,IAAI,aAAa,CAkN9C"}
1
+ {"version":3,"file":"AuthView.d.ts","sourceRoot":"","sources":["../../../src/simulator/views/AuthView.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,UAAU,CAAA;AAmR/D,wBAAgB,cAAc,IAAI,aAAa,CAkN9C"}
@@ -0,0 +1,3 @@
1
+ import type { SimulatorView } from "../types";
2
+ export declare function createKeyboardView(): SimulatorView;
3
+ //# sourceMappingURL=KeyboardView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeyboardView.d.ts","sourceRoot":"","sources":["../../../src/simulator/views/KeyboardView.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,UAAU,CAAA;AAsC/D,wBAAgB,kBAAkB,IAAI,aAAa,CA0ClD"}
@@ -7,4 +7,5 @@ export { createThumbView, type ThumbViewExtended } from "./ThumbView";
7
7
  export { createThemeView } from "./ThemeView";
8
8
  export { createAuthView } from "./AuthView";
9
9
  export { createFeaturesView, isAuthenticated } from "./FeaturesView";
10
+ export { createKeyboardView } from "./KeyboardView";
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/simulator/views/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/simulator/views/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA"}
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=(e,t,n=!1)=>{let r=l(e,n);return t&&r&&t.appendChild(r),r},t=(e,t,...n)=>({tag:e,props:t||{},children:[].concat(...n)});var n=e=>document.createTextNode(e.toString()),r=(e,t)=>e.setAttribute(`class`,t),i=(e,t,n)=>{n?(e.setAttribute(t,``),e[t]=!0):e[t]=!1},a=(e,t,n)=>e.addEventListener(t,n,!1),o=(e,t)=>{if(typeof t==`string`)e.setAttribute(`style`,t);else{if(!t)return;Object.keys(t).forEach(n=>{let r=t[n];typeof t[n]==`number`&&(r=t[n].toString()+`px`),e.style[n]=r})}},s=(t,n,s,c)=>{let l=c||t===`svg`,f=l&&d.includes(t)?t:t.toLowerCase(),p=l?document.createElementNS(`http://www.w3.org/2000/svg`,f):document.createElement(f);return n&&Object.keys(n).forEach(e=>{let t=n[e];if(e===`className`)r(p,t);else if(e===`style`)o(p,t);else if(typeof t==`boolean`)i(p,e,t);else if(e.slice(0,2)===`on`)a(p,e.slice(2).toLowerCase(),t);else{let n=/[A-Z]/.test(e)&&!u.includes(e)?e.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g,`$1-$2`).toLowerCase():e;e.toLowerCase()===`crossorigin`?p.setAttribute(e.toLowerCase(),t):p.setAttribute(n,t)}}),s&&s.length>0&&s.forEach(t=>e(t,p,l)),p},c=(e,t,n,r)=>(t.children=n,l(e(t),r)),l=(e,t)=>e==null||e===!1?null:typeof e==`string`||typeof e==`number`?n(e):typeof e.tag==`function`?c(e.tag,e.props,e.children,t):s(e.tag,e.props,e.children,t),u=[`viewBox`,`preserveAspectRatio`,`patternUnits`,`tabIndex`,`crossOrigin`,`gradientTransform`,`gradientUnits`,`textLength`,`lengthAdjust`],d=[`linearGradient`,`radialGradient`,`clipPath`,`textPath`,`animateMotion`,`animateTransform`,`feColorMatrix`,`feComponentTransfer`,`feDropShadow`,`feFlood`,`feGaussianBlur`,`feOffset`];exports.h=t,exports.render=e;
2
+ //# sourceMappingURL=svgJSX.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svgJSX.cjs","names":[],"sources":["../src/svgJSX.ts"],"sourcesContent":["// Forked from https://github.com/callmecavs/understated/blob/751d973e31b267cc1a7ed246170beeb673ebc662/src/understated.js\n// Licensed MIT: https://github.com/callmecavs/understated/blob/751d973e31b267cc1a7ed246170beeb673ebc662/package.json#L10\n\n// Changes:\n// - Converted to TypeScript\n// - Convert to ESM\n// - Comments\n// - Added support for null/false\n// - Added support for camelCase -> kebab attributes\n// - Special case for certain camel case attributes\n//\n\n/** A virtual DOM node produced by the `h` JSX factory. */\ntype VNode = { tag: string | Function; props: Record<string, any>; children: any[] }\n\n/** Converts a JSX element into DOM calls, this is sorta your root entry point */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- target can be any DOM element\nexport const render = (tree: VNode, target?: any, ns = false) => {\n const rootElement = build(tree, ns)\n if (target && rootElement) target.appendChild(rootElement)\n return rootElement\n}\n\n/** The JSX factory fn */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- props and children are dynamic JSX elements\nexport const h = (tag: string, props: any, ...children: any[]) => {\n return {\n tag,\n props: props || {},\n children: [].concat(...children),\n }\n}\n\nconst createText = (str: string | number) => document.createTextNode(str.toString())\n\nconst setClassAttr = (node: HTMLElement | SVGElement, value: string) => node.setAttribute(\"class\", value)\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- boolean attribute value\nconst setBooleanAttr = (node: HTMLElement | SVGElement, name: keyof HTMLElement | keyof SVGElement, value: any) => {\n if (value) {\n node.setAttribute(name, \"\")\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic property access\n ;(node as any)[name as any] = true\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic property access\n ;(node as any)[name as any] = false\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- event handler type\nconst setEventAttr = (node: HTMLElement | SVGElement, name: keyof HTMLElementEventMap, value: any) =>\n node.addEventListener(name, value, false)\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- style value can be string or object\nconst setStyleAttr = (node: HTMLElement | SVGElement, value: any) => {\n if (typeof value === \"string\") {\n node.setAttribute(\"style\", value)\n } else {\n if (!value) return\n Object.keys(value).forEach((key) => {\n let styleVal = value[key]\n if (typeof value[key] === \"number\") {\n styleVal = value[key].toString() + \"px\"\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic style property\n node.style[key as any] = styleVal\n })\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- props and children are dynamic\nconst createNode = (tag: string, props: any, children: any[], ns?: boolean) => {\n const svg = ns || tag === \"svg\"\n\n // Preserve case for SVG elements that have mixed case\n const preservedTag = svg && specialCasesForCamelCaseElements.includes(tag) ? tag : tag.toLowerCase()\n\n const node = svg ? document.createElementNS(\"http://www.w3.org/2000/svg\", preservedTag) : document.createElement(preservedTag)\n\n if (props) {\n Object.keys(props).forEach((name) => {\n const value = props[name]\n\n if (name === \"className\") {\n setClassAttr(node, value)\n } else if (name === \"style\") {\n setStyleAttr(node, value)\n } else if (typeof value === \"boolean\") {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic property name\n setBooleanAttr(node, name as any, value)\n } else if (name.slice(0, 2) === \"on\") {\n const eventName = name.slice(2).toLowerCase()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- event name mapping\n setEventAttr(node, eventName as any, value)\n } else {\n const hasCap = /[A-Z]/.test(name)\n const kebabCase =\n hasCap && !specialCasesForCamelCase.includes(name) ? name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, \"$1-$2\").toLowerCase() : name\n if (name.toLowerCase() === \"crossorigin\") {\n node.setAttribute(name.toLowerCase(), value)\n } else {\n node.setAttribute(kebabCase, value)\n }\n }\n })\n }\n\n if (children && children.length > 0) children.forEach((child) => render(child, node, svg))\n\n return node\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- component factory with dynamic props\nconst createComponent = (tag: (props: any) => HTMLElement | SVGElement | Text, props: any, children: any[], ns?: boolean) => {\n props[\"children\"] = children\n return build(tag(props), ns)\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- recursive JSX builder with dynamic types\nconst build = (obj: any, ns?: any): HTMLElement | SVGElement | Text | null => {\n if (obj === null || obj === undefined || obj === false) {\n return null\n } else if (typeof obj === \"string\" || typeof obj === \"number\") {\n return createText(obj)\n } else if (typeof obj.tag === \"function\") {\n return createComponent(obj.tag, obj.props, obj.children, ns)\n } else {\n return createNode(obj.tag, obj.props, obj.children, ns)\n }\n}\n\n/** Known attributes which shouldn't get auto-kebab'd */\nconst specialCasesForCamelCase = [\n \"viewBox\",\n \"preserveAspectRatio\",\n \"patternUnits\",\n \"tabIndex\",\n \"crossOrigin\",\n \"gradientTransform\",\n \"gradientUnits\",\n \"textLength\",\n \"lengthAdjust\",\n]\n\n/** Known SVG elements which shouldn't get lowercased */\nconst specialCasesForCamelCaseElements = [\n \"linearGradient\",\n \"radialGradient\",\n \"clipPath\",\n \"textPath\",\n \"animateMotion\",\n \"animateTransform\",\n \"feColorMatrix\",\n \"feComponentTransfer\",\n \"feDropShadow\",\n \"feFlood\",\n \"feGaussianBlur\",\n \"feOffset\",\n]\n"],"mappings":"mEAiBA,MAAa,GAAU,EAAa,EAAc,EAAK,KAAU,CAC/D,IAAM,EAAc,EAAM,EAAM,EAAG,CAEnC,OADI,GAAU,GAAa,EAAO,YAAY,EAAY,CACnD,GAKI,GAAK,EAAa,EAAY,GAAG,KACrC,CACL,MACA,MAAO,GAAS,EAAE,CAClB,SAAU,EAAE,CAAC,OAAO,GAAG,EAAS,CACjC,EAGH,IAAM,EAAc,GAAyB,SAAS,eAAe,EAAI,UAAU,CAAC,CAE9E,GAAgB,EAAgC,IAAkB,EAAK,aAAa,QAAS,EAAM,CAGnG,GAAkB,EAAgC,EAA4C,IAAe,CAC7G,GACF,EAAK,aAAa,EAAM,GAAG,CAEzB,EAAa,GAAe,IAG5B,EAAa,GAAe,IAK5B,GAAgB,EAAgC,EAAiC,IACrF,EAAK,iBAAiB,EAAM,EAAO,GAAM,CAGrC,GAAgB,EAAgC,IAAe,CACnE,GAAI,OAAO,GAAU,SACnB,EAAK,aAAa,QAAS,EAAM,KAC5B,CACL,GAAI,CAAC,EAAO,OACZ,OAAO,KAAK,EAAM,CAAC,QAAS,GAAQ,CAClC,IAAI,EAAW,EAAM,GACjB,OAAO,EAAM,IAAS,WACxB,EAAW,EAAM,GAAK,UAAU,CAAG,MAGrC,EAAK,MAAM,GAAc,GACzB,GAKA,GAAc,EAAa,EAAY,EAAiB,IAAiB,CAC7E,IAAM,EAAM,GAAM,IAAQ,MAGpB,EAAe,GAAO,EAAiC,SAAS,EAAI,CAAG,EAAM,EAAI,aAAa,CAE9F,EAAO,EAAM,SAAS,gBAAgB,6BAA8B,EAAa,CAAG,SAAS,cAAc,EAAa,CAgC9H,OA9BI,GACF,OAAO,KAAK,EAAM,CAAC,QAAS,GAAS,CACnC,IAAM,EAAQ,EAAM,GAEpB,GAAI,IAAS,YACX,EAAa,EAAM,EAAM,SAChB,IAAS,QAClB,EAAa,EAAM,EAAM,SAChB,OAAO,GAAU,UAE1B,EAAe,EAAM,EAAa,EAAM,SAC/B,EAAK,MAAM,EAAG,EAAE,GAAK,KAG9B,EAAa,EAFK,EAAK,MAAM,EAAE,CAAC,aAAa,CAER,EAAM,KACtC,CAEL,IAAM,EADS,QAAQ,KAAK,EAAK,EAErB,CAAC,EAAyB,SAAS,EAAK,CAAG,EAAK,QAAQ,+BAAgC,QAAQ,CAAC,aAAa,CAAG,EACzH,EAAK,aAAa,GAAK,cACzB,EAAK,aAAa,EAAK,aAAa,CAAE,EAAM,CAE5C,EAAK,aAAa,EAAW,EAAM,GAGvC,CAGA,GAAY,EAAS,OAAS,GAAG,EAAS,QAAS,GAAU,EAAO,EAAO,EAAM,EAAI,CAAC,CAEnF,GAIH,GAAmB,EAAsD,EAAY,EAAiB,KAC1G,EAAM,SAAc,EACb,EAAM,EAAI,EAAM,CAAE,EAAG,EAIxB,GAAS,EAAU,IACnB,GAAQ,MAA6B,IAAQ,GACxC,KACE,OAAO,GAAQ,UAAY,OAAO,GAAQ,SAC5C,EAAW,EAAI,CACb,OAAO,EAAI,KAAQ,WACrB,EAAgB,EAAI,IAAK,EAAI,MAAO,EAAI,SAAU,EAAG,CAErD,EAAW,EAAI,IAAK,EAAI,MAAO,EAAI,SAAU,EAAG,CAKrD,EAA2B,CAC/B,UACA,sBACA,eACA,WACA,cACA,oBACA,gBACA,aACA,eACD,CAGK,EAAmC,CACvC,iBACA,iBACA,WACA,WACA,gBACA,mBACA,gBACA,sBACA,eACA,UACA,iBACA,WACD"}
@@ -0,0 +1,16 @@
1
+ /** A virtual DOM node produced by the `h` JSX factory. */
2
+ type VNode = {
3
+ tag: string | Function;
4
+ props: Record<string, any>;
5
+ children: any[];
6
+ };
7
+ /** Converts a JSX element into DOM calls, this is sorta your root entry point */
8
+ export declare const render: (tree: VNode, target?: any, ns?: boolean) => HTMLElement | SVGElement | Text | null;
9
+ /** The JSX factory fn */
10
+ export declare const h: (tag: string, props: any, ...children: any[]) => {
11
+ tag: string;
12
+ props: any;
13
+ children: never[];
14
+ };
15
+ export {};
16
+ //# sourceMappingURL=svgJSX.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svgJSX.d.ts","sourceRoot":"","sources":["../src/svgJSX.ts"],"names":[],"mappings":"AAYA,0DAA0D;AAC1D,KAAK,KAAK,GAAG;IAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAAC,QAAQ,EAAE,GAAG,EAAE,CAAA;CAAE,CAAA;AAEpF,iFAAiF;AAEjF,eAAO,MAAM,MAAM,qFAIlB,CAAA;AAED,yBAAyB;AAEzB,eAAO,MAAM,CAAC;;;;CAMb,CAAA"}
package/dist/svgJSX.js ADDED
@@ -0,0 +1,60 @@
1
+ /** Converts a JSX element into DOM calls, this is sorta your root entry point */
2
+ const e = (e, t, n = !1) => {
3
+ let r = l(e, n);
4
+ return t && r && t.appendChild(r), r;
5
+ }, t = (e, t, ...n) => ({
6
+ tag: e,
7
+ props: t || {},
8
+ children: [].concat(...n)
9
+ });
10
+ var n = (e) => document.createTextNode(e.toString()), r = (e, t) => e.setAttribute("class", t), i = (e, t, n) => {
11
+ n ? (e.setAttribute(t, ""), e[t] = !0) : e[t] = !1;
12
+ }, a = (e, t, n) => e.addEventListener(t, n, !1), o = (e, t) => {
13
+ if (typeof t == "string") e.setAttribute("style", t);
14
+ else {
15
+ if (!t) return;
16
+ Object.keys(t).forEach((n) => {
17
+ let r = t[n];
18
+ typeof t[n] == "number" && (r = t[n].toString() + "px"), e.style[n] = r;
19
+ });
20
+ }
21
+ }, s = (t, n, s, c) => {
22
+ let l = c || t === "svg", f = l && d.includes(t) ? t : t.toLowerCase(), p = l ? document.createElementNS("http://www.w3.org/2000/svg", f) : document.createElement(f);
23
+ return n && Object.keys(n).forEach((e) => {
24
+ let t = n[e];
25
+ if (e === "className") r(p, t);
26
+ else if (e === "style") o(p, t);
27
+ else if (typeof t == "boolean") i(p, e, t);
28
+ else if (e.slice(0, 2) === "on") a(p, e.slice(2).toLowerCase(), t);
29
+ else {
30
+ let n = /[A-Z]/.test(e) && !u.includes(e) ? e.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase() : e;
31
+ e.toLowerCase() === "crossorigin" ? p.setAttribute(e.toLowerCase(), t) : p.setAttribute(n, t);
32
+ }
33
+ }), s && s.length > 0 && s.forEach((t) => e(t, p, l)), p;
34
+ }, c = (e, t, n, r) => (t.children = n, l(e(t), r)), l = (e, t) => e == null || e === !1 ? null : typeof e == "string" || typeof e == "number" ? n(e) : typeof e.tag == "function" ? c(e.tag, e.props, e.children, t) : s(e.tag, e.props, e.children, t), u = [
35
+ "viewBox",
36
+ "preserveAspectRatio",
37
+ "patternUnits",
38
+ "tabIndex",
39
+ "crossOrigin",
40
+ "gradientTransform",
41
+ "gradientUnits",
42
+ "textLength",
43
+ "lengthAdjust"
44
+ ], d = [
45
+ "linearGradient",
46
+ "radialGradient",
47
+ "clipPath",
48
+ "textPath",
49
+ "animateMotion",
50
+ "animateTransform",
51
+ "feColorMatrix",
52
+ "feComponentTransfer",
53
+ "feDropShadow",
54
+ "feFlood",
55
+ "feGaussianBlur",
56
+ "feOffset"
57
+ ];
58
+ export { t as h, e as render };
59
+
60
+ //# sourceMappingURL=svgJSX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svgJSX.js","names":[],"sources":["../src/svgJSX.ts"],"sourcesContent":["// Forked from https://github.com/callmecavs/understated/blob/751d973e31b267cc1a7ed246170beeb673ebc662/src/understated.js\n// Licensed MIT: https://github.com/callmecavs/understated/blob/751d973e31b267cc1a7ed246170beeb673ebc662/package.json#L10\n\n// Changes:\n// - Converted to TypeScript\n// - Convert to ESM\n// - Comments\n// - Added support for null/false\n// - Added support for camelCase -> kebab attributes\n// - Special case for certain camel case attributes\n//\n\n/** A virtual DOM node produced by the `h` JSX factory. */\ntype VNode = { tag: string | Function; props: Record<string, any>; children: any[] }\n\n/** Converts a JSX element into DOM calls, this is sorta your root entry point */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- target can be any DOM element\nexport const render = (tree: VNode, target?: any, ns = false) => {\n const rootElement = build(tree, ns)\n if (target && rootElement) target.appendChild(rootElement)\n return rootElement\n}\n\n/** The JSX factory fn */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- props and children are dynamic JSX elements\nexport const h = (tag: string, props: any, ...children: any[]) => {\n return {\n tag,\n props: props || {},\n children: [].concat(...children),\n }\n}\n\nconst createText = (str: string | number) => document.createTextNode(str.toString())\n\nconst setClassAttr = (node: HTMLElement | SVGElement, value: string) => node.setAttribute(\"class\", value)\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- boolean attribute value\nconst setBooleanAttr = (node: HTMLElement | SVGElement, name: keyof HTMLElement | keyof SVGElement, value: any) => {\n if (value) {\n node.setAttribute(name, \"\")\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic property access\n ;(node as any)[name as any] = true\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic property access\n ;(node as any)[name as any] = false\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- event handler type\nconst setEventAttr = (node: HTMLElement | SVGElement, name: keyof HTMLElementEventMap, value: any) =>\n node.addEventListener(name, value, false)\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- style value can be string or object\nconst setStyleAttr = (node: HTMLElement | SVGElement, value: any) => {\n if (typeof value === \"string\") {\n node.setAttribute(\"style\", value)\n } else {\n if (!value) return\n Object.keys(value).forEach((key) => {\n let styleVal = value[key]\n if (typeof value[key] === \"number\") {\n styleVal = value[key].toString() + \"px\"\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic style property\n node.style[key as any] = styleVal\n })\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- props and children are dynamic\nconst createNode = (tag: string, props: any, children: any[], ns?: boolean) => {\n const svg = ns || tag === \"svg\"\n\n // Preserve case for SVG elements that have mixed case\n const preservedTag = svg && specialCasesForCamelCaseElements.includes(tag) ? tag : tag.toLowerCase()\n\n const node = svg ? document.createElementNS(\"http://www.w3.org/2000/svg\", preservedTag) : document.createElement(preservedTag)\n\n if (props) {\n Object.keys(props).forEach((name) => {\n const value = props[name]\n\n if (name === \"className\") {\n setClassAttr(node, value)\n } else if (name === \"style\") {\n setStyleAttr(node, value)\n } else if (typeof value === \"boolean\") {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic property name\n setBooleanAttr(node, name as any, value)\n } else if (name.slice(0, 2) === \"on\") {\n const eventName = name.slice(2).toLowerCase()\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- event name mapping\n setEventAttr(node, eventName as any, value)\n } else {\n const hasCap = /[A-Z]/.test(name)\n const kebabCase =\n hasCap && !specialCasesForCamelCase.includes(name) ? name.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, \"$1-$2\").toLowerCase() : name\n if (name.toLowerCase() === \"crossorigin\") {\n node.setAttribute(name.toLowerCase(), value)\n } else {\n node.setAttribute(kebabCase, value)\n }\n }\n })\n }\n\n if (children && children.length > 0) children.forEach((child) => render(child, node, svg))\n\n return node\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- component factory with dynamic props\nconst createComponent = (tag: (props: any) => HTMLElement | SVGElement | Text, props: any, children: any[], ns?: boolean) => {\n props[\"children\"] = children\n return build(tag(props), ns)\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- recursive JSX builder with dynamic types\nconst build = (obj: any, ns?: any): HTMLElement | SVGElement | Text | null => {\n if (obj === null || obj === undefined || obj === false) {\n return null\n } else if (typeof obj === \"string\" || typeof obj === \"number\") {\n return createText(obj)\n } else if (typeof obj.tag === \"function\") {\n return createComponent(obj.tag, obj.props, obj.children, ns)\n } else {\n return createNode(obj.tag, obj.props, obj.children, ns)\n }\n}\n\n/** Known attributes which shouldn't get auto-kebab'd */\nconst specialCasesForCamelCase = [\n \"viewBox\",\n \"preserveAspectRatio\",\n \"patternUnits\",\n \"tabIndex\",\n \"crossOrigin\",\n \"gradientTransform\",\n \"gradientUnits\",\n \"textLength\",\n \"lengthAdjust\",\n]\n\n/** Known SVG elements which shouldn't get lowercased */\nconst specialCasesForCamelCaseElements = [\n \"linearGradient\",\n \"radialGradient\",\n \"clipPath\",\n \"textPath\",\n \"animateMotion\",\n \"animateTransform\",\n \"feColorMatrix\",\n \"feComponentTransfer\",\n \"feDropShadow\",\n \"feFlood\",\n \"feGaussianBlur\",\n \"feOffset\",\n]\n"],"mappings":";AAiBA,MAAa,KAAU,GAAa,GAAc,IAAK,OAAU;CAC/D,IAAM,IAAc,EAAM,GAAM,EAAG;AAEnC,QADI,KAAU,KAAa,EAAO,YAAY,EAAY,EACnD;GAKI,KAAK,GAAa,GAAY,GAAG,OACrC;CACL;CACA,OAAO,KAAS,EAAE;CAClB,UAAU,EAAE,CAAC,OAAO,GAAG,EAAS;CACjC;AAGH,IAAM,KAAc,MAAyB,SAAS,eAAe,EAAI,UAAU,CAAC,EAE9E,KAAgB,GAAgC,MAAkB,EAAK,aAAa,SAAS,EAAM,EAGnG,KAAkB,GAAgC,GAA4C,MAAe;AACjH,CAAI,KACF,EAAK,aAAa,GAAM,GAAG,EAEzB,EAAa,KAAe,MAG5B,EAAa,KAAe;GAK5B,KAAgB,GAAgC,GAAiC,MACrF,EAAK,iBAAiB,GAAM,GAAO,GAAM,EAGrC,KAAgB,GAAgC,MAAe;AACnE,KAAI,OAAO,KAAU,SACnB,GAAK,aAAa,SAAS,EAAM;MAC5B;AACL,MAAI,CAAC,EAAO;AACZ,SAAO,KAAK,EAAM,CAAC,SAAS,MAAQ;GAClC,IAAI,IAAW,EAAM;AAKrB,GAJI,OAAO,EAAM,MAAS,aACxB,IAAW,EAAM,GAAK,UAAU,GAAG,OAGrC,EAAK,MAAM,KAAc;IACzB;;GAKA,KAAc,GAAa,GAAY,GAAiB,MAAiB;CAC7E,IAAM,IAAM,KAAM,MAAQ,OAGpB,IAAe,KAAO,EAAiC,SAAS,EAAI,GAAG,IAAM,EAAI,aAAa,EAE9F,IAAO,IAAM,SAAS,gBAAgB,8BAA8B,EAAa,GAAG,SAAS,cAAc,EAAa;AAgC9H,QA9BI,KACF,OAAO,KAAK,EAAM,CAAC,SAAS,MAAS;EACnC,IAAM,IAAQ,EAAM;AAEpB,MAAI,MAAS,YACX,GAAa,GAAM,EAAM;WAChB,MAAS,QAClB,GAAa,GAAM,EAAM;WAChB,OAAO,KAAU,UAE1B,GAAe,GAAM,GAAa,EAAM;WAC/B,EAAK,MAAM,GAAG,EAAE,KAAK,KAG9B,GAAa,GAFK,EAAK,MAAM,EAAE,CAAC,aAAa,EAER,EAAM;OACtC;GAEL,IAAM,IADS,QAAQ,KAAK,EAAK,IAErB,CAAC,EAAyB,SAAS,EAAK,GAAG,EAAK,QAAQ,gCAAgC,QAAQ,CAAC,aAAa,GAAG;AAC7H,GAAI,EAAK,aAAa,KAAK,gBACzB,EAAK,aAAa,EAAK,aAAa,EAAE,EAAM,GAE5C,EAAK,aAAa,GAAW,EAAM;;GAGvC,EAGA,KAAY,EAAS,SAAS,KAAG,EAAS,SAAS,MAAU,EAAO,GAAO,GAAM,EAAI,CAAC,EAEnF;GAIH,KAAmB,GAAsD,GAAY,GAAiB,OAC1G,EAAM,WAAc,GACb,EAAM,EAAI,EAAM,EAAE,EAAG,GAIxB,KAAS,GAAU,MACnB,KAAQ,QAA6B,MAAQ,KACxC,OACE,OAAO,KAAQ,YAAY,OAAO,KAAQ,WAC5C,EAAW,EAAI,GACb,OAAO,EAAI,OAAQ,aACrB,EAAgB,EAAI,KAAK,EAAI,OAAO,EAAI,UAAU,EAAG,GAErD,EAAW,EAAI,KAAK,EAAI,OAAO,EAAI,UAAU,EAAG,EAKrD,IAA2B;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,EAGK,IAAmC;CACvC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
package/dist/vite.cjs CHANGED
@@ -1,5 +1,5 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const l=require(`./asyncToGenerator-BlxRHn40.cjs`),u=require(`./objectSpread2-B6tAAMuy.cjs`);let d=require(`vite`);var f=c(o(((e,t)=>{t.exports={}}))(),1);function p(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}function m(e,t){if(e==null)return{};var n,r,i=p(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.includes(n)||{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var h=[`fixturesGlob`],g=`/@puzzmo-simulator-init.js`,_=`virtual:puzzmo-simulator`,v=`\0`+_;function y(e={}){function t(){let{fixturesGlob:t}=e,n=m(e,h),r=[`import { createSimulator } from "@puzzmo/sdk/simulator"`];t&&r.push(`const fixtures = import.meta.glob(${JSON.stringify(t)}, { eager: true })`);let i=Object.entries(n).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}: ${JSON.stringify(t)}`);return t&&i.push(`fixtures`),r.push(`createSimulator({ ${i.join(`, `)} })`),r.join(`
2
- `)}return{name:`puzzmo-simulator`,apply:`serve`,resolveId(e){if(e===_)return v},load(e){if(e===v)return t()},configureServer(e){e.middlewares.use(`/oauth/callback`,(e,t)=>{t.setHeader(`Content-Type`,`text/html`),t.end(`<!DOCTYPE html>
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./asyncToGenerator-BlxRHn40.cjs`),l=require(`./objectSpread2-B6tAAMuy.cjs`);let u=require(`vite`),d=require(`path`);d=s(d);let f=require(`fs`);f=s(f);function p(e,t){if(e==null)return{};var n={};for(var r in e)if({}.hasOwnProperty.call(e,r)){if(t.includes(r))continue;n[r]=e[r]}return n}function m(e,t){if(e==null)return{};var n,r,i=p(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r<a.length;r++)n=a[r],t.includes(n)||{}.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var h=[`fixturesGlob`],g=`/@puzzmo-simulator-init.js`,_=`virtual:puzzmo-simulator`;function v(e){let t=new Map,n=T(e,3);f.default.existsSync(d.default.join(e,`puzzmo.json`))&&n.unshift(e);for(let i of n)try{var r;let n=JSON.parse(f.default.readFileSync(d.default.join(i,`puzzmo.json`),`utf-8`));if(!(!(n==null||(r=n.game)==null)&&r.slug))continue;let a=d.default.join(i,`src`,`appBundle.js`),o=null;f.default.existsSync(a)&&(o=`/`+d.default.relative(e,a).split(d.default.sep).join(`/`)),t.set(n.game.slug,{dir:i,slug:n.game.slug,displayName:n.game.displayName,appBundlePath:o})}catch(e){}return t}function y(e,t,n){if(e)try{let r=new URL(e).pathname;for(let e of t.values()){let t=`/`+d.default.relative(n,e.dir).split(d.default.sep).join(`/`);if(r.startsWith(t+`/`)||r===t)return e}}catch(e){}if(t.size===1)return t.values().next().value}function b(e,t){let{fixturesGlob:n}=e,r=m(e,h),i=n===!1?null:n==null?`/fixtures/puzzles/**/*.json`:n,a=[`import { createSimulator } from "@puzzmo/sdk/simulator"`];i&&a.push(`const fixtures = import.meta.glob(${JSON.stringify(i)}, { eager: true })`),t!=null&&t.appBundlePath&&(a.push(`import(${JSON.stringify(t.appBundlePath)}).then(m => {`),a.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`),a.push(`}).catch(() => {})`));let o=l.t(l.t({},r),t!=null&&t.slug?{slug:t.slug}:{}),s=Object.entries(o).filter(([,e])=>e!==void 0).map(([e,t])=>`${e}: ${JSON.stringify(t)}`);return i&&s.push(`fixtures`),a.push(`createSimulator({ ${s.join(`, `)} })`),a.join(`
2
+ `)}function x(e={}){let t=new Map,n;return{name:`puzzmo-simulator`,apply:`serve`,configResolved(e){if(n=e.root,t=v(n),t.size===0)e.logger.info(`\x1B[33m\x1B[1m PUZZMO \x1B[22m\x1B[39m\x1B[2m no puzzmo.json files found\x1B[22m`);else{let n=[...t.values()].map(e=>`\x1b[36m${e.slug}\x1b[39m`),r=t.size===1?`game`:`games`;e.logger.info(`\x1b[33m\x1b[1m PUZZMO \x1b[22m\x1b[39m found ${t.size} ${r}: ${n.join(`\x1B[2m, \x1B[22m`)}`)}},resolveId(e){if(e===_||e.startsWith(_+`?`))return`\0`+e},load(n){if(!n.startsWith(`\0`+_))return;let r=new URLSearchParams(n.split(`?`)[1]||``).get(`game`);return b(e,r?t.get(r):t.size===1?t.values().next().value:void 0)},configureServer(e){e.middlewares.use(`/oauth/callback`,(e,t)=>{t.setHeader(`Content-Type`,`text/html`),t.end(`<!DOCTYPE html>
3
3
  <html><head><title>Puzzmo OAuth</title></head>
4
4
  <body><script>
5
5
  var params = new URLSearchParams(window.location.search);
@@ -7,5 +7,5 @@ var returnUrl = sessionStorage.getItem("oauth_return_url") || "/";
7
7
  var url = new URL(returnUrl);
8
8
  params.forEach(function(v, k) { url.searchParams.set(k, v); });
9
9
  window.location.href = url.toString();
10
- <\/script></body></html>`)}),e.middlewares.use(function(){var t=l.t(function*(t,n,r){var i;if(((i=t.url)==null?void 0:i.split(`?`)[0])!==g)return r();let a=yield e.transformRequest(_);if(!a)return r();n.setHeader(`Content-Type`,`application/javascript`),n.end(a.code)});return function(e,n,r){return t.apply(this,arguments)}}())},transformIndexHtml(){return[{tag:`script`,attrs:{type:`module`,src:g},injectTo:`head`}]}}}function b(e,t){return(n={})=>{let{entry:r,outputFile:i}=u.t(u.t({},t),n);return{name:e,apply:`build`,closeBundle(){return l.t(function*(){try{yield(0,d.build)({configFile:!1,logLevel:`warn`,build:{lib:{entry:f.default.isAbsolute(r)?r:f.default.resolve(process.cwd(),r),formats:[`es`],fileName:()=>i},outDir:`dist`,emptyOutDir:!1}})}catch(t){throw console.error(`[${e}] build failed:`,t),t}})()}}}}const x=b(`app-bundle`,{entry:`src/appBundle.js`,outputFile:`app-bundle.js`}),S=b(`editor-bundle`,{entry:`src/editorBundle.js`,outputFile:`editor-bundle.js`});exports.appBundlePlugin=x,exports.editorBundlePlugin=S,exports.puzzmoSimulator=y,exports.t=c;
10
+ <\/script></body></html>`)}),e.middlewares.use(function(){var r=c.t(function*(r,i,a){var o;if(((o=r.url)==null?void 0:o.split(`?`)[0])!==g)return a();let s=y(r.headers.referer,t,n),c=_+(s?`?game=${s.slug}`:``),l=yield e.transformRequest(c);if(!l)return a();i.setHeader(`Content-Type`,`application/javascript`),i.end(l.code)});return function(e,t,n){return r.apply(this,arguments)}}())},transformIndexHtml(){return[{tag:`script`,attrs:{type:`module`,src:g},injectTo:`head`}]}}}function S(e,t){return(n={})=>{let{entry:r,outputFile:i}=l.t(l.t({},t),n);return{name:e,apply:`build`,closeBundle(){return c.t(function*(){try{yield(0,u.build)({configFile:!1,logLevel:`warn`,build:{lib:{entry:d.default.isAbsolute(r)?r:d.default.resolve(process.cwd(),r),formats:[`es`],fileName:()=>i},outDir:`dist`,emptyOutDir:!1}})}catch(t){throw console.error(`[${e}] build failed:`,t),t}})()}}}}const C=S(`app-bundle`,{entry:`src/appBundle.js`,outputFile:`app-bundle.js`}),w=S(`editor-bundle`,{entry:`src/editorBundle.js`,outputFile:`editor-bundle.js`}),T=(e,t,n=0)=>{if(n>=t)return[];let r=[],i;try{i=f.default.readdirSync(e,{withFileTypes:!0})}catch(e){return r}for(let a of i){if(!a.isDirectory()||a.name.startsWith(`.`)||a.name===`node_modules`)continue;let i=d.default.join(e,a.name);f.default.existsSync(d.default.join(i,`puzzmo.json`))&&r.push(i),r.push(...T(i,t,n+1))}return r};exports.appBundlePlugin=C,exports.discoverGames=v,exports.editorBundlePlugin=w,exports.findPuzzmoJsonDirs=T,exports.generateSimulatorCode=b,exports.puzzmoSimulator=x,exports.resolveGameFromReferer=y,exports.t=s;
11
11
  //# sourceMappingURL=vite.cjs.map
package/dist/vite.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.cjs","names":[],"sources":["../__vite-browser-external","../src/vite.ts"],"sourcesContent":["module.exports = {}","import type { Plugin } from \"vite\"\nimport { build } from \"vite\"\nimport path from \"path\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /** Game slug for API features (e.g. \"crossword\", \"my-game\") */\n slug?: string\n /** Glob pattern for fixture files, passed to import.meta.glob (e.g. \"/fixtures/puzzles/**\\/*.json\") */\n fixturesGlob?: string\n}\n\nconst SIMULATOR_URL = \"/@puzzmo-simulator-init.js\"\nconst VIRTUAL_ID = \"virtual:puzzmo-simulator\"\nconst RESOLVED_VIRTUAL_ID = \"\\0\" + VIRTUAL_ID\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n function generateCode(): string {\n const { fixturesGlob, ...config } = options\n\n const lines = [`import { createSimulator } from \"@puzzmo/sdk/simulator\"`]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n const configEntries = Object.entries(config).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return lines.join(\"\\n\")\n }\n\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n // Virtual module used internally for code generation and transformation.\n // Uses \\0 prefix so Vite's HTML processor won't try to inline it.\n resolveId(id) {\n if (id === VIRTUAL_ID) return RESOLVED_VIRTUAL_ID\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) return generateCode()\n },\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n\n // Serve the simulator init module. Registered before Vite's internal\n // middleware so the SPA fallback doesn't intercept it.\n server.middlewares.use(async (req, res, next) => {\n if (req.url?.split(\"?\")[0] !== SIMULATOR_URL) return next()\n\n const result = await server.transformRequest(VIRTUAL_ID)\n if (!result) return next()\n res.setHeader(\"Content-Type\", \"application/javascript\")\n res.end(result.code)\n })\n },\n\n // Inject a script tag whose src the browser will fetch.\n // The URL is NOT resolvable via resolveId (intentionally), so Vite's\n // HTML processor won't inline it. The middleware above serves it instead.\n transformIndexHtml() {\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\", src: SIMULATOR_URL },\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n\ntype BundlePluginOptions = {\n /** Entry file for the bundle */\n entry: string\n /** Output file name */\n outputFile: string\n}\n\nfunction createBundlePlugin(pluginName: string, defaults: BundlePluginOptions) {\n return (options: Partial<BundlePluginOptions> = {}): Plugin => {\n const { entry, outputFile } = { ...defaults, ...options }\n return {\n name: pluginName,\n apply: \"build\",\n async closeBundle() {\n try {\n await build({\n configFile: false,\n logLevel: \"warn\",\n build: {\n lib: {\n entry: path.isAbsolute(entry) ? entry : path.resolve(process.cwd(), entry),\n formats: [\"es\"],\n fileName: () => outputFile,\n },\n outDir: \"dist\",\n emptyOutDir: false,\n },\n })\n } catch (error) {\n console.error(`[${pluginName}] build failed:`, error)\n throw error\n }\n },\n }\n }\n}\n\nexport type AppBundlePluginOptions = Partial<BundlePluginOptions>\n\n/**\n * Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.\n *\n * The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure\n * SVG-string renderer used by the Puzzmo platform for puzzle previews.\n */\nexport const appBundlePlugin = createBundlePlugin(\"app-bundle\", { entry: \"src/appBundle.js\", outputFile: \"app-bundle.js\" })\n\nexport type EditorBundlePluginOptions = Partial<BundlePluginOptions>\n\n/** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */\nexport const editorBundlePlugin = createBundlePlugin(\"editor-bundle\", { entry: \"src/editorBundle.js\", outputFile: \"editor-bundle.js\" })\n"],"mappings":"iuBAAA,EAAO,QAAU,EAAA,0XCsBL,eAAA,CAPN,EAAgB,6BAChB,EAAa,2BACb,EAAsB,KAAO,EAGnC,SAAgB,EAAgB,EAAwC,EAAE,CAAU,CAClF,SAAS,GAAuB,CAC9B,GAAM,CAAE,gBAAA,EAAiB,EAAA,EAAW,EAAA,EAAA,CAE9B,EAAQ,CAAC,0DAA0D,CAErE,GACF,EAAM,KAAK,qCAAqC,KAAK,UAAU,EAAa,CAAC,oBAAoB,CAInG,IAAM,EADgB,OAAO,QAAQ,EAAO,CAAC,QAAQ,EAAG,KAAO,IAAM,IAAA,GAAU,CAC7C,KAAK,CAAC,EAAG,KAAO,GAAG,EAAE,IAAI,KAAK,UAAU,EAAE,GAAG,CAK/E,OAJI,GAAc,EAAY,KAAK,WAAW,CAE9C,EAAM,KAAK,qBAAqB,EAAY,KAAK,KAAK,CAAC,KAAK,CAErD,EAAM,KAAK;EAAK,CAGzB,MAAO,CACL,KAAM,mBACN,MAAO,QAIP,UAAU,EAAI,CACZ,GAAI,IAAO,EAAY,OAAO,GAGhC,KAAK,EAAI,CACP,GAAI,IAAO,EAAqB,OAAO,GAAc,EAGvD,gBAAgB,EAAQ,CACtB,EAAO,YAAY,IAAI,mBAAoB,EAAM,IAAQ,CACvD,EAAI,UAAU,eAAgB,YAAY,CAC1C,EAAI,IAAI;;;;;;;;0BAQS,EACjB,CAIF,EAAO,YAAY,IAAA,UAAA,qBAAW,EAAK,EAAK,EAAS,OAC/C,KAAA,EAAI,EAAI,MAAA,KAAA,IAAA,GAAA,EAAK,MAAM,IAAI,CAAC,MAAO,EAAe,OAAO,GAAM,CAE3D,IAAM,EAAS,MAAM,EAAO,iBAAiB,EAAW,CACxD,GAAI,CAAC,EAAQ,OAAO,GAAM,CAC1B,EAAI,UAAU,eAAgB,yBAAyB,CACvD,EAAI,IAAI,EAAO,KAAK,mBANQ,EAAK,EAAK,EAAA,oCAOtC,EAMJ,oBAAqB,CACnB,MAAO,CACL,CACE,IAAK,SACL,MAAO,CAAE,KAAM,SAAU,IAAK,EAAe,CAC7C,SAAU,OACX,CACF,EAEJ,CAUH,SAAS,EAAmB,EAAoB,EAA+B,CAC7E,OAAQ,EAAwC,EAAE,GAAa,CAC7D,GAAM,CAAE,QAAO,cAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAoB,EAAA,CAAa,EAAS,CACzD,MAAO,CACL,KAAM,EACN,MAAO,QACP,aAAM,uBAAc,CAClB,GAAI,CACF,MAAA,EAAA,EAAA,OAAY,CACV,WAAY,GACZ,SAAU,OACV,MAAO,CACL,IAAK,CACH,MAAO,EAAA,QAAK,WAAW,EAAM,CAAG,EAAQ,EAAA,QAAK,QAAQ,QAAQ,KAAK,CAAE,EAAM,CAC1E,QAAS,CAAC,KAAK,CACf,aAAgB,EACjB,CACD,OAAQ,OACR,YAAa,GACd,CACF,CAAC,OACK,EAAO,CAEd,MADA,QAAQ,MAAM,IAAI,EAAW,iBAAkB,EAAM,CAC/C,QAGX,EAYL,MAAa,EAAkB,EAAmB,aAAc,CAAE,MAAO,mBAAoB,WAAY,gBAAiB,CAAC,CAK9G,EAAqB,EAAmB,gBAAiB,CAAE,MAAO,sBAAuB,WAAY,mBAAoB,CAAC"}
1
+ {"version":3,"file":"vite.cjs","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import type { Plugin, ResolvedConfig } from \"vite\"\nimport { build } from \"vite\"\nimport path from \"path\"\nimport fs from \"fs\"\n\nexport type PuzzmoSimulatorPluginOptions = {\n /** Whether to auto-start the game after READY (default: true) */\n autoStart?: boolean\n /** Initial collapsed state (default: true) */\n collapsed?: boolean\n /** Glob pattern for fixture files, passed to import.meta.glob which is relative to the closest puzzmo.json. Defaults to \"/fixtures/puzzles/**\\/*.json\". Pass false to disable. */\n fixturesGlob?: string | false\n}\n\nconst simulatorURL = \"/@puzzmo-simulator-init.js\"\nconst virtualID = \"virtual:puzzmo-simulator\"\n\nexport type GameInfo = {\n /** Directory containing the puzzmo.json */\n dir: string\n slug: string\n displayName: string\n /** Vite-root-relative path to app bundle entry, if it exists */\n appBundlePath: string | null\n}\n\n/** Discover all games from puzzmo.json files under a root directory. */\nexport function discoverGames(viteRoot: string): Map<string, GameInfo> {\n const games = new Map<string, GameInfo>()\n const candidates = findPuzzmoJsonDirs(viteRoot, 3)\n if (fs.existsSync(path.join(viteRoot, \"puzzmo.json\"))) {\n candidates.unshift(viteRoot)\n }\n for (const dir of candidates) {\n try {\n const data = JSON.parse(fs.readFileSync(path.join(dir, \"puzzmo.json\"), \"utf-8\"))\n if (!data?.game?.slug) continue\n const bundleEntry = path.join(dir, \"src\", \"appBundle.js\")\n let appBundle: string | null = null\n if (fs.existsSync(bundleEntry)) {\n const relative = path.relative(viteRoot, bundleEntry)\n appBundle = \"/\" + relative.split(path.sep).join(\"/\")\n }\n games.set(data.game.slug, { dir, slug: data.game.slug, displayName: data.game.displayName, appBundlePath: appBundle })\n } catch {\n // skip invalid files\n }\n }\n return games\n}\n\n/** Resolve which game a request belongs to using the referer URL */\nexport function resolveGameFromReferer(referer: string | undefined, games: Map<string, GameInfo>, viteRoot: string): GameInfo | undefined {\n if (referer) {\n try {\n const refPath = new URL(referer).pathname\n for (const g of games.values()) {\n const relDir = \"/\" + path.relative(viteRoot, g.dir).split(path.sep).join(\"/\")\n if (refPath.startsWith(relDir + \"/\") || refPath === relDir) return g\n }\n } catch {\n // ignore malformed referer\n }\n }\n if (games.size === 1) return games.values().next().value\n return undefined\n}\n\n/** Generate the virtual module code for the simulator. */\nexport function generateSimulatorCode(options: PuzzmoSimulatorPluginOptions, game: GameInfo | undefined): string {\n const { fixturesGlob: fixturesOpt, ...config } = options\n const fixturesGlob = fixturesOpt === false ? null : (fixturesOpt ?? \"/fixtures/puzzles/**/*.json\")\n\n const lines = [`import { createSimulator } from \"@puzzmo/sdk/simulator\"`]\n\n if (fixturesGlob) {\n lines.push(`const fixtures = import.meta.glob(${JSON.stringify(fixturesGlob)}, { eager: true })`)\n }\n\n if (game?.appBundlePath) {\n lines.push(`import(${JSON.stringify(game.appBundlePath)}).then(m => {`)\n lines.push(` if (m.renderThumbnail) globalThis.renderThumbnail = m.renderThumbnail`)\n lines.push(`}).catch(() => {})`)\n }\n\n const simConfig = { ...config, ...(game?.slug ? { slug: game.slug } : {}) }\n const configEntries = Object.entries(simConfig).filter(([, v]) => v !== undefined)\n const configParts = configEntries.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)\n if (fixturesGlob) configParts.push(\"fixtures\")\n\n lines.push(`createSimulator({ ${configParts.join(\", \")} })`)\n\n return lines.join(\"\\n\")\n}\n\n/** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */\nexport function puzzmoSimulator(options: PuzzmoSimulatorPluginOptions = {}): Plugin {\n let games = new Map<string, GameInfo>()\n let viteRoot: string\n\n return {\n name: \"puzzmo-simulator\",\n apply: \"serve\",\n\n configResolved(config: ResolvedConfig) {\n viteRoot = config.root\n games = discoverGames(viteRoot)\n\n if (games.size === 0) {\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m\\x1b[2m no puzzmo.json files found\\x1b[22m`)\n } else {\n const names = [...games.values()].map((g) => `\\x1b[36m${g.slug}\\x1b[39m`)\n const label = games.size === 1 ? \"game\" : \"games\"\n config.logger.info(`\\x1b[33m\\x1b[1m PUZZMO \\x1b[22m\\x1b[39m found ${games.size} ${label}: ${names.join(\"\\x1b[2m, \\x1b[22m\")}`)\n }\n },\n\n resolveId(id) {\n if (id === virtualID || id.startsWith(virtualID + \"?\")) return \"\\0\" + id\n },\n\n load(id) {\n if (!id.startsWith(\"\\0\" + virtualID)) return\n const params = new URLSearchParams(id.split(\"?\")[1] || \"\")\n const gameSlug = params.get(\"game\")\n const game = gameSlug ? games.get(gameSlug) : games.size === 1 ? games.values().next().value : undefined\n return generateSimulatorCode(options, game)\n },\n\n configureServer(server) {\n server.middlewares.use(\"/oauth/callback\", (_req, res) => {\n res.setHeader(\"Content-Type\", \"text/html\")\n res.end(`<!DOCTYPE html>\n<html><head><title>Puzzmo OAuth</title></head>\n<body><script>\nvar params = new URLSearchParams(window.location.search);\nvar returnUrl = sessionStorage.getItem(\"oauth_return_url\") || \"/\";\nvar url = new URL(returnUrl);\nparams.forEach(function(v, k) { url.searchParams.set(k, v); });\nwindow.location.href = url.toString();\n</script></body></html>`)\n })\n\n // Serve the simulator init module, resolving the game from the referer\n server.middlewares.use(async (req, res, next) => {\n if (req.url?.split(\"?\")[0] !== simulatorURL) return next()\n\n const game = resolveGameFromReferer(req.headers.referer, games, viteRoot)\n const moduleID = virtualID + (game ? `?game=${game.slug}` : \"\")\n const result = await server.transformRequest(moduleID)\n if (!result) return next()\n res.setHeader(\"Content-Type\", \"application/javascript\")\n res.end(result.code)\n })\n },\n\n transformIndexHtml() {\n return [\n {\n tag: \"script\",\n attrs: { type: \"module\", src: simulatorURL },\n injectTo: \"head\",\n },\n ]\n },\n }\n}\n\ntype BundlePluginOptions = {\n /** Entry file for the bundle */\n entry: string\n /** Output file name */\n outputFile: string\n}\n\nfunction createBundlePlugin(pluginName: string, defaults: BundlePluginOptions) {\n return (options: Partial<BundlePluginOptions> = {}): Plugin => {\n const { entry, outputFile } = { ...defaults, ...options }\n return {\n name: pluginName,\n apply: \"build\",\n async closeBundle() {\n try {\n await build({\n configFile: false,\n logLevel: \"warn\",\n build: {\n lib: {\n entry: path.isAbsolute(entry) ? entry : path.resolve(process.cwd(), entry),\n formats: [\"es\"],\n fileName: () => outputFile,\n },\n outDir: \"dist\",\n emptyOutDir: false,\n },\n })\n } catch (error) {\n console.error(`[${pluginName}] build failed:`, error)\n throw error\n }\n },\n }\n }\n}\n\nexport type AppBundlePluginOptions = Partial<BundlePluginOptions>\n\n/**\n * Vite plugin that produces dist/app-bundle.js after the main build for app-level integrations.\n *\n * The bundle exports `renderThumbnail(puzzleStr, inputStr?, config?)` — a pure\n * SVG-string renderer used by the Puzzmo platform for puzzle previews.\n */\nexport const appBundlePlugin = createBundlePlugin(\"app-bundle\", { entry: \"src/appBundle.js\", outputFile: \"app-bundle.js\" })\n\nexport type EditorBundlePluginOptions = Partial<BundlePluginOptions>\n\n/** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */\nexport const editorBundlePlugin = createBundlePlugin(\"editor-bundle\", { entry: \"src/editorBundle.js\", outputFile: \"editor-bundle.js\" })\n\n/** Recursively find directories containing puzzmo.json, up to `maxDepth` levels deep. */\nexport const findPuzzmoJsonDirs = (root: string, maxDepth: number, depth = 0): string[] => {\n if (depth >= maxDepth) return []\n const results: string[] = []\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(root, { withFileTypes: true })\n } catch {\n return results\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue\n const dir = path.join(root, entry.name)\n if (fs.existsSync(path.join(dir, \"puzzmo.json\"))) {\n results.push(dir)\n }\n results.push(...findPuzzmoJsonDirs(dir, maxDepth, depth + 1))\n }\n return results\n}\n"],"mappings":"yjCAsEU,eAAA,CAxDJ,EAAe,6BACf,EAAY,2BAYlB,SAAgB,EAAc,EAAyC,CACrE,IAAM,EAAQ,IAAI,IACZ,EAAa,EAAmB,EAAU,EAAE,CAC9C,EAAA,QAAG,WAAW,EAAA,QAAK,KAAK,EAAU,cAAc,CAAC,EACnD,EAAW,QAAQ,EAAS,CAE9B,IAAK,IAAM,KAAO,EAChB,GAAI,OACF,IAAM,EAAO,KAAK,MAAM,EAAA,QAAG,aAAa,EAAA,QAAK,KAAK,EAAK,cAAc,CAAE,QAAQ,CAAC,CAChF,GAAI,EAAA,KAAA,OAAA,EAAC,EAAM,OAAA,OAAA,EAAM,MAAM,SACvB,IAAM,EAAc,EAAA,QAAK,KAAK,EAAK,MAAO,eAAe,CACrD,EAA2B,KAC3B,EAAA,QAAG,WAAW,EAAY,GAE5B,EAAY,IADK,EAAA,QAAK,SAAS,EAAU,EAAY,CAC1B,MAAM,EAAA,QAAK,IAAI,CAAC,KAAK,IAAI,EAEtD,EAAM,IAAI,EAAK,KAAK,KAAM,CAAE,MAAK,KAAM,EAAK,KAAK,KAAM,YAAa,EAAK,KAAK,YAAa,cAAe,EAAW,CAAC,SAChH,EAIV,OAAO,EAIT,SAAgB,EAAuB,EAA6B,EAA8B,EAAwC,CACxI,GAAI,EACF,GAAI,CACF,IAAM,EAAU,IAAI,IAAI,EAAQ,CAAC,SACjC,IAAK,IAAM,KAAK,EAAM,QAAQ,CAAE,CAC9B,IAAM,EAAS,IAAM,EAAA,QAAK,SAAS,EAAU,EAAE,IAAI,CAAC,MAAM,EAAA,QAAK,IAAI,CAAC,KAAK,IAAI,CAC7E,GAAI,EAAQ,WAAW,EAAS,IAAI,EAAI,IAAY,EAAQ,OAAO,WAE/D,EAIV,GAAI,EAAM,OAAS,EAAG,OAAO,EAAM,QAAQ,CAAC,MAAM,CAAC,MAKrD,SAAgB,EAAsB,EAAuC,EAAoC,CAC/G,GAAM,CAAE,aAAc,GAAA,EAAgB,EAAA,EAAW,EAAA,EAAA,CAC3C,EAAe,IAAgB,GAAQ,KAAQ,GAAA,KAAe,8BAAf,EAE/C,EAAQ,CAAC,0DAA0D,CAErE,GACF,EAAM,KAAK,qCAAqC,KAAK,UAAU,EAAa,CAAC,oBAAoB,CAGnG,GAAA,MAAI,EAAM,gBACR,EAAM,KAAK,UAAU,KAAK,UAAU,EAAK,cAAc,CAAC,eAAe,CACvE,EAAM,KAAK,0EAA0E,CACrF,EAAM,KAAK,qBAAqB,EAGlC,IAAM,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAiB,EAAA,CAAA,GAAA,MAAY,EAAM,KAAO,CAAE,KAAM,EAAK,KAAM,CAAG,EAAE,CAAG,CAErE,EADgB,OAAO,QAAQ,EAAU,CAAC,QAAQ,EAAG,KAAO,IAAM,IAAA,GAAU,CAChD,KAAK,CAAC,EAAG,KAAO,GAAG,EAAE,IAAI,KAAK,UAAU,EAAE,GAAG,CAK/E,OAJI,GAAc,EAAY,KAAK,WAAW,CAE9C,EAAM,KAAK,qBAAqB,EAAY,KAAK,KAAK,CAAC,KAAK,CAErD,EAAM,KAAK;EAAK,CAIzB,SAAgB,EAAgB,EAAwC,EAAE,CAAU,CAClF,IAAI,EAAQ,IAAI,IACZ,EAEJ,MAAO,CACL,KAAM,mBACN,MAAO,QAEP,eAAe,EAAwB,CAIrC,GAHA,EAAW,EAAO,KAClB,EAAQ,EAAc,EAAS,CAE3B,EAAM,OAAS,EACjB,EAAO,OAAO,KAAK,qFAAqF,KACnG,CACL,IAAM,EAAQ,CAAC,GAAG,EAAM,QAAQ,CAAC,CAAC,IAAK,GAAM,WAAW,EAAE,KAAK,UAAU,CACnE,EAAQ,EAAM,OAAS,EAAI,OAAS,QAC1C,EAAO,OAAO,KAAK,kDAAkD,EAAM,KAAK,GAAG,EAAM,IAAI,EAAM,KAAK,oBAAoB,GAAG,GAInI,UAAU,EAAI,CACZ,GAAI,IAAO,GAAa,EAAG,WAAW,EAAY,IAAI,CAAE,MAAO,KAAO,GAGxE,KAAK,EAAI,CACP,GAAI,CAAC,EAAG,WAAW,KAAO,EAAU,CAAE,OAEtC,IAAM,EADS,IAAI,gBAAgB,EAAG,MAAM,IAAI,CAAC,IAAM,GAAG,CAClC,IAAI,OAAO,CAEnC,OAAO,EAAsB,EADhB,EAAW,EAAM,IAAI,EAAS,CAAG,EAAM,OAAS,EAAI,EAAM,QAAQ,CAAC,MAAM,CAAC,MAAQ,IAAA,GACpD,EAG7C,gBAAgB,EAAQ,CACtB,EAAO,YAAY,IAAI,mBAAoB,EAAM,IAAQ,CACvD,EAAI,UAAU,eAAgB,YAAY,CAC1C,EAAI,IAAI;;;;;;;;0BAQS,EACjB,CAGF,EAAO,YAAY,IAAA,UAAA,qBAAW,EAAK,EAAK,EAAS,OAC/C,KAAA,EAAI,EAAI,MAAA,KAAA,IAAA,GAAA,EAAK,MAAM,IAAI,CAAC,MAAO,EAAc,OAAO,GAAM,CAE1D,IAAM,EAAO,EAAuB,EAAI,QAAQ,QAAS,EAAO,EAAS,CACnE,EAAW,GAAa,EAAO,SAAS,EAAK,OAAS,IACtD,EAAS,MAAM,EAAO,iBAAiB,EAAS,CACtD,GAAI,CAAC,EAAQ,OAAO,GAAM,CAC1B,EAAI,UAAU,eAAgB,yBAAyB,CACvD,EAAI,IAAI,EAAO,KAAK,mBARQ,EAAK,EAAK,EAAA,oCAStC,EAGJ,oBAAqB,CACnB,MAAO,CACL,CACE,IAAK,SACL,MAAO,CAAE,KAAM,SAAU,IAAK,EAAc,CAC5C,SAAU,OACX,CACF,EAEJ,CAUH,SAAS,EAAmB,EAAoB,EAA+B,CAC7E,OAAQ,EAAwC,EAAE,GAAa,CAC7D,GAAM,CAAE,QAAO,cAAA,EAAA,EAAA,EAAA,EAAA,EAAA,CAAoB,EAAA,CAAa,EAAS,CACzD,MAAO,CACL,KAAM,EACN,MAAO,QACP,aAAM,uBAAc,CAClB,GAAI,CACF,MAAA,EAAA,EAAA,OAAY,CACV,WAAY,GACZ,SAAU,OACV,MAAO,CACL,IAAK,CACH,MAAO,EAAA,QAAK,WAAW,EAAM,CAAG,EAAQ,EAAA,QAAK,QAAQ,QAAQ,KAAK,CAAE,EAAM,CAC1E,QAAS,CAAC,KAAK,CACf,aAAgB,EACjB,CACD,OAAQ,OACR,YAAa,GACd,CACF,CAAC,OACK,EAAO,CAEd,MADA,QAAQ,MAAM,IAAI,EAAW,iBAAkB,EAAM,CAC/C,QAGX,EAYL,MAAa,EAAkB,EAAmB,aAAc,CAAE,MAAO,mBAAoB,WAAY,gBAAiB,CAAC,CAK9G,EAAqB,EAAmB,gBAAiB,CAAE,MAAO,sBAAuB,WAAY,mBAAoB,CAAC,CAG1H,GAAsB,EAAc,EAAkB,EAAQ,IAAgB,CACzF,GAAI,GAAS,EAAU,MAAO,EAAE,CAChC,IAAM,EAAoB,EAAE,CACxB,EACJ,GAAI,CACF,EAAU,EAAA,QAAG,YAAY,EAAM,CAAE,cAAe,GAAM,CAAC,SACjD,CACN,OAAO,EAET,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,EAAM,aAAa,EAAI,EAAM,KAAK,WAAW,IAAI,EAAI,EAAM,OAAS,eAAgB,SACzF,IAAM,EAAM,EAAA,QAAK,KAAK,EAAM,EAAM,KAAK,CACnC,EAAA,QAAG,WAAW,EAAA,QAAK,KAAK,EAAK,cAAc,CAAC,EAC9C,EAAQ,KAAK,EAAI,CAEnB,EAAQ,KAAK,GAAG,EAAmB,EAAK,EAAU,EAAQ,EAAE,CAAC,CAE/D,OAAO"}
package/dist/vite.d.ts CHANGED
@@ -4,11 +4,23 @@ export type PuzzmoSimulatorPluginOptions = {
4
4
  autoStart?: boolean;
5
5
  /** Initial collapsed state (default: true) */
6
6
  collapsed?: boolean;
7
- /** Game slug for API features (e.g. "crossword", "my-game") */
8
- slug?: string;
9
- /** Glob pattern for fixture files, passed to import.meta.glob (e.g. "/fixtures/puzzles/**\/*.json") */
10
- fixturesGlob?: string;
7
+ /** Glob pattern for fixture files, passed to import.meta.glob which is relative to the closest puzzmo.json. Defaults to "/fixtures/puzzles/**\/*.json". Pass false to disable. */
8
+ fixturesGlob?: string | false;
11
9
  };
10
+ export type GameInfo = {
11
+ /** Directory containing the puzzmo.json */
12
+ dir: string;
13
+ slug: string;
14
+ displayName: string;
15
+ /** Vite-root-relative path to app bundle entry, if it exists */
16
+ appBundlePath: string | null;
17
+ };
18
+ /** Discover all games from puzzmo.json files under a root directory. */
19
+ export declare function discoverGames(viteRoot: string): Map<string, GameInfo>;
20
+ /** Resolve which game a request belongs to using the referer URL */
21
+ export declare function resolveGameFromReferer(referer: string | undefined, games: Map<string, GameInfo>, viteRoot: string): GameInfo | undefined;
22
+ /** Generate the virtual module code for the simulator. */
23
+ export declare function generateSimulatorCode(options: PuzzmoSimulatorPluginOptions, game: GameInfo | undefined): string;
12
24
  /** Vite plugin that injects the Puzzmo simulator in dev mode and handles OAuth callbacks. */
13
25
  export declare function puzzmoSimulator(options?: PuzzmoSimulatorPluginOptions): Plugin;
14
26
  type BundlePluginOptions = {
@@ -28,5 +40,7 @@ export declare const appBundlePlugin: (options?: Partial<BundlePluginOptions>) =
28
40
  export type EditorBundlePluginOptions = Partial<BundlePluginOptions>;
29
41
  /** Vite plugin that produces dist/editor-bundle.js after the main build for editor-level integrations. */
30
42
  export declare const editorBundlePlugin: (options?: Partial<BundlePluginOptions>) => Plugin<any>;
43
+ /** Recursively find directories containing puzzmo.json, up to `maxDepth` levels deep. */
44
+ export declare const findPuzzmoJsonDirs: (root: string, maxDepth: number, depth?: number) => string[];
31
45
  export {};
32
46
  //# sourceMappingURL=vite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAIlC,MAAM,MAAM,4BAA4B,GAAG;IACzC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAMD,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,OAAO,GAAE,4BAAiC,GAAG,MAAM,CAwElF;AAED,KAAK,mBAAmB,GAAG;IACzB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAgCD,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,eAAe,yDAA+F,CAAA;AAE3H,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEpE,0GAA0G;AAC1G,eAAO,MAAM,kBAAkB,yDAAwG,CAAA"}
1
+ {"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAkB,MAAM,MAAM,CAAA;AAKlD,MAAM,MAAM,4BAA4B,GAAG;IACzC,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,kLAAkL;IAClL,YAAY,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC9B,CAAA;AAKD,MAAM,MAAM,QAAQ,GAAG;IACrB,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,CAAA;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAsBrE;AAED,oEAAoE;AACpE,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAcxI;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,EAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAwB/G;AAED,6FAA6F;AAC7F,wBAAgB,eAAe,CAAC,OAAO,GAAE,4BAAiC,GAAG,MAAM,CAsElF;AAED,KAAK,mBAAmB,GAAG;IACzB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,uBAAuB;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAgCD,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,eAAe,yDAA+F,CAAA;AAE3H,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAEpE,0GAA0G;AAC1G,eAAO,MAAM,kBAAkB,yDAAwG,CAAA;AAEvI,yFAAyF;AACzF,eAAO,MAAM,kBAAkB,8DAkB9B,CAAA"}