@almadar/ui 2.15.8 → 2.15.10

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 (125) hide show
  1. package/dist/components/atoms/ContentSection.d.ts +16 -0
  2. package/dist/components/atoms/SectionHeader.d.ts +14 -0
  3. package/dist/components/atoms/StatCard.d.ts +13 -0
  4. package/dist/components/atoms/index.d.ts +3 -0
  5. package/dist/components/atoms/svg/SvgBranch.d.ts +12 -0
  6. package/dist/components/atoms/svg/SvgConnection.d.ts +13 -0
  7. package/dist/components/atoms/svg/SvgFlow.d.ts +10 -0
  8. package/dist/components/atoms/svg/SvgGrid.d.ts +14 -0
  9. package/dist/components/atoms/svg/SvgLobe.d.ts +13 -0
  10. package/dist/components/atoms/svg/SvgMesh.d.ts +12 -0
  11. package/dist/components/atoms/svg/SvgMorph.d.ts +11 -0
  12. package/dist/components/atoms/svg/SvgNode.d.ts +12 -0
  13. package/dist/components/atoms/svg/SvgPulse.d.ts +12 -0
  14. package/dist/components/atoms/svg/SvgRing.d.ts +13 -0
  15. package/dist/components/atoms/svg/SvgShield.d.ts +11 -0
  16. package/dist/components/atoms/svg/SvgStack.d.ts +13 -0
  17. package/dist/components/atoms/svg/index.d.ts +12 -0
  18. package/dist/{chunk-ACUO2BBW.js → components/index.cjs} +24764 -16677
  19. package/dist/components/index.js +37757 -889
  20. package/dist/components/molecules/AnimatedCounter.d.ts +18 -0
  21. package/dist/components/molecules/ArticleSection.d.ts +18 -0
  22. package/dist/components/molecules/CTABanner.d.ts +31 -0
  23. package/dist/components/molecules/CaseStudyCard.d.ts +24 -0
  24. package/dist/components/molecules/CodeExample.d.ts +23 -0
  25. package/dist/components/molecules/CommunityLinks.d.ts +25 -0
  26. package/dist/components/molecules/DocBreadcrumb.d.ts +20 -0
  27. package/dist/components/molecules/DocCodeBlock.d.ts +13 -0
  28. package/dist/components/molecules/DocPagination.d.ts +14 -0
  29. package/dist/components/molecules/DocSearch.d.ts +15 -0
  30. package/dist/components/molecules/DocSidebar.d.ts +24 -0
  31. package/dist/components/molecules/DocTOC.d.ts +24 -0
  32. package/dist/components/molecules/FeatureCard.d.ts +26 -0
  33. package/dist/components/molecules/FeatureGrid.d.ts +19 -0
  34. package/dist/components/molecules/GradientDivider.d.ts +14 -0
  35. package/dist/components/molecules/HeroSection.d.ts +36 -0
  36. package/dist/components/molecules/InstallBox.d.ts +16 -0
  37. package/dist/components/molecules/MarketingFooter.d.ts +27 -0
  38. package/dist/components/molecules/PricingCard.d.ts +21 -0
  39. package/dist/components/molecules/PricingGrid.d.ts +13 -0
  40. package/dist/components/molecules/PullQuote.d.ts +14 -0
  41. package/dist/components/molecules/ServiceCatalog.d.ts +19 -0
  42. package/dist/components/molecules/ShowcaseCard.d.ts +20 -0
  43. package/dist/components/molecules/SocialProof.d.ts +25 -0
  44. package/dist/components/molecules/SplitSection.d.ts +21 -0
  45. package/dist/components/molecules/StatsGrid.d.ts +17 -0
  46. package/dist/components/molecules/StepFlow.d.ts +20 -0
  47. package/dist/components/molecules/TagCloud.d.ts +18 -0
  48. package/dist/components/molecules/TeamCard.d.ts +18 -0
  49. package/dist/components/molecules/index.d.ts +19 -0
  50. package/dist/components/molecules/svg/AIGenerates.d.ts +7 -0
  51. package/dist/components/molecules/svg/ClosedCircuit.d.ts +7 -0
  52. package/dist/components/molecules/svg/CommunityOwnership.d.ts +7 -0
  53. package/dist/components/molecules/svg/CompileAnywhere.d.ts +7 -0
  54. package/dist/components/molecules/svg/ComposableModels.d.ts +7 -0
  55. package/dist/components/molecules/svg/DescribeProveDeploy.d.ts +7 -0
  56. package/dist/components/molecules/svg/DomainGrid.d.ts +7 -0
  57. package/dist/components/molecules/svg/EventBus.d.ts +7 -0
  58. package/dist/components/molecules/svg/OrbitalUnit.d.ts +7 -0
  59. package/dist/components/molecules/svg/PlanVerifyRemember.d.ts +7 -0
  60. package/dist/components/molecules/svg/ProveCorrect.d.ts +7 -0
  61. package/dist/components/molecules/svg/ServiceLayers.d.ts +7 -0
  62. package/dist/components/molecules/svg/SharedReality.d.ts +7 -0
  63. package/dist/components/molecules/svg/StandardLibrary.d.ts +7 -0
  64. package/dist/components/molecules/svg/StateMachine.d.ts +7 -0
  65. package/dist/components/molecules/svg/WorldModel.d.ts +7 -0
  66. package/dist/components/molecules/svg/index.d.ts +16 -0
  67. package/dist/components/organisms/CaseStudyOrganism.d.ts +19 -0
  68. package/dist/components/organisms/FeatureGridOrganism.d.ts +20 -0
  69. package/dist/components/organisms/HeroOrganism.d.ts +18 -0
  70. package/dist/components/organisms/PricingOrganism.d.ts +19 -0
  71. package/dist/components/organisms/ShowcaseOrganism.d.ts +20 -0
  72. package/dist/components/organisms/StatsOrganism.d.ts +17 -0
  73. package/dist/components/organisms/StepFlowOrganism.d.ts +20 -0
  74. package/dist/components/organisms/TeamOrganism.d.ts +18 -0
  75. package/dist/components/organisms/game/three/index.cjs +2525 -0
  76. package/dist/components/organisms/game/three/index.js +1795 -50
  77. package/dist/components/organisms/index.d.ts +9 -0
  78. package/dist/components/organisms/marketing-types.d.ts +87 -0
  79. package/dist/components/templates/AboutPageTemplate.d.ts +26 -0
  80. package/dist/components/templates/FeatureDetailPageTemplate.d.ts +27 -0
  81. package/dist/components/templates/LandingPageTemplate.d.ts +31 -0
  82. package/dist/components/templates/PricingPageTemplate.d.ts +26 -0
  83. package/dist/components/templates/index.d.ts +4 -0
  84. package/dist/context/index.cjs +550 -0
  85. package/dist/context/index.js +420 -6
  86. package/dist/docs/index.cjs +4015 -0
  87. package/dist/docs/index.d.cts +412 -0
  88. package/dist/docs/index.d.ts +29 -0
  89. package/dist/docs/index.js +3977 -0
  90. package/dist/hooks/index.cjs +2606 -0
  91. package/dist/hooks/index.js +2535 -8
  92. package/dist/illustrations/index.cjs +3004 -0
  93. package/dist/illustrations/index.d.cts +261 -0
  94. package/dist/illustrations/index.d.ts +35 -0
  95. package/dist/illustrations/index.js +2971 -0
  96. package/dist/{chunk-XL7WB2O5.js → lib/index.cjs} +454 -274
  97. package/dist/lib/index.js +1407 -3
  98. package/dist/locales/index.cjs +340 -0
  99. package/dist/locales/index.js +105 -2
  100. package/dist/marketing/index.cjs +4683 -0
  101. package/dist/marketing/index.d.cts +831 -0
  102. package/dist/marketing/index.d.ts +62 -0
  103. package/dist/marketing/index.js +4626 -0
  104. package/dist/providers/index.cjs +4811 -0
  105. package/dist/providers/index.js +4765 -11
  106. package/dist/{chunk-K2D5D3WK.js → renderer/index.cjs} +101 -42
  107. package/dist/renderer/index.js +1036 -2
  108. package/dist/runtime/index.cjs +4400 -0
  109. package/dist/runtime/index.js +3615 -19
  110. package/dist/{chunk-N7MVUW4R.js → stores/index.cjs} +24 -1
  111. package/dist/stores/index.js +194 -2
  112. package/dist/tsup.config.d.ts +2 -1
  113. package/package.json +27 -12
  114. package/tailwind-preset.cjs +9 -0
  115. package/themes/index.css +22 -20
  116. package/dist/chunk-3HJHHULT.js +0 -93
  117. package/dist/chunk-3JGAROCW.js +0 -149
  118. package/dist/chunk-4N3BAPDB.js +0 -1667
  119. package/dist/chunk-CDIOHSKG.js +0 -661
  120. package/dist/chunk-DKQN5FVU.js +0 -279
  121. package/dist/chunk-JJHCOO34.js +0 -375
  122. package/dist/chunk-PKBMQBKP.js +0 -5
  123. package/dist/chunk-QIABKRCN.js +0 -107
  124. package/dist/chunk-SD3KVCY6.js +0 -1465
  125. package/dist/chunk-YXZM3WCF.js +0 -222
@@ -0,0 +1,4811 @@
1
+ 'use strict';
2
+
3
+ var React113 = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ require('react-dom');
6
+ require('@almadar/ui/context');
7
+ var LucideIcons = require('lucide-react');
8
+ var clsx = require('clsx');
9
+ var tailwindMerge = require('tailwind-merge');
10
+ require('@almadar/evaluator');
11
+ require('@almadar/patterns');
12
+ require('react-leaflet');
13
+ var L = require('leaflet');
14
+ require('leaflet/dist/leaflet.css');
15
+ require('react-router-dom');
16
+ var ReactMarkdown = require('react-markdown');
17
+ var remarkGfm = require('remark-gfm');
18
+ var remarkMath = require('remark-math');
19
+ var rehypeKatex = require('rehype-katex');
20
+ var SyntaxHighlighter = require('react-syntax-highlighter/dist/esm/prism');
21
+ var dark = require('react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus');
22
+ var fiber = require('@react-three/fiber');
23
+ var drei = require('@react-three/drei');
24
+ var THREE = require('three');
25
+ var GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
26
+ var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
27
+ var OBJLoader_js = require('three/examples/jsm/loaders/OBJLoader.js');
28
+
29
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
30
+
31
+ function _interopNamespace(e) {
32
+ if (e && e.__esModule) return e;
33
+ var n = Object.create(null);
34
+ if (e) {
35
+ Object.keys(e).forEach(function (k) {
36
+ if (k !== 'default') {
37
+ var d = Object.getOwnPropertyDescriptor(e, k);
38
+ Object.defineProperty(n, k, d.get ? d : {
39
+ enumerable: true,
40
+ get: function () { return e[k]; }
41
+ });
42
+ }
43
+ });
44
+ }
45
+ n.default = e;
46
+ return Object.freeze(n);
47
+ }
48
+
49
+ var React113__namespace = /*#__PURE__*/_interopNamespace(React113);
50
+ var LucideIcons__namespace = /*#__PURE__*/_interopNamespace(LucideIcons);
51
+ var L__default = /*#__PURE__*/_interopDefault(L);
52
+ var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
53
+ var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
54
+ var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
55
+ var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
56
+ var SyntaxHighlighter__default = /*#__PURE__*/_interopDefault(SyntaxHighlighter);
57
+ var dark__default = /*#__PURE__*/_interopDefault(dark);
58
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
59
+
60
+ var __defProp = Object.defineProperty;
61
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
62
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
63
+ var BUILT_IN_THEMES = [
64
+ {
65
+ name: "wireframe",
66
+ displayName: "Wireframe",
67
+ hasLightMode: true,
68
+ hasDarkMode: true
69
+ },
70
+ {
71
+ name: "minimalist",
72
+ displayName: "Minimalist",
73
+ hasLightMode: true,
74
+ hasDarkMode: true
75
+ },
76
+ {
77
+ name: "almadar",
78
+ displayName: "Almadar",
79
+ hasLightMode: true,
80
+ hasDarkMode: true
81
+ },
82
+ {
83
+ name: "trait-wars",
84
+ displayName: "Trait Wars",
85
+ hasLightMode: false,
86
+ hasDarkMode: true
87
+ },
88
+ // Extended themes
89
+ {
90
+ name: "ocean",
91
+ displayName: "Ocean",
92
+ hasLightMode: true,
93
+ hasDarkMode: true
94
+ },
95
+ {
96
+ name: "forest",
97
+ displayName: "Forest",
98
+ hasLightMode: true,
99
+ hasDarkMode: true
100
+ },
101
+ {
102
+ name: "sunset",
103
+ displayName: "Sunset",
104
+ hasLightMode: true,
105
+ hasDarkMode: true
106
+ },
107
+ {
108
+ name: "lavender",
109
+ displayName: "Lavender",
110
+ hasLightMode: true,
111
+ hasDarkMode: true
112
+ },
113
+ {
114
+ name: "rose",
115
+ displayName: "Rose",
116
+ hasLightMode: true,
117
+ hasDarkMode: true
118
+ },
119
+ {
120
+ name: "slate",
121
+ displayName: "Slate",
122
+ hasLightMode: true,
123
+ hasDarkMode: true
124
+ },
125
+ {
126
+ name: "ember",
127
+ displayName: "Ember",
128
+ hasLightMode: true,
129
+ hasDarkMode: true
130
+ },
131
+ {
132
+ name: "midnight",
133
+ displayName: "Midnight",
134
+ hasLightMode: true,
135
+ hasDarkMode: true
136
+ },
137
+ {
138
+ name: "sand",
139
+ displayName: "Sand",
140
+ hasLightMode: true,
141
+ hasDarkMode: true
142
+ },
143
+ {
144
+ name: "neon",
145
+ displayName: "Neon",
146
+ hasLightMode: true,
147
+ hasDarkMode: true
148
+ },
149
+ {
150
+ name: "arctic",
151
+ displayName: "Arctic",
152
+ hasLightMode: true,
153
+ hasDarkMode: true
154
+ },
155
+ {
156
+ name: "copper",
157
+ displayName: "Copper",
158
+ hasLightMode: true,
159
+ hasDarkMode: true
160
+ }
161
+ ];
162
+ var ThemeContext = React113.createContext(void 0);
163
+ var THEME_STORAGE_KEY = "theme";
164
+ var MODE_STORAGE_KEY = "theme-mode";
165
+ function getSystemMode() {
166
+ if (typeof window === "undefined") return "light";
167
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
168
+ }
169
+ function resolveMode(mode) {
170
+ if (mode === "system") {
171
+ return getSystemMode();
172
+ }
173
+ return mode;
174
+ }
175
+ var ThemeProvider = ({
176
+ children,
177
+ themes = [],
178
+ defaultTheme = "wireframe",
179
+ defaultMode = "system",
180
+ targetRef
181
+ }) => {
182
+ const availableThemes = React113.useMemo(() => {
183
+ const themeMap = /* @__PURE__ */ new Map();
184
+ BUILT_IN_THEMES.forEach((t) => themeMap.set(t.name, t));
185
+ themes.forEach((t) => themeMap.set(t.name, t));
186
+ return Array.from(themeMap.values());
187
+ }, [themes]);
188
+ const isScoped = !!targetRef;
189
+ const [theme, setThemeState] = React113.useState(() => {
190
+ if (isScoped || typeof window === "undefined") return defaultTheme;
191
+ const stored = localStorage.getItem(THEME_STORAGE_KEY);
192
+ const validThemes = [
193
+ ...BUILT_IN_THEMES.map((t) => t.name),
194
+ ...themes.map((t) => t.name)
195
+ ];
196
+ if (stored && validThemes.includes(stored)) {
197
+ return stored;
198
+ }
199
+ return defaultTheme;
200
+ });
201
+ const [mode, setModeState] = React113.useState(() => {
202
+ if (isScoped || typeof window === "undefined") return defaultMode;
203
+ const stored = localStorage.getItem(MODE_STORAGE_KEY);
204
+ if (stored === "light" || stored === "dark" || stored === "system") {
205
+ return stored;
206
+ }
207
+ return defaultMode;
208
+ });
209
+ const [resolvedMode, setResolvedMode] = React113.useState(
210
+ () => resolveMode(mode)
211
+ );
212
+ const appliedTheme = React113.useMemo(
213
+ () => `${theme}-${resolvedMode}`,
214
+ [theme, resolvedMode]
215
+ );
216
+ React113.useEffect(() => {
217
+ const updateResolved = () => {
218
+ setResolvedMode(resolveMode(mode));
219
+ };
220
+ updateResolved();
221
+ if (mode === "system") {
222
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
223
+ const handleChange = () => updateResolved();
224
+ mediaQuery.addEventListener("change", handleChange);
225
+ return () => mediaQuery.removeEventListener("change", handleChange);
226
+ }
227
+ return void 0;
228
+ }, [mode]);
229
+ React113.useEffect(() => {
230
+ if (isScoped) {
231
+ if (targetRef?.current) {
232
+ targetRef.current.setAttribute("data-theme", appliedTheme);
233
+ targetRef.current.classList.remove("light", "dark");
234
+ targetRef.current.classList.add(resolvedMode);
235
+ }
236
+ return;
237
+ }
238
+ const root = document.documentElement;
239
+ root.setAttribute("data-theme", appliedTheme);
240
+ root.classList.remove("light", "dark");
241
+ root.classList.add(resolvedMode);
242
+ }, [appliedTheme, resolvedMode, targetRef, isScoped]);
243
+ const setTheme = React113.useCallback(
244
+ (newTheme) => {
245
+ const validTheme = availableThemes.find((t) => t.name === newTheme);
246
+ if (validTheme) {
247
+ setThemeState(newTheme);
248
+ if (!isScoped && typeof window !== "undefined") {
249
+ localStorage.setItem(THEME_STORAGE_KEY, newTheme);
250
+ }
251
+ } else {
252
+ console.warn(
253
+ `Theme "${newTheme}" not found. Available: ${availableThemes.map((t) => t.name).join(", ")}`
254
+ );
255
+ }
256
+ },
257
+ [availableThemes]
258
+ );
259
+ const setMode = React113.useCallback((newMode) => {
260
+ setModeState(newMode);
261
+ if (!isScoped && typeof window !== "undefined") {
262
+ localStorage.setItem(MODE_STORAGE_KEY, newMode);
263
+ }
264
+ }, []);
265
+ const toggleMode = React113.useCallback(() => {
266
+ const newMode = resolvedMode === "dark" ? "light" : "dark";
267
+ setMode(newMode);
268
+ }, [resolvedMode, setMode]);
269
+ const contextValue = React113.useMemo(
270
+ () => ({
271
+ theme,
272
+ mode,
273
+ resolvedMode,
274
+ setTheme,
275
+ setMode,
276
+ toggleMode,
277
+ availableThemes,
278
+ appliedTheme
279
+ }),
280
+ [
281
+ theme,
282
+ mode,
283
+ resolvedMode,
284
+ setTheme,
285
+ setMode,
286
+ toggleMode,
287
+ availableThemes,
288
+ appliedTheme
289
+ ]
290
+ );
291
+ return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: contextValue, children });
292
+ };
293
+ function setGlobalEventBus(bus) {
294
+ if (typeof window !== "undefined") {
295
+ window.__kflowEventBus = bus;
296
+ }
297
+ }
298
+ function getGlobalEventBus() {
299
+ if (typeof window !== "undefined") {
300
+ return window.__kflowEventBus ?? null;
301
+ }
302
+ return null;
303
+ }
304
+ var fallbackListeners = /* @__PURE__ */ new Map();
305
+ var fallbackAnyListeners = /* @__PURE__ */ new Set();
306
+ var fallbackEventBus = {
307
+ emit: (type, payload) => {
308
+ const event = {
309
+ type,
310
+ payload,
311
+ timestamp: Date.now()
312
+ };
313
+ const handlers = fallbackListeners.get(type);
314
+ if (handlers) {
315
+ handlers.forEach((handler) => {
316
+ try {
317
+ handler(event);
318
+ } catch (error) {
319
+ console.error(`[EventBus] Error in listener for '${type}':`, error);
320
+ }
321
+ });
322
+ }
323
+ fallbackAnyListeners.forEach((handler) => {
324
+ try {
325
+ handler(event);
326
+ } catch (error) {
327
+ console.error(`[EventBus] Error in onAny listener for '${type}':`, error);
328
+ }
329
+ });
330
+ },
331
+ on: (type, listener) => {
332
+ if (!fallbackListeners.has(type)) {
333
+ fallbackListeners.set(type, /* @__PURE__ */ new Set());
334
+ }
335
+ fallbackListeners.get(type).add(listener);
336
+ return () => {
337
+ const handlers = fallbackListeners.get(type);
338
+ if (handlers) {
339
+ handlers.delete(listener);
340
+ if (handlers.size === 0) {
341
+ fallbackListeners.delete(type);
342
+ }
343
+ }
344
+ };
345
+ },
346
+ once: (type, listener) => {
347
+ const wrappedListener = (event) => {
348
+ fallbackListeners.get(type)?.delete(wrappedListener);
349
+ listener(event);
350
+ };
351
+ return fallbackEventBus.on(type, wrappedListener);
352
+ },
353
+ hasListeners: (type) => {
354
+ const handlers = fallbackListeners.get(type);
355
+ return handlers !== void 0 && handlers.size > 0;
356
+ },
357
+ onAny: (listener) => {
358
+ fallbackAnyListeners.add(listener);
359
+ return () => {
360
+ fallbackAnyListeners.delete(listener);
361
+ };
362
+ }
363
+ };
364
+ function useEventBus() {
365
+ const context = React113.useContext(EventBusContext);
366
+ return context ?? getGlobalEventBus() ?? fallbackEventBus;
367
+ }
368
+ function useEmitEvent() {
369
+ const eventBus = useEventBus();
370
+ return React113.useCallback(
371
+ (type, payload) => {
372
+ eventBus.emit(type, payload);
373
+ },
374
+ [eventBus]
375
+ );
376
+ }
377
+ var EventBusContext = React113.createContext(null);
378
+ function EventBusProvider({ children, debug: debug2 = false }) {
379
+ const listenersRef = React113.useRef(/* @__PURE__ */ new Map());
380
+ const anyListenersRef = React113.useRef(/* @__PURE__ */ new Set());
381
+ const deprecationWarningShown = React113.useRef(false);
382
+ const getSelectedEntity = React113.useCallback(() => {
383
+ if (!deprecationWarningShown.current) {
384
+ console.warn(
385
+ "[EventBus] getSelectedEntity is deprecated. Use SelectionProvider and useSelection hook instead. See SelectionProvider.tsx for migration guide."
386
+ );
387
+ deprecationWarningShown.current = true;
388
+ }
389
+ return null;
390
+ }, []);
391
+ const clearSelectedEntity = React113.useCallback(() => {
392
+ if (!deprecationWarningShown.current) {
393
+ console.warn(
394
+ "[EventBus] clearSelectedEntity is deprecated. Use SelectionProvider and useSelection hook instead. See SelectionProvider.tsx for migration guide."
395
+ );
396
+ deprecationWarningShown.current = true;
397
+ }
398
+ }, []);
399
+ const emit = React113.useCallback((type, payload) => {
400
+ const event = {
401
+ type,
402
+ payload,
403
+ timestamp: Date.now()
404
+ };
405
+ const listeners7 = listenersRef.current.get(type);
406
+ const listenerCount = listeners7?.size ?? 0;
407
+ if (debug2) {
408
+ if (listenerCount > 0) {
409
+ console.log(`[EventBus] Emit: ${type} \u2192 ${listenerCount} listener(s)`, payload);
410
+ } else {
411
+ console.warn(`[EventBus] Emit: ${type} (NO LISTENERS - event may be lost!)`, payload);
412
+ }
413
+ }
414
+ if (listeners7) {
415
+ const listenersCopy = Array.from(listeners7);
416
+ for (const listener of listenersCopy) {
417
+ try {
418
+ listener(event);
419
+ } catch (error) {
420
+ console.error(`[EventBus] Error in listener for '${type}':`, error);
421
+ }
422
+ }
423
+ }
424
+ const anyListeners = Array.from(anyListenersRef.current);
425
+ for (const listener of anyListeners) {
426
+ try {
427
+ listener(event);
428
+ } catch (error) {
429
+ console.error(`[EventBus] Error in onAny listener for '${type}':`, error);
430
+ }
431
+ }
432
+ }, [debug2]);
433
+ const on = React113.useCallback((type, listener) => {
434
+ if (!listenersRef.current.has(type)) {
435
+ listenersRef.current.set(type, /* @__PURE__ */ new Set());
436
+ }
437
+ const listeners7 = listenersRef.current.get(type);
438
+ listeners7.add(listener);
439
+ if (debug2) {
440
+ console.log(`[EventBus] Subscribed to '${type}', total: ${listeners7.size}`);
441
+ }
442
+ return () => {
443
+ listeners7.delete(listener);
444
+ if (debug2) {
445
+ console.log(`[EventBus] Unsubscribed from '${type}', remaining: ${listeners7.size}`);
446
+ }
447
+ if (listeners7.size === 0) {
448
+ listenersRef.current.delete(type);
449
+ }
450
+ };
451
+ }, [debug2]);
452
+ const once = React113.useCallback((type, listener) => {
453
+ const wrappedListener = (event) => {
454
+ listenersRef.current.get(type)?.delete(wrappedListener);
455
+ listener(event);
456
+ };
457
+ return on(type, wrappedListener);
458
+ }, [on]);
459
+ const hasListeners = React113.useCallback((type) => {
460
+ const listeners7 = listenersRef.current.get(type);
461
+ return listeners7 !== void 0 && listeners7.size > 0;
462
+ }, []);
463
+ const onAny = React113.useCallback((listener) => {
464
+ anyListenersRef.current.add(listener);
465
+ if (debug2) {
466
+ console.log(`[EventBus] onAny subscribed, total: ${anyListenersRef.current.size}`);
467
+ }
468
+ return () => {
469
+ anyListenersRef.current.delete(listener);
470
+ if (debug2) {
471
+ console.log(`[EventBus] onAny unsubscribed, remaining: ${anyListenersRef.current.size}`);
472
+ }
473
+ };
474
+ }, [debug2]);
475
+ const contextValue = React113.useMemo(
476
+ () => ({
477
+ emit,
478
+ on,
479
+ once,
480
+ hasListeners,
481
+ onAny,
482
+ getSelectedEntity,
483
+ clearSelectedEntity
484
+ }),
485
+ [emit, on, once, hasListeners, onAny, getSelectedEntity, clearSelectedEntity]
486
+ );
487
+ React113.useEffect(() => {
488
+ setGlobalEventBus(contextValue);
489
+ return () => {
490
+ setGlobalEventBus(null);
491
+ };
492
+ }, [contextValue]);
493
+ return /* @__PURE__ */ jsxRuntime.jsx(EventBusContext.Provider, { value: contextValue, children });
494
+ }
495
+ var SelectionContext = React113.createContext(null);
496
+ var defaultCompareEntities = (a, b) => {
497
+ if (a === b) return true;
498
+ if (!a || !b) return false;
499
+ if (typeof a === "object" && typeof b === "object") {
500
+ const aId = a.id;
501
+ const bId = b.id;
502
+ return aId !== void 0 && aId === bId;
503
+ }
504
+ return false;
505
+ };
506
+ function SelectionProvider({
507
+ children,
508
+ debug: debug2 = false,
509
+ compareEntities = defaultCompareEntities
510
+ }) {
511
+ const eventBus = useEventBus();
512
+ const [selected, setSelectedState] = React113.useState(null);
513
+ const setSelected = React113.useCallback(
514
+ (entity) => {
515
+ setSelectedState(entity);
516
+ if (debug2) {
517
+ console.log("[SelectionProvider] Selection set:", entity);
518
+ }
519
+ },
520
+ [debug2]
521
+ );
522
+ const clearSelection = React113.useCallback(() => {
523
+ setSelectedState(null);
524
+ if (debug2) {
525
+ console.log("[SelectionProvider] Selection cleared");
526
+ }
527
+ }, [debug2]);
528
+ const isSelected = React113.useCallback(
529
+ (entity) => {
530
+ return compareEntities(selected, entity);
531
+ },
532
+ [selected, compareEntities]
533
+ );
534
+ React113.useEffect(() => {
535
+ const handleSelect = (event) => {
536
+ const row = event.payload?.row;
537
+ if (row) {
538
+ setSelected(row);
539
+ if (debug2) {
540
+ console.log(`[SelectionProvider] ${event.type} received:`, row);
541
+ }
542
+ }
543
+ };
544
+ const handleDeselect = (event) => {
545
+ clearSelection();
546
+ if (debug2) {
547
+ console.log(`[SelectionProvider] ${event.type} received - clearing selection`);
548
+ }
549
+ };
550
+ const unsubView = eventBus.on("UI:VIEW", handleSelect);
551
+ const unsubSelect = eventBus.on("UI:SELECT", handleSelect);
552
+ const unsubClose = eventBus.on("UI:CLOSE", handleDeselect);
553
+ const unsubDeselect = eventBus.on("UI:DESELECT", handleDeselect);
554
+ const unsubCancel = eventBus.on("UI:CANCEL", handleDeselect);
555
+ return () => {
556
+ unsubView();
557
+ unsubSelect();
558
+ unsubClose();
559
+ unsubDeselect();
560
+ unsubCancel();
561
+ };
562
+ }, [eventBus, setSelected, clearSelection, debug2]);
563
+ const contextValue = {
564
+ selected,
565
+ setSelected,
566
+ clearSelection,
567
+ isSelected
568
+ };
569
+ return /* @__PURE__ */ jsxRuntime.jsx(SelectionContext.Provider, { value: contextValue, children });
570
+ }
571
+ function useSelection() {
572
+ const context = React113.useContext(SelectionContext);
573
+ if (!context) {
574
+ throw new Error("useSelection must be used within a SelectionProvider");
575
+ }
576
+ return context;
577
+ }
578
+ function useSelectionOptional() {
579
+ const context = React113.useContext(SelectionContext);
580
+ return context;
581
+ }
582
+ var FetchedDataContext = React113.createContext(null);
583
+ function FetchedDataProvider({
584
+ initialData,
585
+ children
586
+ }) {
587
+ const [state, setState] = React113.useState(() => ({
588
+ data: initialData || {},
589
+ fetchedAt: {},
590
+ loading: false,
591
+ error: null
592
+ }));
593
+ const getData = React113.useCallback(
594
+ (entityName) => {
595
+ return state.data[entityName] || [];
596
+ },
597
+ [state.data]
598
+ );
599
+ const getById = React113.useCallback(
600
+ (entityName, id) => {
601
+ const records = state.data[entityName];
602
+ return records?.find((r) => r.id === id);
603
+ },
604
+ [state.data]
605
+ );
606
+ const hasData = React113.useCallback(
607
+ (entityName) => {
608
+ return entityName in state.data && state.data[entityName].length > 0;
609
+ },
610
+ [state.data]
611
+ );
612
+ const getFetchedAt = React113.useCallback(
613
+ (entityName) => {
614
+ return state.fetchedAt[entityName];
615
+ },
616
+ [state.fetchedAt]
617
+ );
618
+ const setData = React113.useCallback((data) => {
619
+ const now = Date.now();
620
+ setState((prev) => ({
621
+ ...prev,
622
+ data: {
623
+ ...prev.data,
624
+ ...data
625
+ },
626
+ fetchedAt: {
627
+ ...prev.fetchedAt,
628
+ ...Object.keys(data).reduce(
629
+ (acc, key) => ({ ...acc, [key]: now }),
630
+ {}
631
+ )
632
+ },
633
+ loading: false,
634
+ error: null
635
+ }));
636
+ }, []);
637
+ const clearData = React113.useCallback(() => {
638
+ setState((prev) => ({
639
+ ...prev,
640
+ data: {},
641
+ fetchedAt: {}
642
+ }));
643
+ }, []);
644
+ const clearEntity = React113.useCallback((entityName) => {
645
+ setState((prev) => {
646
+ const newData = { ...prev.data };
647
+ const newFetchedAt = { ...prev.fetchedAt };
648
+ delete newData[entityName];
649
+ delete newFetchedAt[entityName];
650
+ return {
651
+ ...prev,
652
+ data: newData,
653
+ fetchedAt: newFetchedAt
654
+ };
655
+ });
656
+ }, []);
657
+ const setLoading = React113.useCallback((loading) => {
658
+ setState((prev) => ({ ...prev, loading }));
659
+ }, []);
660
+ const setError = React113.useCallback((error) => {
661
+ setState((prev) => ({ ...prev, error, loading: false }));
662
+ }, []);
663
+ const contextValue = React113.useMemo(
664
+ () => ({
665
+ getData,
666
+ getById,
667
+ hasData,
668
+ getFetchedAt,
669
+ setData,
670
+ clearData,
671
+ clearEntity,
672
+ loading: state.loading,
673
+ setLoading,
674
+ error: state.error,
675
+ setError
676
+ }),
677
+ [
678
+ getData,
679
+ getById,
680
+ hasData,
681
+ getFetchedAt,
682
+ setData,
683
+ clearData,
684
+ clearEntity,
685
+ state.loading,
686
+ setLoading,
687
+ state.error,
688
+ setError
689
+ ]
690
+ );
691
+ return /* @__PURE__ */ jsxRuntime.jsx(FetchedDataContext.Provider, { value: contextValue, children });
692
+ }
693
+ function useFetchedDataContext() {
694
+ return React113.useContext(FetchedDataContext);
695
+ }
696
+ function useFetchedData() {
697
+ const context = React113.useContext(FetchedDataContext);
698
+ if (!context) {
699
+ return {
700
+ getData: () => [],
701
+ getById: () => void 0,
702
+ hasData: () => false,
703
+ getFetchedAt: () => void 0,
704
+ setData: () => {
705
+ },
706
+ clearData: () => {
707
+ },
708
+ clearEntity: () => {
709
+ },
710
+ loading: false,
711
+ setLoading: () => {
712
+ },
713
+ error: null,
714
+ setError: () => {
715
+ }
716
+ };
717
+ }
718
+ return context;
719
+ }
720
+ function useFetchedEntity(entityName) {
721
+ const context = useFetchedData();
722
+ return {
723
+ /** All fetched records for this entity */
724
+ records: context.getData(entityName),
725
+ /** Get a record by ID */
726
+ getById: (id) => context.getById(entityName, id),
727
+ /** Whether data has been fetched for this entity */
728
+ hasData: context.hasData(entityName),
729
+ /** When data was last fetched */
730
+ fetchedAt: context.getFetchedAt(entityName),
731
+ /** Whether data is loading */
732
+ loading: context.loading,
733
+ /** Current error */
734
+ error: context.error
735
+ };
736
+ }
737
+ var EntityDataContext = React113.createContext(null);
738
+ function EntityDataProvider({
739
+ adapter,
740
+ children
741
+ }) {
742
+ return React113__namespace.default.createElement(
743
+ EntityDataContext.Provider,
744
+ { value: adapter },
745
+ children
746
+ );
747
+ }
748
+ function cn(...inputs) {
749
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
750
+ }
751
+ var iconAliases = {
752
+ "close": LucideIcons__namespace.X,
753
+ "trash": LucideIcons__namespace.Trash2,
754
+ "loader": LucideIcons__namespace.Loader2,
755
+ "stop": LucideIcons__namespace.Square,
756
+ "volume": LucideIcons__namespace.Volume2,
757
+ "volume-off": LucideIcons__namespace.VolumeX,
758
+ "refresh": LucideIcons__namespace.RefreshCw,
759
+ "share": LucideIcons__namespace.Share2,
760
+ "sort-asc": LucideIcons__namespace.ArrowUpNarrowWide,
761
+ "sort-desc": LucideIcons__namespace.ArrowDownNarrowWide
762
+ };
763
+ function kebabToPascal(name) {
764
+ return name.split("-").map((part) => {
765
+ if (/^\d+$/.test(part)) return part;
766
+ return part.charAt(0).toUpperCase() + part.slice(1);
767
+ }).join("");
768
+ }
769
+ var resolvedCache = /* @__PURE__ */ new Map();
770
+ function resolveIcon(name) {
771
+ const cached = resolvedCache.get(name);
772
+ if (cached) return cached;
773
+ const resolved = doResolve(name);
774
+ resolvedCache.set(name, resolved);
775
+ return resolved;
776
+ }
777
+ function doResolve(name) {
778
+ if (iconAliases[name]) return iconAliases[name];
779
+ const pascalName = kebabToPascal(name);
780
+ const directLookup = LucideIcons__namespace[pascalName];
781
+ if (directLookup && typeof directLookup === "object") return directLookup;
782
+ const asIs = LucideIcons__namespace[name];
783
+ if (asIs && typeof asIs === "object") return asIs;
784
+ return LucideIcons__namespace.HelpCircle;
785
+ }
786
+ var paddingStyles = {
787
+ none: "p-0",
788
+ xs: "p-1",
789
+ sm: "p-2",
790
+ md: "p-4",
791
+ lg: "p-6",
792
+ xl: "p-8",
793
+ "2xl": "p-12"
794
+ };
795
+ var paddingXStyles = {
796
+ none: "px-0",
797
+ xs: "px-1",
798
+ sm: "px-2",
799
+ md: "px-4",
800
+ lg: "px-6",
801
+ xl: "px-8",
802
+ "2xl": "px-12"
803
+ };
804
+ var paddingYStyles = {
805
+ none: "py-0",
806
+ xs: "py-1",
807
+ sm: "py-2",
808
+ md: "py-4",
809
+ lg: "py-6",
810
+ xl: "py-8",
811
+ "2xl": "py-12"
812
+ };
813
+ var marginStyles = {
814
+ none: "m-0",
815
+ xs: "m-1",
816
+ sm: "m-2",
817
+ md: "m-4",
818
+ lg: "m-6",
819
+ xl: "m-8",
820
+ "2xl": "m-12",
821
+ auto: "m-auto"
822
+ };
823
+ var marginXStyles = {
824
+ none: "mx-0",
825
+ xs: "mx-1",
826
+ sm: "mx-2",
827
+ md: "mx-4",
828
+ lg: "mx-6",
829
+ xl: "mx-8",
830
+ "2xl": "mx-12",
831
+ auto: "mx-auto"
832
+ };
833
+ var marginYStyles = {
834
+ none: "my-0",
835
+ xs: "my-1",
836
+ sm: "my-2",
837
+ md: "my-4",
838
+ lg: "my-6",
839
+ xl: "my-8",
840
+ "2xl": "my-12",
841
+ auto: "my-auto"
842
+ };
843
+ var bgStyles = {
844
+ transparent: "bg-transparent",
845
+ primary: "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
846
+ secondary: "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
847
+ muted: "bg-[var(--color-muted)] text-[var(--color-foreground)]",
848
+ accent: "bg-[var(--color-accent)] text-[var(--color-accent-foreground)]",
849
+ surface: "bg-[var(--color-card)]",
850
+ overlay: "bg-[var(--color-card)]/80 backdrop-blur-sm"
851
+ };
852
+ var roundedStyles = {
853
+ none: "rounded-none",
854
+ sm: "rounded-[var(--radius-sm)]",
855
+ md: "rounded-[var(--radius-md)]",
856
+ lg: "rounded-[var(--radius-lg)]",
857
+ xl: "rounded-[var(--radius-xl)]",
858
+ "2xl": "rounded-[var(--radius-xl)]",
859
+ full: "rounded-[var(--radius-full)]"
860
+ };
861
+ var shadowStyles = {
862
+ none: "shadow-none",
863
+ sm: "shadow-[var(--shadow-sm)]",
864
+ md: "shadow-[var(--shadow-main)]",
865
+ lg: "shadow-[var(--shadow-lg)]",
866
+ xl: "shadow-[var(--shadow-lg)]"
867
+ };
868
+ var displayStyles = {
869
+ block: "block",
870
+ inline: "inline",
871
+ "inline-block": "inline-block",
872
+ flex: "flex",
873
+ "inline-flex": "inline-flex",
874
+ grid: "grid"
875
+ };
876
+ var overflowStyles = {
877
+ auto: "overflow-auto",
878
+ hidden: "overflow-hidden",
879
+ visible: "overflow-visible",
880
+ scroll: "overflow-scroll"
881
+ };
882
+ var positionStyles = {
883
+ relative: "relative",
884
+ absolute: "absolute",
885
+ fixed: "fixed",
886
+ sticky: "sticky"
887
+ };
888
+ var Box = React113__namespace.default.forwardRef(
889
+ ({
890
+ padding,
891
+ paddingX,
892
+ paddingY,
893
+ margin,
894
+ marginX,
895
+ marginY,
896
+ bg = "transparent",
897
+ border = false,
898
+ rounded = "none",
899
+ shadow = "none",
900
+ display,
901
+ fullWidth = false,
902
+ fullHeight = false,
903
+ overflow,
904
+ position,
905
+ className,
906
+ children,
907
+ as: Component2 = "div",
908
+ action,
909
+ actionPayload,
910
+ hoverEvent,
911
+ onClick,
912
+ onMouseEnter,
913
+ onMouseLeave,
914
+ ...rest
915
+ }, ref) => {
916
+ const eventBus = useEventBus();
917
+ const handleClick = React113.useCallback((e) => {
918
+ if (action) {
919
+ e.stopPropagation();
920
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
921
+ }
922
+ onClick?.(e);
923
+ }, [action, actionPayload, eventBus, onClick]);
924
+ const handleMouseEnter = React113.useCallback((e) => {
925
+ if (hoverEvent) {
926
+ eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
927
+ }
928
+ onMouseEnter?.(e);
929
+ }, [hoverEvent, eventBus, onMouseEnter]);
930
+ const handleMouseLeave = React113.useCallback((e) => {
931
+ if (hoverEvent) {
932
+ eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
933
+ }
934
+ onMouseLeave?.(e);
935
+ }, [hoverEvent, eventBus, onMouseLeave]);
936
+ const isClickable = action || onClick;
937
+ const Comp = Component2;
938
+ return /* @__PURE__ */ jsxRuntime.jsx(
939
+ Comp,
940
+ {
941
+ ref,
942
+ className: cn(
943
+ // Padding
944
+ padding && paddingStyles[padding],
945
+ paddingX && paddingXStyles[paddingX],
946
+ paddingY && paddingYStyles[paddingY],
947
+ // Margin
948
+ margin && marginStyles[margin],
949
+ marginX && marginXStyles[marginX],
950
+ marginY && marginYStyles[marginY],
951
+ // Background
952
+ bgStyles[bg],
953
+ // Border - uses theme variables
954
+ border && "border-[length:var(--border-width)] border-[var(--color-border)]",
955
+ // Rounded
956
+ roundedStyles[rounded],
957
+ // Shadow
958
+ shadowStyles[shadow],
959
+ // Display
960
+ display && displayStyles[display],
961
+ // Dimensions
962
+ fullWidth && "w-full",
963
+ fullHeight && "h-full",
964
+ // Overflow
965
+ overflow && overflowStyles[overflow],
966
+ // Position
967
+ position && positionStyles[position],
968
+ // Cursor for clickable
969
+ isClickable && "cursor-pointer",
970
+ className
971
+ ),
972
+ onClick: isClickable ? handleClick : void 0,
973
+ onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
974
+ onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
975
+ ...rest,
976
+ children
977
+ }
978
+ );
979
+ }
980
+ );
981
+ Box.displayName = "Box";
982
+ var variantStyles = {
983
+ h1: "text-4xl font-bold tracking-tight text-[var(--color-foreground)]",
984
+ h2: "text-3xl font-bold tracking-tight text-[var(--color-foreground)]",
985
+ h3: "text-2xl font-bold text-[var(--color-foreground)]",
986
+ h4: "text-xl font-bold text-[var(--color-foreground)]",
987
+ h5: "text-lg font-bold text-[var(--color-foreground)]",
988
+ h6: "text-base font-bold text-[var(--color-foreground)]",
989
+ heading: "text-2xl font-bold text-[var(--color-foreground)]",
990
+ subheading: "text-lg font-semibold text-[var(--color-foreground)]",
991
+ body1: "text-base font-normal text-[var(--color-foreground)]",
992
+ body2: "text-sm font-normal text-[var(--color-foreground)]",
993
+ body: "text-base font-normal text-[var(--color-foreground)]",
994
+ caption: "text-xs font-normal text-[var(--color-muted-foreground)]",
995
+ overline: "text-xs uppercase tracking-wide font-bold text-[var(--color-muted-foreground)]",
996
+ small: "text-sm font-normal text-[var(--color-foreground)]",
997
+ large: "text-lg font-medium text-[var(--color-foreground)]",
998
+ label: "text-sm font-medium text-[var(--color-foreground)]"
999
+ };
1000
+ var colorStyles = {
1001
+ primary: "text-[var(--color-foreground)]",
1002
+ secondary: "text-[var(--color-muted-foreground)]",
1003
+ muted: "text-[var(--color-muted-foreground)]",
1004
+ error: "text-[var(--color-error)]",
1005
+ success: "text-[var(--color-success)]",
1006
+ warning: "text-[var(--color-warning)]",
1007
+ inherit: "text-inherit"
1008
+ };
1009
+ var weightStyles = {
1010
+ light: "font-light",
1011
+ normal: "font-normal",
1012
+ medium: "font-medium",
1013
+ semibold: "font-semibold",
1014
+ bold: "font-bold"
1015
+ };
1016
+ var defaultElements = {
1017
+ h1: "h1",
1018
+ h2: "h2",
1019
+ h3: "h3",
1020
+ h4: "h4",
1021
+ h5: "h5",
1022
+ h6: "h6",
1023
+ heading: "h2",
1024
+ subheading: "h3",
1025
+ body1: "p",
1026
+ body2: "p",
1027
+ body: "p",
1028
+ caption: "span",
1029
+ overline: "span",
1030
+ small: "span",
1031
+ large: "p",
1032
+ label: "span"
1033
+ };
1034
+ var typographySizeStyles = {
1035
+ xs: "text-xs",
1036
+ sm: "text-sm",
1037
+ md: "text-base",
1038
+ lg: "text-lg",
1039
+ xl: "text-xl",
1040
+ "2xl": "text-2xl",
1041
+ "3xl": "text-3xl"
1042
+ };
1043
+ var overflowStyles2 = {
1044
+ visible: "overflow-visible",
1045
+ hidden: "overflow-hidden",
1046
+ wrap: "break-words overflow-hidden",
1047
+ "clamp-2": "overflow-hidden line-clamp-2",
1048
+ "clamp-3": "overflow-hidden line-clamp-3"
1049
+ };
1050
+ var Typography = ({
1051
+ variant: variantProp,
1052
+ level,
1053
+ color = "primary",
1054
+ align,
1055
+ weight,
1056
+ size,
1057
+ truncate = false,
1058
+ overflow,
1059
+ as,
1060
+ id,
1061
+ className,
1062
+ style,
1063
+ content,
1064
+ children
1065
+ }) => {
1066
+ const variant = variantProp ?? (level ? `h${level}` : "body1");
1067
+ const Component2 = as || defaultElements[variant];
1068
+ const Comp = Component2;
1069
+ return /* @__PURE__ */ jsxRuntime.jsx(
1070
+ Comp,
1071
+ {
1072
+ id,
1073
+ className: cn(
1074
+ variantStyles[variant],
1075
+ colorStyles[color],
1076
+ weight && weightStyles[weight],
1077
+ size && typographySizeStyles[size],
1078
+ align && `text-${align}`,
1079
+ truncate && "truncate overflow-hidden text-ellipsis",
1080
+ overflow && overflowStyles2[overflow],
1081
+ className
1082
+ ),
1083
+ style,
1084
+ children: children ?? content
1085
+ }
1086
+ );
1087
+ };
1088
+ Typography.displayName = "Typography";
1089
+ var variantStyles2 = {
1090
+ primary: [
1091
+ "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
1092
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1093
+ "shadow-[var(--shadow-sm)]",
1094
+ "hover:bg-[var(--color-primary-hover)] hover:shadow-[var(--shadow-hover)]",
1095
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
1096
+ ].join(" "),
1097
+ secondary: [
1098
+ "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
1099
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]",
1100
+ "hover:bg-[var(--color-secondary-hover)]",
1101
+ "active:scale-[var(--active-scale)]"
1102
+ ].join(" "),
1103
+ ghost: [
1104
+ "bg-transparent text-[var(--color-muted-foreground)]",
1105
+ "hover:text-[var(--color-foreground)] hover:bg-[var(--color-muted)]",
1106
+ "active:scale-[var(--active-scale)]"
1107
+ ].join(" "),
1108
+ danger: [
1109
+ "bg-[var(--color-surface)] text-[var(--color-error)]",
1110
+ "border-[length:var(--border-width)] border-[var(--color-error)]",
1111
+ "shadow-[var(--shadow-sm)]",
1112
+ "hover:bg-[var(--color-error)] hover:text-[var(--color-error-foreground)] hover:shadow-[var(--shadow-hover)]",
1113
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
1114
+ ].join(" "),
1115
+ success: [
1116
+ "bg-[var(--color-surface)] text-[var(--color-success)]",
1117
+ "border-[length:var(--border-width)] border-[var(--color-success)]",
1118
+ "shadow-[var(--shadow-sm)]",
1119
+ "hover:bg-[var(--color-success)] hover:text-[var(--color-success-foreground)] hover:shadow-[var(--shadow-hover)]",
1120
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
1121
+ ].join(" "),
1122
+ warning: [
1123
+ "bg-[var(--color-surface)] text-[var(--color-warning)]",
1124
+ "border-[length:var(--border-width)] border-[var(--color-warning)]",
1125
+ "shadow-[var(--shadow-sm)]",
1126
+ "hover:bg-[var(--color-warning)] hover:text-[var(--color-warning-foreground)] hover:shadow-[var(--shadow-hover)]",
1127
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
1128
+ ].join(" "),
1129
+ // "default" is an alias for secondary
1130
+ default: [
1131
+ "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
1132
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]",
1133
+ "hover:bg-[var(--color-secondary-hover)]",
1134
+ "active:scale-[var(--active-scale)]"
1135
+ ].join(" ")
1136
+ };
1137
+ variantStyles2.destructive = variantStyles2.danger;
1138
+ var sizeStyles2 = {
1139
+ sm: "px-3 py-1.5 text-sm",
1140
+ md: "px-4 py-2 text-sm",
1141
+ lg: "px-6 py-3 text-base"
1142
+ };
1143
+ var iconSizeStyles = {
1144
+ sm: "h-3.5 w-3.5",
1145
+ md: "h-4 w-4",
1146
+ lg: "h-5 w-5"
1147
+ };
1148
+ function resolveIconProp(value, sizeClass) {
1149
+ if (!value) return null;
1150
+ if (typeof value === "string") {
1151
+ const Resolved = resolveIcon(value);
1152
+ return Resolved ? /* @__PURE__ */ jsxRuntime.jsx(Resolved, { className: sizeClass }) : null;
1153
+ }
1154
+ if (typeof value === "function") {
1155
+ const IconComp = value;
1156
+ return /* @__PURE__ */ jsxRuntime.jsx(IconComp, { className: sizeClass });
1157
+ }
1158
+ if (React113__namespace.default.isValidElement(value)) {
1159
+ return value;
1160
+ }
1161
+ if (typeof value === "object" && value !== null && "render" in value) {
1162
+ const IconComp = value;
1163
+ return /* @__PURE__ */ jsxRuntime.jsx(IconComp, { className: sizeClass });
1164
+ }
1165
+ return value;
1166
+ }
1167
+ var Button = React113__namespace.default.forwardRef(
1168
+ ({
1169
+ className,
1170
+ variant = "primary",
1171
+ size = "md",
1172
+ isLoading = false,
1173
+ disabled,
1174
+ leftIcon,
1175
+ rightIcon,
1176
+ icon: iconProp,
1177
+ iconRight: iconRightProp,
1178
+ action,
1179
+ actionPayload,
1180
+ label,
1181
+ children,
1182
+ onClick,
1183
+ ...props
1184
+ }, ref) => {
1185
+ const eventBus = useEventBus();
1186
+ const leftIconValue = leftIcon || iconProp;
1187
+ const rightIconValue = rightIcon || iconRightProp;
1188
+ const resolvedLeftIcon = resolveIconProp(leftIconValue, iconSizeStyles[size]);
1189
+ const resolvedRightIcon = resolveIconProp(rightIconValue, iconSizeStyles[size]);
1190
+ const handleClick = (e) => {
1191
+ if (action) {
1192
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
1193
+ }
1194
+ onClick?.(e);
1195
+ };
1196
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1197
+ "button",
1198
+ {
1199
+ ref,
1200
+ disabled: disabled || isLoading,
1201
+ className: cn(
1202
+ "inline-flex items-center justify-center gap-2",
1203
+ "font-[var(--font-weight-medium)]",
1204
+ "rounded-[var(--radius-sm)]",
1205
+ "transition-all duration-[var(--transition-normal)]",
1206
+ "focus:outline-none focus:ring-[length:var(--focus-ring-width)] focus:ring-[var(--color-ring)] focus:ring-offset-[length:var(--focus-ring-offset)]",
1207
+ "disabled:opacity-50 disabled:cursor-not-allowed",
1208
+ variantStyles2[variant],
1209
+ sizeStyles2[size],
1210
+ className
1211
+ ),
1212
+ onClick: handleClick,
1213
+ ...props,
1214
+ "data-testid": props["data-testid"] ?? (action ? `action-${action}` : void 0),
1215
+ children: [
1216
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Loader2, { className: "h-4 w-4 animate-spin" }) : resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
1217
+ children || label,
1218
+ resolvedRightIcon && !isLoading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: resolvedRightIcon })
1219
+ ]
1220
+ }
1221
+ );
1222
+ }
1223
+ );
1224
+ Button.displayName = "Button";
1225
+ var variantStyles3 = {
1226
+ default: [
1227
+ "bg-[var(--color-muted)] text-[var(--color-foreground)]",
1228
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]"
1229
+ ].join(" "),
1230
+ primary: "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
1231
+ secondary: "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
1232
+ success: [
1233
+ "bg-[var(--color-surface)] text-[var(--color-success)]",
1234
+ "border-[length:var(--border-width)] border-[var(--color-success)]"
1235
+ ].join(" "),
1236
+ warning: [
1237
+ "bg-[var(--color-surface)] text-[var(--color-warning)]",
1238
+ "border-[length:var(--border-width)] border-[var(--color-warning)]"
1239
+ ].join(" "),
1240
+ danger: [
1241
+ "bg-[var(--color-surface)] text-[var(--color-error)]",
1242
+ "border-[length:var(--border-width)] border-[var(--color-error)]"
1243
+ ].join(" "),
1244
+ error: [
1245
+ "bg-[var(--color-surface)] text-[var(--color-error)]",
1246
+ "border-[length:var(--border-width)] border-[var(--color-error)]"
1247
+ ].join(" "),
1248
+ info: [
1249
+ "bg-[var(--color-surface)] text-[var(--color-info)]",
1250
+ "border-[length:var(--border-width)] border-[var(--color-info)]"
1251
+ ].join(" "),
1252
+ neutral: [
1253
+ "bg-[var(--color-muted)] text-[var(--color-muted-foreground)]",
1254
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]"
1255
+ ].join(" ")
1256
+ };
1257
+ var sizeStyles3 = {
1258
+ sm: "px-2 py-0.5 text-xs",
1259
+ md: "px-2.5 py-1 text-sm",
1260
+ lg: "px-3 py-1.5 text-base"
1261
+ };
1262
+ var Badge = React113__namespace.default.forwardRef(
1263
+ ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
1264
+ const iconSizes2 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
1265
+ const resolvedIcon = typeof icon === "string" ? (() => {
1266
+ const I = resolveIcon(icon);
1267
+ return I ? /* @__PURE__ */ jsxRuntime.jsx(I, { className: iconSizes2[size] }) : null;
1268
+ })() : icon;
1269
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1270
+ "span",
1271
+ {
1272
+ ref,
1273
+ className: cn(
1274
+ "inline-flex items-center gap-1 font-bold rounded-[var(--radius-sm)]",
1275
+ variantStyles3[variant],
1276
+ sizeStyles3[size],
1277
+ className
1278
+ ),
1279
+ ...props,
1280
+ children: [
1281
+ resolvedIcon,
1282
+ children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
1283
+ ]
1284
+ }
1285
+ );
1286
+ }
1287
+ );
1288
+ Badge.displayName = "Badge";
1289
+ var Input = React113__namespace.default.forwardRef(
1290
+ ({
1291
+ className,
1292
+ inputType,
1293
+ type: htmlType,
1294
+ error,
1295
+ leftIcon,
1296
+ rightIcon,
1297
+ icon: IconComponent,
1298
+ clearable,
1299
+ onClear,
1300
+ value,
1301
+ options,
1302
+ rows = 3,
1303
+ onChange,
1304
+ ...props
1305
+ }, ref) => {
1306
+ const type = inputType || htmlType || "text";
1307
+ const resolvedLeftIcon = leftIcon || IconComponent && /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: "h-4 w-4" });
1308
+ const showClearButton = clearable && value && String(value).length > 0;
1309
+ const baseClassName = cn(
1310
+ "block w-full rounded-[var(--radius-sm)] transition-all duration-[var(--transition-fast)]",
1311
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]",
1312
+ "px-3 py-2 text-sm",
1313
+ "bg-[var(--color-card)] hover:bg-[var(--color-muted)] focus:bg-[var(--color-card)]",
1314
+ "text-[var(--color-foreground)] placeholder:text-[var(--color-muted-foreground)]",
1315
+ "focus:outline-none focus:ring-1 focus:ring-[var(--color-ring)] focus:border-[var(--color-ring)]",
1316
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-[var(--color-muted)]",
1317
+ error ? "border-[var(--color-error)] focus:border-[var(--color-error)] focus:ring-[var(--color-error)]" : "",
1318
+ resolvedLeftIcon && "pl-10",
1319
+ (rightIcon || showClearButton) && "pr-10",
1320
+ className
1321
+ );
1322
+ if (type === "select") {
1323
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1324
+ resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-[var(--color-muted-foreground)]", children: resolvedLeftIcon }),
1325
+ /* @__PURE__ */ jsxRuntime.jsxs(
1326
+ "select",
1327
+ {
1328
+ ref,
1329
+ value,
1330
+ onChange,
1331
+ className: cn(baseClassName, "appearance-none pr-10", className),
1332
+ ...props,
1333
+ children: [
1334
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select..." }),
1335
+ options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
1336
+ ]
1337
+ }
1338
+ ),
1339
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-[var(--color-muted-foreground)]", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronDown, { className: "h-4 w-4" }) })
1340
+ ] });
1341
+ }
1342
+ if (type === "textarea") {
1343
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative", children: /* @__PURE__ */ jsxRuntime.jsx(
1344
+ "textarea",
1345
+ {
1346
+ ref,
1347
+ value,
1348
+ onChange,
1349
+ rows,
1350
+ className: baseClassName,
1351
+ ...props
1352
+ }
1353
+ ) });
1354
+ }
1355
+ if (type === "checkbox") {
1356
+ return /* @__PURE__ */ jsxRuntime.jsx(
1357
+ "input",
1358
+ {
1359
+ ref,
1360
+ type: "checkbox",
1361
+ checked: props.checked,
1362
+ onChange,
1363
+ className: cn(
1364
+ "h-4 w-4 rounded-[var(--radius-sm)]",
1365
+ "border-[var(--color-border)]",
1366
+ "text-[var(--color-primary)] focus:ring-[var(--color-ring)]",
1367
+ "disabled:opacity-50 disabled:cursor-not-allowed",
1368
+ className
1369
+ ),
1370
+ ...props
1371
+ }
1372
+ );
1373
+ }
1374
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1375
+ resolvedLeftIcon && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none text-[var(--color-muted-foreground)]", children: resolvedLeftIcon }),
1376
+ /* @__PURE__ */ jsxRuntime.jsx(
1377
+ "input",
1378
+ {
1379
+ ref,
1380
+ type,
1381
+ value,
1382
+ onChange,
1383
+ className: baseClassName,
1384
+ ...props
1385
+ }
1386
+ ),
1387
+ showClearButton && /* @__PURE__ */ jsxRuntime.jsx(
1388
+ "button",
1389
+ {
1390
+ type: "button",
1391
+ onClick: onClear,
1392
+ className: "absolute inset-y-0 right-0 pr-3 flex items-center text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)]",
1393
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-4 w-4" })
1394
+ }
1395
+ ),
1396
+ rightIcon && !showClearButton && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-[var(--color-muted-foreground)]", children: rightIcon })
1397
+ ] });
1398
+ }
1399
+ );
1400
+ Input.displayName = "Input";
1401
+ var Label = React113__namespace.default.forwardRef(
1402
+ ({ className, required, children, ...props }, ref) => {
1403
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1404
+ "label",
1405
+ {
1406
+ ref,
1407
+ className: cn(
1408
+ "block text-sm font-bold text-[var(--color-foreground)]",
1409
+ className
1410
+ ),
1411
+ ...props,
1412
+ children: [
1413
+ children,
1414
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[var(--color-error)] ml-1", children: "*" })
1415
+ ]
1416
+ }
1417
+ );
1418
+ }
1419
+ );
1420
+ Label.displayName = "Label";
1421
+ var Textarea = React113__namespace.default.forwardRef(
1422
+ ({ className, error, ...props }, ref) => {
1423
+ return /* @__PURE__ */ jsxRuntime.jsx(
1424
+ "textarea",
1425
+ {
1426
+ ref,
1427
+ className: cn(
1428
+ "block w-full border-[length:var(--border-width)] shadow-[var(--shadow-sm)]",
1429
+ "px-3 py-2 text-sm text-[var(--color-foreground)]",
1430
+ "bg-[var(--color-card)]",
1431
+ "placeholder:text-[var(--color-placeholder)]",
1432
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-[var(--color-ring)]",
1433
+ "disabled:bg-[var(--color-muted)] disabled:text-[var(--color-muted-foreground)] disabled:cursor-not-allowed",
1434
+ "resize-y min-h-[80px]",
1435
+ error ? "border-[var(--color-error)] focus:border-[var(--color-error)]" : "border-[var(--color-border)] focus:border-[var(--color-primary)]",
1436
+ className
1437
+ ),
1438
+ ...props
1439
+ }
1440
+ );
1441
+ }
1442
+ );
1443
+ Textarea.displayName = "Textarea";
1444
+ var Select = React113__namespace.default.forwardRef(
1445
+ ({ className, options, placeholder, error, ...props }, ref) => {
1446
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1447
+ /* @__PURE__ */ jsxRuntime.jsxs(
1448
+ "select",
1449
+ {
1450
+ ref,
1451
+ className: cn(
1452
+ "block w-full border-[length:var(--border-width)] shadow-[var(--shadow-sm)] appearance-none",
1453
+ "px-3 py-2 pr-10 text-sm text-[var(--color-foreground)] font-medium",
1454
+ "bg-[var(--color-card)]",
1455
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-[var(--color-ring)]",
1456
+ "disabled:bg-[var(--color-muted)] disabled:text-[var(--color-muted-foreground)] disabled:cursor-not-allowed",
1457
+ error ? "border-[var(--color-error)] focus:border-[var(--color-error)]" : "border-[var(--color-border)] focus:border-[var(--color-primary)]",
1458
+ className
1459
+ ),
1460
+ ...props,
1461
+ children: [
1462
+ placeholder && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: placeholder }),
1463
+ options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(
1464
+ "option",
1465
+ {
1466
+ value: option.value,
1467
+ disabled: option.disabled,
1468
+ children: option.label
1469
+ },
1470
+ option.value
1471
+ ))
1472
+ ]
1473
+ }
1474
+ ),
1475
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.ChevronDown, { className: "h-4 w-4 text-[var(--color-foreground)]" }) })
1476
+ ] });
1477
+ }
1478
+ );
1479
+ Select.displayName = "Select";
1480
+ var Checkbox = React113__namespace.default.forwardRef(
1481
+ ({ className, label, id, ...props }, ref) => {
1482
+ const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
1483
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center", children: [
1484
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
1485
+ "input",
1486
+ {
1487
+ ref,
1488
+ type: "checkbox",
1489
+ id: inputId,
1490
+ className: cn(
1491
+ "peer h-4 w-4 border-[length:var(--border-width)] border-[var(--color-border)]",
1492
+ "accent-[var(--color-primary)] focus:ring-[var(--color-ring)] focus:ring-offset-0",
1493
+ "bg-[var(--color-card)] checked:bg-[var(--color-primary)]",
1494
+ "disabled:opacity-50 disabled:cursor-not-allowed",
1495
+ className
1496
+ ),
1497
+ ...props
1498
+ }
1499
+ ) }),
1500
+ label && /* @__PURE__ */ jsxRuntime.jsx(
1501
+ "label",
1502
+ {
1503
+ htmlFor: inputId,
1504
+ className: "ml-2 text-sm text-[var(--color-foreground)] font-medium cursor-pointer select-none",
1505
+ children: label
1506
+ }
1507
+ )
1508
+ ] });
1509
+ }
1510
+ );
1511
+ Checkbox.displayName = "Checkbox";
1512
+ var variantStyles4 = {
1513
+ default: [
1514
+ "bg-[var(--color-card)] border-none",
1515
+ "transition-all duration-[var(--transition-normal)]",
1516
+ "hover:shadow-[var(--shadow-hover)] hover:-translate-y-0.5"
1517
+ ].join(" "),
1518
+ bordered: [
1519
+ "bg-[var(--color-card)]",
1520
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1521
+ "shadow-none",
1522
+ "transition-all duration-[var(--transition-normal)]",
1523
+ "hover:shadow-[var(--shadow-hover)] hover:-translate-y-0.5"
1524
+ ].join(" "),
1525
+ elevated: [
1526
+ "bg-[var(--color-card)]",
1527
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1528
+ "shadow-[var(--shadow-main)]",
1529
+ "transition-all duration-[var(--transition-normal)]",
1530
+ "hover:shadow-[var(--shadow-hover)] hover:-translate-y-0.5"
1531
+ ].join(" "),
1532
+ // Interactive variant with theme-specific hover effects
1533
+ interactive: [
1534
+ "bg-[var(--color-card)]",
1535
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1536
+ "shadow-[var(--shadow-main)]",
1537
+ "cursor-pointer",
1538
+ "transition-all duration-[var(--transition-normal)]",
1539
+ "hover:shadow-[var(--shadow-hover)]"
1540
+ ].join(" ")
1541
+ };
1542
+ var paddingStyles2 = {
1543
+ none: "",
1544
+ sm: "p-3",
1545
+ md: "p-4",
1546
+ lg: "p-6"
1547
+ };
1548
+ var shadowStyles2 = {
1549
+ none: "shadow-none",
1550
+ sm: "shadow-[var(--shadow-sm)]",
1551
+ md: "shadow-[var(--shadow-main)]",
1552
+ lg: "shadow-[var(--shadow-lg)]"
1553
+ };
1554
+ var Card = React113__namespace.default.forwardRef(
1555
+ ({
1556
+ className,
1557
+ variant = "bordered",
1558
+ padding = "md",
1559
+ title,
1560
+ subtitle,
1561
+ shadow,
1562
+ children,
1563
+ ...props
1564
+ }, ref) => {
1565
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1566
+ "div",
1567
+ {
1568
+ ref,
1569
+ className: cn(
1570
+ "rounded-[var(--radius-md)]",
1571
+ "transition-all duration-[var(--transition-normal)]",
1572
+ variantStyles4[variant],
1573
+ paddingStyles2[padding],
1574
+ shadow && shadowStyles2[shadow],
1575
+ className
1576
+ ),
1577
+ ...props,
1578
+ children: [
1579
+ (title || subtitle) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
1580
+ title && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg text-[var(--color-card-foreground)] font-[var(--font-weight-bold)]", children: title }),
1581
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-[var(--color-muted-foreground)] mt-1", children: subtitle })
1582
+ ] }),
1583
+ children
1584
+ ]
1585
+ }
1586
+ );
1587
+ }
1588
+ );
1589
+ Card.displayName = "Card";
1590
+ var CardHeader = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("mb-4", className), ...props }));
1591
+ CardHeader.displayName = "CardHeader";
1592
+ var CardTitle = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1593
+ "h3",
1594
+ {
1595
+ ref,
1596
+ className: cn(
1597
+ "text-lg text-[var(--color-card-foreground)]",
1598
+ "font-[var(--font-weight-bold)]",
1599
+ className
1600
+ ),
1601
+ ...props
1602
+ }
1603
+ ));
1604
+ CardTitle.displayName = "CardTitle";
1605
+ var CardContent = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx("div", { ref, className: cn("", className), ...props }));
1606
+ CardContent.displayName = "CardContent";
1607
+ var CardBody = CardContent;
1608
+ CardBody.displayName = "CardBody";
1609
+ var CardFooter = React113__namespace.default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
1610
+ "div",
1611
+ {
1612
+ ref,
1613
+ className: cn("mt-4 flex items-center", className),
1614
+ ...props
1615
+ }
1616
+ ));
1617
+ CardFooter.displayName = "CardFooter";
1618
+ var sizeStyles4 = {
1619
+ xs: "h-3 w-3",
1620
+ sm: "h-4 w-4",
1621
+ md: "h-6 w-6",
1622
+ lg: "h-8 w-8"
1623
+ };
1624
+ var Spinner = React113__namespace.default.forwardRef(
1625
+ ({ className, size = "md", ...props }, ref) => {
1626
+ return /* @__PURE__ */ jsxRuntime.jsx(
1627
+ "div",
1628
+ {
1629
+ ref,
1630
+ className: cn("text-[var(--color-foreground)]", className),
1631
+ ...props,
1632
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Loader2, { className: cn("animate-spin", sizeStyles4[size]) })
1633
+ }
1634
+ );
1635
+ }
1636
+ );
1637
+ Spinner.displayName = "Spinner";
1638
+ var Radio = React113__namespace.default.forwardRef(
1639
+ ({
1640
+ label,
1641
+ helperText,
1642
+ error,
1643
+ size = "md",
1644
+ className,
1645
+ id,
1646
+ checked,
1647
+ disabled,
1648
+ ...props
1649
+ }, ref) => {
1650
+ const radioId = id || `radio-${Math.random().toString(36).substr(2, 9)}`;
1651
+ const hasError = !!error;
1652
+ const sizeClasses6 = {
1653
+ sm: "w-4 h-4",
1654
+ md: "w-5 h-5",
1655
+ lg: "w-6 h-6"
1656
+ };
1657
+ const dotSizeClasses = {
1658
+ sm: "w-2 h-2",
1659
+ md: "w-2.5 h-2.5",
1660
+ lg: "w-3 h-3"
1661
+ };
1662
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1663
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
1664
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-shrink-0 mt-0.5", children: [
1665
+ /* @__PURE__ */ jsxRuntime.jsx(
1666
+ "input",
1667
+ {
1668
+ ref,
1669
+ type: "radio",
1670
+ id: radioId,
1671
+ checked,
1672
+ disabled,
1673
+ className: cn("sr-only peer", className),
1674
+ "aria-invalid": hasError,
1675
+ "aria-describedby": error ? `${radioId}-error` : helperText ? `${radioId}-helper` : void 0,
1676
+ ...props
1677
+ }
1678
+ ),
1679
+ /* @__PURE__ */ jsxRuntime.jsx(
1680
+ "label",
1681
+ {
1682
+ htmlFor: radioId,
1683
+ className: cn(
1684
+ "flex items-center justify-center",
1685
+ "border-[length:var(--border-width)] transition-all cursor-pointer",
1686
+ sizeClasses6[size],
1687
+ hasError ? "border-[var(--color-error)] peer-focus:ring-[var(--color-error)]/20" : "border-[var(--color-border)] peer-focus:ring-[var(--color-ring)]/20",
1688
+ checked ? hasError ? "border-[var(--color-error)]" : "border-[var(--color-primary)] bg-[var(--color-primary)]" : "",
1689
+ "peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-offset-2",
1690
+ disabled && "opacity-50 cursor-not-allowed",
1691
+ !disabled && "hover:border-[var(--color-border-hover)]"
1692
+ ),
1693
+ children: checked && /* @__PURE__ */ jsxRuntime.jsx(
1694
+ "div",
1695
+ {
1696
+ className: cn(
1697
+ "transition-all",
1698
+ dotSizeClasses[size],
1699
+ hasError ? "bg-[var(--color-error)]" : "bg-[var(--color-primary-foreground)]"
1700
+ )
1701
+ }
1702
+ )
1703
+ }
1704
+ )
1705
+ ] }),
1706
+ label && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsxRuntime.jsx(
1707
+ "label",
1708
+ {
1709
+ htmlFor: radioId,
1710
+ className: cn(
1711
+ "block text-sm font-medium cursor-pointer select-none",
1712
+ hasError ? "text-[var(--color-error)]" : "text-[var(--color-foreground)]",
1713
+ disabled && "opacity-50 cursor-not-allowed"
1714
+ ),
1715
+ children: label
1716
+ }
1717
+ ) })
1718
+ ] }),
1719
+ (helperText || error) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 ml-8", children: [
1720
+ error && /* @__PURE__ */ jsxRuntime.jsx(
1721
+ "p",
1722
+ {
1723
+ id: `${radioId}-error`,
1724
+ className: "text-sm text-[var(--color-error)] font-medium",
1725
+ role: "alert",
1726
+ children: error
1727
+ }
1728
+ ),
1729
+ !error && helperText && /* @__PURE__ */ jsxRuntime.jsx(
1730
+ "p",
1731
+ {
1732
+ id: `${radioId}-helper`,
1733
+ className: "text-sm text-[var(--color-muted-foreground)]",
1734
+ children: helperText
1735
+ }
1736
+ )
1737
+ ] })
1738
+ ] });
1739
+ }
1740
+ );
1741
+ Radio.displayName = "Radio";
1742
+ var Switch = React113__namespace.forwardRef(
1743
+ ({
1744
+ checked,
1745
+ defaultChecked = false,
1746
+ onChange,
1747
+ disabled = false,
1748
+ label,
1749
+ id,
1750
+ name,
1751
+ className
1752
+ }, ref) => {
1753
+ const [isChecked, setIsChecked] = React113__namespace.useState(
1754
+ checked !== void 0 ? checked : defaultChecked
1755
+ );
1756
+ React113__namespace.useEffect(() => {
1757
+ if (checked !== void 0) {
1758
+ setIsChecked(checked);
1759
+ }
1760
+ }, [checked]);
1761
+ const handleClick = () => {
1762
+ if (disabled) return;
1763
+ const newValue = !isChecked;
1764
+ if (checked === void 0) {
1765
+ setIsChecked(newValue);
1766
+ }
1767
+ onChange?.(newValue);
1768
+ };
1769
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("inline-flex items-center gap-2", className), children: [
1770
+ /* @__PURE__ */ jsxRuntime.jsx(
1771
+ "button",
1772
+ {
1773
+ ref,
1774
+ type: "button",
1775
+ role: "switch",
1776
+ "aria-checked": isChecked,
1777
+ "aria-label": label,
1778
+ id,
1779
+ name,
1780
+ disabled,
1781
+ onClick: handleClick,
1782
+ className: cn(
1783
+ "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
1784
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1785
+ isChecked ? "bg-primary" : "bg-muted",
1786
+ disabled && "cursor-not-allowed opacity-50"
1787
+ ),
1788
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1789
+ "span",
1790
+ {
1791
+ className: cn(
1792
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
1793
+ isChecked ? "translate-x-5" : "translate-x-0"
1794
+ )
1795
+ }
1796
+ )
1797
+ }
1798
+ ),
1799
+ label && /* @__PURE__ */ jsxRuntime.jsx(
1800
+ "label",
1801
+ {
1802
+ htmlFor: id,
1803
+ className: cn(
1804
+ "text-sm font-medium leading-none cursor-pointer",
1805
+ disabled && "cursor-not-allowed opacity-70"
1806
+ ),
1807
+ onClick: handleClick,
1808
+ children: label
1809
+ }
1810
+ )
1811
+ ] });
1812
+ }
1813
+ );
1814
+ Switch.displayName = "Switch";
1815
+ var gapStyles = {
1816
+ none: "gap-0",
1817
+ xs: "gap-1",
1818
+ sm: "gap-2",
1819
+ md: "gap-4",
1820
+ lg: "gap-6",
1821
+ xl: "gap-8",
1822
+ "2xl": "gap-12"
1823
+ };
1824
+ var alignStyles = {
1825
+ start: "items-start",
1826
+ center: "items-center",
1827
+ end: "items-end",
1828
+ stretch: "items-stretch",
1829
+ baseline: "items-baseline"
1830
+ };
1831
+ var justifyStyles = {
1832
+ start: "justify-start",
1833
+ center: "justify-center",
1834
+ end: "justify-end",
1835
+ between: "justify-between",
1836
+ around: "justify-around",
1837
+ evenly: "justify-evenly"
1838
+ };
1839
+ var Stack = ({
1840
+ direction = "vertical",
1841
+ gap = "md",
1842
+ align = "stretch",
1843
+ justify = "start",
1844
+ wrap = false,
1845
+ reverse = false,
1846
+ flex = false,
1847
+ className,
1848
+ style,
1849
+ children,
1850
+ as: Component2 = "div",
1851
+ onClick,
1852
+ onKeyDown,
1853
+ role,
1854
+ tabIndex,
1855
+ action,
1856
+ actionPayload,
1857
+ responsive = false
1858
+ }) => {
1859
+ const eventBus = useEventBus();
1860
+ const handleClick = (e) => {
1861
+ if (action) {
1862
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
1863
+ }
1864
+ onClick?.(e);
1865
+ };
1866
+ const isHorizontal = direction === "horizontal";
1867
+ const directionClass = responsive && isHorizontal ? reverse ? "flex-col-reverse md:flex-row-reverse" : "flex-col md:flex-row" : isHorizontal ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
1868
+ const Comp = Component2;
1869
+ return /* @__PURE__ */ jsxRuntime.jsx(
1870
+ Comp,
1871
+ {
1872
+ className: cn(
1873
+ "flex",
1874
+ directionClass,
1875
+ gapStyles[gap],
1876
+ alignStyles[align],
1877
+ justifyStyles[justify],
1878
+ wrap && "flex-wrap",
1879
+ flex && "flex-1",
1880
+ className
1881
+ ),
1882
+ style,
1883
+ onClick: action || onClick ? handleClick : void 0,
1884
+ onKeyDown,
1885
+ role,
1886
+ tabIndex,
1887
+ children
1888
+ }
1889
+ );
1890
+ };
1891
+ var VStack = (props) => /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "vertical", ...props });
1892
+ var HStack = (props) => /* @__PURE__ */ jsxRuntime.jsx(Stack, { direction: "horizontal", ...props });
1893
+ var statusColors = {
1894
+ online: "bg-[var(--color-success)]",
1895
+ offline: "bg-[var(--color-muted-foreground)]",
1896
+ away: "bg-[var(--color-warning)]",
1897
+ busy: "bg-[var(--color-error)]",
1898
+ warning: "bg-[var(--color-warning)]",
1899
+ critical: "bg-[var(--color-error)]"
1900
+ };
1901
+ var pulseRingColors = {
1902
+ online: "ring-[var(--color-success)]",
1903
+ offline: "ring-[var(--color-muted-foreground)]",
1904
+ away: "ring-[var(--color-warning)]",
1905
+ busy: "ring-[var(--color-error)]",
1906
+ warning: "ring-[var(--color-warning)]",
1907
+ critical: "ring-[var(--color-error)]"
1908
+ };
1909
+ var sizeStyles5 = {
1910
+ sm: "w-2 h-2",
1911
+ md: "w-2.5 h-2.5",
1912
+ lg: "w-3 h-3"
1913
+ };
1914
+ var StatusDot = React113__namespace.default.forwardRef(
1915
+ ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
1916
+ return /* @__PURE__ */ jsxRuntime.jsx(
1917
+ "span",
1918
+ {
1919
+ ref,
1920
+ className: cn(
1921
+ "inline-block rounded-full flex-shrink-0",
1922
+ statusColors[status],
1923
+ sizeStyles5[size],
1924
+ pulse && [
1925
+ "animate-pulse",
1926
+ "ring-2 ring-offset-1",
1927
+ pulseRingColors[status],
1928
+ "ring-opacity-40"
1929
+ ],
1930
+ className
1931
+ ),
1932
+ role: "status",
1933
+ "aria-label": label ?? status,
1934
+ ...props
1935
+ }
1936
+ );
1937
+ }
1938
+ );
1939
+ StatusDot.displayName = "StatusDot";
1940
+ var sizeStyles6 = {
1941
+ sm: { icon: "w-3 h-3", text: "text-xs" },
1942
+ md: { icon: "w-4 h-4", text: "text-sm" },
1943
+ lg: { icon: "w-5 h-5", text: "text-base" }
1944
+ };
1945
+ function resolveDirection(value, direction) {
1946
+ if (direction) return direction;
1947
+ if (value === void 0 || value === 0) return "flat";
1948
+ return value > 0 ? "up" : "down";
1949
+ }
1950
+ function resolveColor(dir, invert) {
1951
+ if (dir === "flat") return "text-[var(--color-muted-foreground)]";
1952
+ const isPositive = dir === "up";
1953
+ const isGood = invert ? !isPositive : isPositive;
1954
+ return isGood ? "text-[var(--color-success)]" : "text-[var(--color-error)]";
1955
+ }
1956
+ var iconMap2 = {
1957
+ up: LucideIcons.TrendingUp,
1958
+ down: LucideIcons.TrendingDown,
1959
+ flat: LucideIcons.ArrowRight
1960
+ };
1961
+ var TrendIndicator = React113__namespace.default.forwardRef(
1962
+ ({
1963
+ className,
1964
+ value,
1965
+ direction,
1966
+ showValue = true,
1967
+ invert = false,
1968
+ label,
1969
+ size = "md",
1970
+ ...props
1971
+ }, ref) => {
1972
+ const dir = resolveDirection(value, direction);
1973
+ const colorClass = resolveColor(dir, invert);
1974
+ const IconComponent = iconMap2[dir];
1975
+ const styles = sizeStyles6[size];
1976
+ const formattedValue = value !== void 0 ? `${value > 0 ? "+" : ""}${value}%` : void 0;
1977
+ const ariaLabel = label ?? (formattedValue ? `${dir} ${formattedValue}` : dir);
1978
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1979
+ "span",
1980
+ {
1981
+ ref,
1982
+ className: cn(
1983
+ "inline-flex items-center gap-1 font-medium",
1984
+ colorClass,
1985
+ styles.text,
1986
+ className
1987
+ ),
1988
+ role: "status",
1989
+ "aria-label": ariaLabel,
1990
+ ...props,
1991
+ children: [
1992
+ /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: styles.icon }),
1993
+ showValue && formattedValue && /* @__PURE__ */ jsxRuntime.jsx("span", { children: formattedValue })
1994
+ ]
1995
+ }
1996
+ );
1997
+ }
1998
+ );
1999
+ TrendIndicator.displayName = "TrendIndicator";
2000
+ function useSafeEventBus() {
2001
+ try {
2002
+ return useEventBus();
2003
+ } catch {
2004
+ return { emit: () => {
2005
+ }, on: () => () => {
2006
+ }, once: () => {
2007
+ } };
2008
+ }
2009
+ }
2010
+ var trackSizes = {
2011
+ sm: "h-1",
2012
+ md: "h-1.5",
2013
+ lg: "h-2"
2014
+ };
2015
+ var thumbSizes = {
2016
+ sm: "w-3 h-3",
2017
+ md: "w-4 h-4",
2018
+ lg: "w-5 h-5"
2019
+ };
2020
+ var RangeSlider = React113__namespace.default.forwardRef(
2021
+ ({
2022
+ className,
2023
+ min = 0,
2024
+ max = 100,
2025
+ value = 0,
2026
+ step = 1,
2027
+ showTooltip = false,
2028
+ showTicks = false,
2029
+ buffered,
2030
+ size = "md",
2031
+ disabled = false,
2032
+ action,
2033
+ actionPayload,
2034
+ onChange,
2035
+ formatValue: formatValue5,
2036
+ ...props
2037
+ }, ref) => {
2038
+ const [isDragging, setIsDragging] = React113.useState(false);
2039
+ const [showTip, setShowTip] = React113.useState(false);
2040
+ const inputRef = React113.useRef(null);
2041
+ const eventBus = useSafeEventBus();
2042
+ const percentage = max !== min ? (value - min) / (max - min) * 100 : 0;
2043
+ const bufferedPercentage = buffered !== void 0 ? Math.min(buffered, 100) : void 0;
2044
+ const displayValue = formatValue5 ? formatValue5(value) : String(value);
2045
+ const handleChange = React113.useCallback(
2046
+ (e) => {
2047
+ const newValue = Number(e.target.value);
2048
+ onChange?.(newValue);
2049
+ if (action) {
2050
+ eventBus.emit(`UI:${action}`, { ...actionPayload, value: newValue });
2051
+ }
2052
+ },
2053
+ [onChange, action, actionPayload, eventBus]
2054
+ );
2055
+ const tickCount = showTicks ? Math.min(Math.floor((max - min) / step), 20) : 0;
2056
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2057
+ "div",
2058
+ {
2059
+ ref,
2060
+ className: cn(
2061
+ "relative w-full",
2062
+ disabled && "opacity-50 cursor-not-allowed",
2063
+ className
2064
+ ),
2065
+ ...props,
2066
+ children: [
2067
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full py-2", children: [
2068
+ /* @__PURE__ */ jsxRuntime.jsx(
2069
+ "div",
2070
+ {
2071
+ className: cn(
2072
+ "absolute inset-x-0 rounded-full bg-[var(--color-muted)]",
2073
+ trackSizes[size]
2074
+ ),
2075
+ style: { top: "50%", transform: "translateY(-50%)" }
2076
+ }
2077
+ ),
2078
+ bufferedPercentage !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
2079
+ "div",
2080
+ {
2081
+ className: cn(
2082
+ "absolute rounded-full bg-[var(--color-muted-foreground)] opacity-30",
2083
+ trackSizes[size]
2084
+ ),
2085
+ style: {
2086
+ top: "50%",
2087
+ transform: "translateY(-50%)",
2088
+ left: 0,
2089
+ width: `${bufferedPercentage}%`
2090
+ }
2091
+ }
2092
+ ),
2093
+ /* @__PURE__ */ jsxRuntime.jsx(
2094
+ "div",
2095
+ {
2096
+ className: cn(
2097
+ "absolute rounded-full bg-[var(--color-primary)]",
2098
+ trackSizes[size]
2099
+ ),
2100
+ style: {
2101
+ top: "50%",
2102
+ transform: "translateY(-50%)",
2103
+ left: 0,
2104
+ width: `${percentage}%`
2105
+ }
2106
+ }
2107
+ ),
2108
+ /* @__PURE__ */ jsxRuntime.jsx(
2109
+ "input",
2110
+ {
2111
+ ref: inputRef,
2112
+ type: "range",
2113
+ min,
2114
+ max,
2115
+ step,
2116
+ value,
2117
+ disabled,
2118
+ onChange: handleChange,
2119
+ onMouseDown: () => {
2120
+ setIsDragging(true);
2121
+ setShowTip(true);
2122
+ },
2123
+ onMouseUp: () => {
2124
+ setIsDragging(false);
2125
+ setShowTip(false);
2126
+ },
2127
+ onTouchStart: () => {
2128
+ setIsDragging(true);
2129
+ setShowTip(true);
2130
+ },
2131
+ onTouchEnd: () => {
2132
+ setIsDragging(false);
2133
+ setShowTip(false);
2134
+ },
2135
+ onFocus: () => setShowTip(true),
2136
+ onBlur: () => {
2137
+ if (!isDragging) setShowTip(false);
2138
+ },
2139
+ className: cn(
2140
+ "absolute inset-0 w-full opacity-0 cursor-pointer",
2141
+ disabled && "cursor-not-allowed",
2142
+ // Thumb sizing via pseudo-element
2143
+ "[&::-webkit-slider-thumb]:appearance-none",
2144
+ "[&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5",
2145
+ "[&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5"
2146
+ ),
2147
+ style: { height: "100%", margin: 0 },
2148
+ "aria-label": props["aria-label"] ?? "Range slider",
2149
+ "aria-valuemin": min,
2150
+ "aria-valuemax": max,
2151
+ "aria-valuenow": value,
2152
+ "aria-valuetext": displayValue
2153
+ }
2154
+ ),
2155
+ /* @__PURE__ */ jsxRuntime.jsx(
2156
+ "div",
2157
+ {
2158
+ className: cn(
2159
+ "absolute rounded-full bg-[var(--color-primary-foreground)]",
2160
+ "border-2 border-[var(--color-primary)]",
2161
+ "shadow-[var(--shadow-sm)]",
2162
+ "pointer-events-none",
2163
+ "transition-transform duration-100",
2164
+ isDragging && "scale-110",
2165
+ thumbSizes[size]
2166
+ ),
2167
+ style: {
2168
+ top: "50%",
2169
+ transform: `translateY(-50%) translateX(-50%)${isDragging ? " scale(1.1)" : ""}`,
2170
+ left: `${percentage}%`
2171
+ }
2172
+ }
2173
+ ),
2174
+ showTooltip && showTip && /* @__PURE__ */ jsxRuntime.jsx(
2175
+ "div",
2176
+ {
2177
+ className: cn(
2178
+ "absolute -top-8 px-2 py-0.5 rounded",
2179
+ "bg-[var(--color-foreground)] text-[var(--color-background)]",
2180
+ "text-xs font-medium whitespace-nowrap",
2181
+ "pointer-events-none"
2182
+ ),
2183
+ style: {
2184
+ left: `${percentage}%`,
2185
+ transform: "translateX(-50%)"
2186
+ },
2187
+ children: displayValue
2188
+ }
2189
+ )
2190
+ ] }),
2191
+ showTicks && tickCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative w-full h-2 mt-1", children: Array.from({ length: tickCount + 1 }, (_, i) => {
2192
+ const tickPercent = i / tickCount * 100;
2193
+ return /* @__PURE__ */ jsxRuntime.jsx(
2194
+ "div",
2195
+ {
2196
+ className: "absolute w-px h-1.5 bg-[var(--color-muted-foreground)]",
2197
+ style: { left: `${tickPercent}%` }
2198
+ },
2199
+ i
2200
+ );
2201
+ }) })
2202
+ ]
2203
+ }
2204
+ );
2205
+ }
2206
+ );
2207
+ RangeSlider.displayName = "RangeSlider";
2208
+ var backgroundClasses = {
2209
+ default: "",
2210
+ alt: "bg-[var(--color-surface)]",
2211
+ dark: "bg-[var(--color-foreground)] text-[var(--color-background)]",
2212
+ gradient: [
2213
+ "bg-gradient-to-b",
2214
+ "from-[var(--color-primary)]/5",
2215
+ "to-[var(--color-secondary)]/5"
2216
+ ].join(" ")
2217
+ };
2218
+ var paddingClasses = {
2219
+ sm: "py-12",
2220
+ md: "py-16",
2221
+ lg: "py-24"
2222
+ };
2223
+ var ContentSection = React113__namespace.default.forwardRef(
2224
+ ({ children, background = "default", padding = "lg", id, className }, ref) => {
2225
+ return /* @__PURE__ */ jsxRuntime.jsx(
2226
+ Box,
2227
+ {
2228
+ ref,
2229
+ as: "section",
2230
+ id,
2231
+ className: cn(
2232
+ backgroundClasses[background],
2233
+ paddingClasses[padding],
2234
+ className
2235
+ ),
2236
+ children: /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children })
2237
+ }
2238
+ );
2239
+ }
2240
+ );
2241
+ ContentSection.displayName = "ContentSection";
2242
+
2243
+ // locales/en.json
2244
+ var en_default = {
2245
+ $meta: { locale: "en", direction: "ltr" },
2246
+ "common.save": "Save",
2247
+ "common.cancel": "Cancel",
2248
+ "common.delete": "Delete",
2249
+ "common.close": "Close",
2250
+ "common.confirm": "Are you sure?",
2251
+ "common.create": "Create",
2252
+ "common.edit": "Edit",
2253
+ "common.view": "View",
2254
+ "common.add": "Add",
2255
+ "common.remove": "Remove",
2256
+ "common.search": "Search...",
2257
+ "common.filter": "Filter",
2258
+ "common.actions": "Actions",
2259
+ "common.yes": "Yes",
2260
+ "common.no": "No",
2261
+ "common.selected": "selected",
2262
+ "common.ok": "OK",
2263
+ "common.done": "Done",
2264
+ "common.apply": "Apply",
2265
+ "common.reset": "Reset",
2266
+ "common.refresh": "Refresh",
2267
+ "common.export": "Export",
2268
+ "common.import": "Import",
2269
+ "common.copy": "Copy",
2270
+ "common.settings": "Settings",
2271
+ "nav.previous": "Previous",
2272
+ "nav.next": "Next",
2273
+ "nav.back": "Back",
2274
+ "nav.home": "Home",
2275
+ "form.submit": "Submit",
2276
+ "form.saving": "Saving...",
2277
+ "form.required": "This field is required",
2278
+ "form.invalidEmail": "Enter a valid email address",
2279
+ "form.selectPlaceholder": "Select {{label}}...",
2280
+ "form.searchPlaceholder": "Search {{entity}}...",
2281
+ "table.empty.title": "No items found",
2282
+ "table.empty.description": "No items to display.",
2283
+ "table.search.placeholder": "Search...",
2284
+ "table.pagination.showing": "Showing {{start}} to {{end}} of {{total}} results",
2285
+ "table.pagination.page": "Page {{page}} of {{totalPages}}",
2286
+ "table.bulk.selected": "{{count}} selected",
2287
+ "table.loading": "Loading...",
2288
+ "status.loading": "Loading...",
2289
+ "status.scheduled": "Scheduled",
2290
+ "status.inProgress": "In Progress",
2291
+ "status.completed": "Completed",
2292
+ "status.cancelled": "Cancelled",
2293
+ "status.pending": "Pending",
2294
+ "status.active": "Active",
2295
+ "status.inactive": "Inactive",
2296
+ "status.draft": "Draft",
2297
+ "status.archived": "Archived",
2298
+ "error.generic": "Something went wrong",
2299
+ "error.retry": "Try again",
2300
+ "error.notFound": "Not found",
2301
+ "error.loadFailed": "Failed to load: {{message}}",
2302
+ "error.configMissing": "Configuration not found for: {{id}}",
2303
+ "common.loading": "Loading...",
2304
+ "common.showMore": "Show More",
2305
+ "common.showLess": "Show Less",
2306
+ "common.noResults": "No results found",
2307
+ "common.saveChanges": "Save Changes",
2308
+ "common.retry": "Retry",
2309
+ "common.open": "Open",
2310
+ "common.back": "Back",
2311
+ "empty.noItems": "No items",
2312
+ "empty.noData": "No data available",
2313
+ "empty.noItemsYet": "No items yet",
2314
+ "empty.noItemsAdded": "No items added yet",
2315
+ "empty.noOptionsFound": "No options found",
2316
+ "list.addItemPlaceholder": "Add new item...",
2317
+ "error.occurred": "An error occurred",
2318
+ "error.failedToLoad": "Failed to load data",
2319
+ "wizard.back": "Back",
2320
+ "wizard.next": "Next",
2321
+ "wizard.complete": "Complete",
2322
+ "wizard.stepOf": "Step {{current}} of {{total}}",
2323
+ "pagination.previous": "Previous",
2324
+ "pagination.next": "Next",
2325
+ "pagination.total": "Total:",
2326
+ "pagination.show": "Show:",
2327
+ "pagination.goTo": "Go to:",
2328
+ "pagination.go": "Go",
2329
+ "auth.signIn": "Sign in",
2330
+ "auth.signOut": "Sign out",
2331
+ "dialog.confirm": "Confirm",
2332
+ "dialog.cancel": "Cancel",
2333
+ "dialog.loading": "Loading...",
2334
+ "dialog.delete.title": "Delete {{item}}?",
2335
+ "dialog.delete.message": "This action cannot be undone.",
2336
+ "trait.availableActions": "Available Actions",
2337
+ "trait.transitions": "Transitions",
2338
+ "trait.availableNow": "Available now",
2339
+ "book.startReading": "Start Reading",
2340
+ "book.tableOfContents": "Table of Contents",
2341
+ "book.partNumber": "Part {{number}}",
2342
+ "book.print": "Print",
2343
+ "book.previousPage": "Previous page",
2344
+ "book.nextPage": "Next page",
2345
+ "quiz.showAnswer": "Show answer",
2346
+ "quiz.hideAnswer": "Hide answer"
2347
+ };
2348
+
2349
+ // hooks/useTranslate.ts
2350
+ var { $meta: _meta, ...coreMessages } = en_default;
2351
+ var coreLocale = coreMessages;
2352
+ var I18nContext = React113.createContext({
2353
+ locale: "en",
2354
+ direction: "ltr",
2355
+ t: (key) => coreLocale[key] ?? key
2356
+ // core locale fallback
2357
+ });
2358
+ I18nContext.displayName = "I18nContext";
2359
+ I18nContext.Provider;
2360
+ function useTranslate() {
2361
+ return React113.useContext(I18nContext);
2362
+ }
2363
+ var ErrorState = ({
2364
+ title,
2365
+ message,
2366
+ description,
2367
+ onRetry,
2368
+ className,
2369
+ retryEvent
2370
+ }) => {
2371
+ const eventBus = useEventBus();
2372
+ const { t } = useTranslate();
2373
+ const handleRetry = () => {
2374
+ if (retryEvent) eventBus.emit(`UI:${retryEvent}`, {});
2375
+ onRetry?.();
2376
+ };
2377
+ const resolvedTitle = title ?? t("error.generic");
2378
+ const resolvedMessage = message ?? description ?? t("error.occurred");
2379
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2380
+ VStack,
2381
+ {
2382
+ align: "center",
2383
+ className: cn(
2384
+ "justify-center py-12 text-center",
2385
+ className
2386
+ ),
2387
+ children: [
2388
+ /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mb-4 rounded-[var(--radius-full)] bg-[var(--color-error)]/10 p-3", children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.AlertCircle, { className: "h-8 w-8 text-[var(--color-error)]" }) }),
2389
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h3", className: "text-lg font-medium text-[var(--color-foreground)]", children: resolvedTitle }),
2390
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "mt-1 text-[var(--color-muted-foreground)] max-w-sm", children: resolvedMessage }),
2391
+ (onRetry || retryEvent) && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary", className: "mt-4", onClick: handleRetry, children: t("error.retry") })
2392
+ ]
2393
+ }
2394
+ );
2395
+ };
2396
+ ErrorState.displayName = "ErrorState";
2397
+ var ErrorBoundary = class extends React113__namespace.default.Component {
2398
+ constructor(props) {
2399
+ super(props);
2400
+ __publicField(this, "reset", () => {
2401
+ this.setState({ error: null });
2402
+ });
2403
+ this.state = { error: null };
2404
+ }
2405
+ static getDerivedStateFromError(error) {
2406
+ return { error };
2407
+ }
2408
+ componentDidCatch(error, errorInfo) {
2409
+ this.props.onError?.(error, errorInfo);
2410
+ }
2411
+ render() {
2412
+ const { error } = this.state;
2413
+ const { children, fallback, className } = this.props;
2414
+ if (error) {
2415
+ const wrapper = className ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn(className), children: this.renderFallback(error, fallback) }) : this.renderFallback(error, fallback);
2416
+ return wrapper;
2417
+ }
2418
+ return children;
2419
+ }
2420
+ renderFallback(error, fallback) {
2421
+ if (typeof fallback === "function") {
2422
+ return fallback(error, this.reset);
2423
+ }
2424
+ if (fallback) {
2425
+ return fallback;
2426
+ }
2427
+ return /* @__PURE__ */ jsxRuntime.jsx(
2428
+ ErrorState,
2429
+ {
2430
+ title: "Something went wrong",
2431
+ message: error.message,
2432
+ onRetry: this.reset
2433
+ }
2434
+ );
2435
+ }
2436
+ };
2437
+ __publicField(ErrorBoundary, "displayName", "ErrorBoundary");
2438
+
2439
+ // renderer/client-effect-executor.ts
2440
+ function executeClientEffects(effects, config) {
2441
+ if (!effects || effects.length === 0) {
2442
+ return;
2443
+ }
2444
+ for (const effect of effects) {
2445
+ try {
2446
+ executeEffect(effect, config);
2447
+ } catch (error) {
2448
+ console.error(
2449
+ `[ClientEffectExecutor] Error executing effect:`,
2450
+ effect,
2451
+ error
2452
+ );
2453
+ }
2454
+ }
2455
+ config.onComplete?.();
2456
+ }
2457
+ function executeEffect(effect, config) {
2458
+ const [effectType, ...args] = effect;
2459
+ switch (effectType) {
2460
+ case "render-ui": {
2461
+ const [slot, patternConfig] = args;
2462
+ executeRenderUI(slot, patternConfig, config);
2463
+ break;
2464
+ }
2465
+ case "navigate": {
2466
+ const [path, params] = args;
2467
+ executeNavigate(path, params, config);
2468
+ break;
2469
+ }
2470
+ case "notify": {
2471
+ const [message, options] = args;
2472
+ executeNotify(message, options, config);
2473
+ break;
2474
+ }
2475
+ case "emit": {
2476
+ const [event, payload] = args;
2477
+ executeEmit(event, payload, config);
2478
+ break;
2479
+ }
2480
+ default:
2481
+ console.warn(`[ClientEffectExecutor] Unknown effect type: ${effectType}`);
2482
+ }
2483
+ }
2484
+ function executeRenderUI(slot, patternConfig, config) {
2485
+ config.renderToSlot(slot, patternConfig);
2486
+ }
2487
+ function executeNavigate(path, params, config) {
2488
+ config.navigate(path, params);
2489
+ }
2490
+ function executeNotify(message, options, config) {
2491
+ config.notify(message, options);
2492
+ }
2493
+ function executeEmit(event, payload, config) {
2494
+ config.eventBus.emit(event, payload);
2495
+ }
2496
+ var ClientEffectConfigContext = React113.createContext(null);
2497
+ ClientEffectConfigContext.Provider;
2498
+ var effectIdCounter = 0;
2499
+ function generateEffectId() {
2500
+ return `offline-effect-${++effectIdCounter}-${Date.now()}`;
2501
+ }
2502
+ var OfflineExecutor = class {
2503
+ constructor(config) {
2504
+ __publicField(this, "config");
2505
+ __publicField(this, "state");
2506
+ __publicField(this, "storage");
2507
+ /**
2508
+ * Handle going online
2509
+ */
2510
+ __publicField(this, "handleOnline", () => {
2511
+ this.state.isOffline = false;
2512
+ });
2513
+ /**
2514
+ * Handle going offline
2515
+ */
2516
+ __publicField(this, "handleOffline", () => {
2517
+ this.state.isOffline = true;
2518
+ });
2519
+ this.config = {
2520
+ enableSyncQueue: true,
2521
+ maxQueueSize: 100,
2522
+ ...config
2523
+ };
2524
+ this.state = {
2525
+ isOffline: !this.checkOnline(),
2526
+ syncQueue: [],
2527
+ localEffectsProcessed: 0,
2528
+ effectsSynced: 0
2529
+ };
2530
+ this.storage = typeof localStorage !== "undefined" ? localStorage : null;
2531
+ this.loadSyncQueue();
2532
+ if (typeof window !== "undefined") {
2533
+ window.addEventListener("online", this.handleOnline);
2534
+ window.addEventListener("offline", this.handleOffline);
2535
+ }
2536
+ }
2537
+ /**
2538
+ * Check if we're online (browser API)
2539
+ */
2540
+ checkOnline() {
2541
+ return typeof navigator !== "undefined" ? navigator.onLine : true;
2542
+ }
2543
+ /**
2544
+ * Load sync queue from localStorage
2545
+ */
2546
+ loadSyncQueue() {
2547
+ if (!this.storage) return;
2548
+ try {
2549
+ const stored = this.storage.getItem("orbital-offline-queue");
2550
+ if (stored) {
2551
+ this.state.syncQueue = JSON.parse(stored);
2552
+ }
2553
+ } catch (error) {
2554
+ console.warn("[OfflineExecutor] Failed to load sync queue:", error);
2555
+ }
2556
+ }
2557
+ /**
2558
+ * Save sync queue to localStorage
2559
+ */
2560
+ saveSyncQueue() {
2561
+ if (!this.storage) return;
2562
+ try {
2563
+ this.storage.setItem("orbital-offline-queue", JSON.stringify(this.state.syncQueue));
2564
+ } catch (error) {
2565
+ console.warn("[OfflineExecutor] Failed to save sync queue:", error);
2566
+ }
2567
+ }
2568
+ /**
2569
+ * Add an effect to the sync queue
2570
+ */
2571
+ queueForSync(type, payload) {
2572
+ if (!this.config.enableSyncQueue) return;
2573
+ const effect = {
2574
+ id: generateEffectId(),
2575
+ timestamp: Date.now(),
2576
+ type,
2577
+ payload,
2578
+ retries: 0,
2579
+ maxRetries: 3
2580
+ };
2581
+ this.state.syncQueue.push(effect);
2582
+ if (this.state.syncQueue.length > (this.config.maxQueueSize ?? 100)) {
2583
+ this.state.syncQueue.shift();
2584
+ }
2585
+ this.saveSyncQueue();
2586
+ this.config.onEffectQueued?.(effect);
2587
+ this.config.onQueueChange?.(this.state.syncQueue);
2588
+ }
2589
+ /**
2590
+ * Execute client effects immediately.
2591
+ */
2592
+ executeClientEffects(effects) {
2593
+ if (effects.length === 0) return;
2594
+ executeClientEffects(effects, this.config);
2595
+ this.state.localEffectsProcessed += effects.length;
2596
+ }
2597
+ /**
2598
+ * Process an event in offline mode.
2599
+ *
2600
+ * Returns a simulated EventResponse with mock data.
2601
+ * Client effects are executed immediately.
2602
+ * Server effects are queued for sync.
2603
+ */
2604
+ processEventOffline(event, payload, effects) {
2605
+ const clientEffects = [];
2606
+ const fetchedData = {};
2607
+ if (effects) {
2608
+ for (const effect of effects) {
2609
+ if (!Array.isArray(effect) || effect.length < 1) continue;
2610
+ const [type, ...args] = effect;
2611
+ switch (type) {
2612
+ // Client effects - execute immediately
2613
+ case "render-ui":
2614
+ case "navigate":
2615
+ case "notify":
2616
+ case "emit":
2617
+ clientEffects.push(effect);
2618
+ break;
2619
+ // Fetch effect - use mock data
2620
+ case "fetch": {
2621
+ const [entityName, _query] = args;
2622
+ if (typeof entityName === "string" && this.config.mockDataProvider) {
2623
+ fetchedData[entityName] = this.config.mockDataProvider(entityName);
2624
+ }
2625
+ break;
2626
+ }
2627
+ // Server effects - queue for sync
2628
+ case "persist":
2629
+ case "call-service":
2630
+ case "spawn":
2631
+ case "despawn":
2632
+ this.queueForSync(type, { args, event, payload });
2633
+ break;
2634
+ default:
2635
+ console.warn(`[OfflineExecutor] Unknown effect type: ${type}`);
2636
+ }
2637
+ }
2638
+ }
2639
+ if (clientEffects.length > 0) {
2640
+ this.executeClientEffects(clientEffects);
2641
+ }
2642
+ return {
2643
+ success: true,
2644
+ data: Object.keys(fetchedData).length > 0 ? fetchedData : void 0,
2645
+ clientEffects: clientEffects.length > 0 ? clientEffects : void 0
2646
+ };
2647
+ }
2648
+ /**
2649
+ * Sync pending effects to server.
2650
+ *
2651
+ * @param serverUrl - Base URL for the orbital server
2652
+ * @param authToken - Optional auth token for requests
2653
+ * @returns Number of successfully synced effects
2654
+ */
2655
+ async syncPendingEffects(serverUrl, authToken) {
2656
+ if (this.state.syncQueue.length === 0) {
2657
+ return 0;
2658
+ }
2659
+ this.state.lastSyncAttempt = Date.now();
2660
+ let syncedCount = 0;
2661
+ const failedEffects = [];
2662
+ const headers = {
2663
+ "Content-Type": "application/json"
2664
+ };
2665
+ if (authToken) {
2666
+ headers["Authorization"] = `Bearer ${authToken}`;
2667
+ }
2668
+ for (const effect of this.state.syncQueue) {
2669
+ try {
2670
+ const response = await fetch(`${serverUrl}/sync-effect`, {
2671
+ method: "POST",
2672
+ headers,
2673
+ body: JSON.stringify({
2674
+ type: effect.type,
2675
+ payload: effect.payload,
2676
+ offlineId: effect.id,
2677
+ offlineTimestamp: effect.timestamp
2678
+ })
2679
+ });
2680
+ if (response.ok) {
2681
+ syncedCount++;
2682
+ } else {
2683
+ effect.retries++;
2684
+ if (effect.retries < effect.maxRetries) {
2685
+ failedEffects.push(effect);
2686
+ }
2687
+ }
2688
+ } catch (error) {
2689
+ effect.retries++;
2690
+ if (effect.retries < effect.maxRetries) {
2691
+ failedEffects.push(effect);
2692
+ }
2693
+ }
2694
+ }
2695
+ this.state.syncQueue = failedEffects;
2696
+ this.state.effectsSynced += syncedCount;
2697
+ if (syncedCount > 0) {
2698
+ this.state.lastSuccessfulSync = Date.now();
2699
+ }
2700
+ this.saveSyncQueue();
2701
+ this.config.onQueueChange?.(this.state.syncQueue);
2702
+ return syncedCount;
2703
+ }
2704
+ /**
2705
+ * Get current executor state
2706
+ */
2707
+ getState() {
2708
+ return { ...this.state };
2709
+ }
2710
+ /**
2711
+ * Get number of pending effects
2712
+ */
2713
+ getPendingCount() {
2714
+ return this.state.syncQueue.length;
2715
+ }
2716
+ /**
2717
+ * Clear the sync queue
2718
+ */
2719
+ clearQueue() {
2720
+ this.state.syncQueue = [];
2721
+ this.saveSyncQueue();
2722
+ this.config.onQueueChange?.(this.state.syncQueue);
2723
+ }
2724
+ /**
2725
+ * Dispose the executor and clean up listeners
2726
+ */
2727
+ dispose() {
2728
+ if (typeof window !== "undefined") {
2729
+ window.removeEventListener("online", this.handleOnline);
2730
+ window.removeEventListener("offline", this.handleOffline);
2731
+ }
2732
+ }
2733
+ };
2734
+ function useOfflineExecutor(options) {
2735
+ const executorRef = React113.useRef(null);
2736
+ const [state, setState] = React113.useState({
2737
+ isOffline: false,
2738
+ syncQueue: [],
2739
+ localEffectsProcessed: 0,
2740
+ effectsSynced: 0
2741
+ });
2742
+ React113.useEffect(() => {
2743
+ const executor = new OfflineExecutor({
2744
+ ...options,
2745
+ onQueueChange: (queue) => {
2746
+ setState(executor.getState());
2747
+ options.onQueueChange?.(queue);
2748
+ }
2749
+ });
2750
+ executorRef.current = executor;
2751
+ setState(executor.getState());
2752
+ return () => {
2753
+ executor.dispose();
2754
+ executorRef.current = null;
2755
+ };
2756
+ }, []);
2757
+ React113.useEffect(() => {
2758
+ if (!options.autoSync || !options.serverUrl) return;
2759
+ const handleOnline = async () => {
2760
+ if (executorRef.current) {
2761
+ await executorRef.current.syncPendingEffects(
2762
+ options.serverUrl,
2763
+ options.authToken
2764
+ );
2765
+ setState(executorRef.current.getState());
2766
+ }
2767
+ };
2768
+ window.addEventListener("online", handleOnline);
2769
+ return () => window.removeEventListener("online", handleOnline);
2770
+ }, [options.autoSync, options.serverUrl, options.authToken]);
2771
+ const executeEffects = React113.useCallback((effects) => {
2772
+ executorRef.current?.executeClientEffects(effects);
2773
+ if (executorRef.current) {
2774
+ setState(executorRef.current.getState());
2775
+ }
2776
+ }, []);
2777
+ const processEventOffline = React113.useCallback(
2778
+ (event, payload, effects) => {
2779
+ const result = executorRef.current?.processEventOffline(event, payload, effects);
2780
+ if (executorRef.current) {
2781
+ setState(executorRef.current.getState());
2782
+ }
2783
+ return result ?? { success: false, error: "Executor not initialized" };
2784
+ },
2785
+ []
2786
+ );
2787
+ const sync = React113.useCallback(async () => {
2788
+ if (!executorRef.current || !options.serverUrl) return 0;
2789
+ const count = await executorRef.current.syncPendingEffects(
2790
+ options.serverUrl,
2791
+ options.authToken
2792
+ );
2793
+ setState(executorRef.current.getState());
2794
+ return count;
2795
+ }, [options.serverUrl, options.authToken]);
2796
+ const clearQueue = React113.useCallback(() => {
2797
+ executorRef.current?.clearQueue();
2798
+ if (executorRef.current) {
2799
+ setState(executorRef.current.getState());
2800
+ }
2801
+ }, []);
2802
+ return {
2803
+ state,
2804
+ isOffline: state.isOffline,
2805
+ pendingCount: state.syncQueue.length,
2806
+ executeClientEffects: executeEffects,
2807
+ processEventOffline,
2808
+ sync,
2809
+ clearQueue
2810
+ };
2811
+ }
2812
+ React113.createContext(null);
2813
+ var defaultIcon = L__default.default.icon({
2814
+ iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
2815
+ iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
2816
+ shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
2817
+ iconSize: [25, 41],
2818
+ iconAnchor: [12, 41],
2819
+ popupAnchor: [1, -34],
2820
+ shadowSize: [41, 41]
2821
+ });
2822
+ L__default.default.Marker.prototype.options.icon = defaultIcon;
2823
+
2824
+ // lib/verificationRegistry.ts
2825
+ var checks = /* @__PURE__ */ new Map();
2826
+ var transitions = [];
2827
+ var MAX_TRANSITIONS = 500;
2828
+ var listeners = /* @__PURE__ */ new Set();
2829
+ function notifyListeners() {
2830
+ listeners.forEach((l) => l());
2831
+ exposeOnWindow();
2832
+ }
2833
+ function registerCheck(id, label, status = "pending", details) {
2834
+ checks.set(id, { id, label, status, details, updatedAt: Date.now() });
2835
+ notifyListeners();
2836
+ }
2837
+ function getAllChecks() {
2838
+ return Array.from(checks.values());
2839
+ }
2840
+ function recordTransition(trace) {
2841
+ const entry = {
2842
+ ...trace,
2843
+ id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
2844
+ };
2845
+ transitions.push(entry);
2846
+ if (transitions.length > MAX_TRANSITIONS) {
2847
+ transitions.shift();
2848
+ }
2849
+ if (entry.event === "INIT") {
2850
+ const hasFetch = entry.effects.some((e) => e.type === "fetch");
2851
+ const checkId = `init-fetch-${entry.traitName}`;
2852
+ if (hasFetch) {
2853
+ registerCheck(
2854
+ checkId,
2855
+ `INIT transition for "${entry.traitName}" has fetch effect`,
2856
+ "pass"
2857
+ );
2858
+ } else {
2859
+ const hasRenderUI = entry.effects.some((e) => e.type === "render-ui");
2860
+ if (hasRenderUI) {
2861
+ registerCheck(
2862
+ checkId,
2863
+ `INIT transition for "${entry.traitName}" missing fetch effect`,
2864
+ "fail",
2865
+ "Entity-bound render-ui without a fetch effect will show empty data"
2866
+ );
2867
+ }
2868
+ }
2869
+ }
2870
+ const failedEffects = entry.effects.filter((e) => e.status === "failed");
2871
+ if (failedEffects.length > 0) {
2872
+ registerCheck(
2873
+ `effects-${entry.id}`,
2874
+ `Effects failed in ${entry.traitName}: ${entry.from} -> ${entry.to}`,
2875
+ "fail",
2876
+ failedEffects.map((e) => `${e.type}: ${e.error}`).join("; ")
2877
+ );
2878
+ }
2879
+ notifyListeners();
2880
+ }
2881
+ function getTransitions() {
2882
+ return [...transitions];
2883
+ }
2884
+ function getBridgeHealth() {
2885
+ return null;
2886
+ }
2887
+ function getSummary() {
2888
+ const allChecks = getAllChecks();
2889
+ return {
2890
+ totalChecks: allChecks.length,
2891
+ passed: allChecks.filter((c) => c.status === "pass").length,
2892
+ failed: allChecks.filter((c) => c.status === "fail").length,
2893
+ warnings: allChecks.filter((c) => c.status === "warn").length,
2894
+ pending: allChecks.filter((c) => c.status === "pending").length
2895
+ };
2896
+ }
2897
+ function getSnapshot() {
2898
+ return {
2899
+ checks: getAllChecks(),
2900
+ transitions: getTransitions(),
2901
+ bridge: getBridgeHealth(),
2902
+ summary: getSummary()
2903
+ };
2904
+ }
2905
+ function subscribeToVerification(listener) {
2906
+ listeners.add(listener);
2907
+ return () => listeners.delete(listener);
2908
+ }
2909
+ function exposeOnWindow() {
2910
+ if (typeof window === "undefined") return;
2911
+ if (!window.__orbitalVerification) {
2912
+ window.__orbitalVerification = {
2913
+ getSnapshot,
2914
+ getChecks: getAllChecks,
2915
+ getTransitions,
2916
+ getBridge: getBridgeHealth,
2917
+ getSummary,
2918
+ waitForTransition
2919
+ };
2920
+ }
2921
+ }
2922
+ function waitForTransition(event, timeoutMs = 1e4) {
2923
+ return new Promise((resolve) => {
2924
+ const existing = transitions.find((t) => t.event === event);
2925
+ if (existing) {
2926
+ resolve(existing);
2927
+ return;
2928
+ }
2929
+ const timeout = setTimeout(() => {
2930
+ unsub();
2931
+ resolve(null);
2932
+ }, timeoutMs);
2933
+ const unsub = subscribeToVerification(() => {
2934
+ const found = transitions.find((t) => t.event === event);
2935
+ if (found) {
2936
+ clearTimeout(timeout);
2937
+ unsub();
2938
+ resolve(found);
2939
+ }
2940
+ });
2941
+ });
2942
+ }
2943
+ function bindEventBus(eventBus) {
2944
+ if (typeof window === "undefined") return;
2945
+ exposeOnWindow();
2946
+ if (window.__orbitalVerification) {
2947
+ window.__orbitalVerification.sendEvent = (event, payload) => {
2948
+ const prefixed = event.startsWith("UI:") ? event : `UI:${event}`;
2949
+ eventBus.emit(prefixed, payload);
2950
+ };
2951
+ const eventLog = [];
2952
+ window.__orbitalVerification.eventLog = eventLog;
2953
+ window.__orbitalVerification.clearEventLog = () => {
2954
+ eventLog.length = 0;
2955
+ };
2956
+ if (eventBus.onAny) {
2957
+ eventBus.onAny((event) => {
2958
+ if (eventLog.length < 200) {
2959
+ eventLog.push({
2960
+ type: event.type,
2961
+ payload: event.payload,
2962
+ timestamp: Date.now()
2963
+ });
2964
+ }
2965
+ });
2966
+ }
2967
+ }
2968
+ }
2969
+ function bindTraitStateGetter(getter) {
2970
+ if (typeof window === "undefined") return;
2971
+ exposeOnWindow();
2972
+ if (window.__orbitalVerification) {
2973
+ window.__orbitalVerification.getTraitState = getter;
2974
+ }
2975
+ }
2976
+ exposeOnWindow();
2977
+ var MarkdownContent = React113__namespace.default.memo(
2978
+ ({ content, direction, className }) => {
2979
+ const { t: _t } = useTranslate();
2980
+ return /* @__PURE__ */ jsxRuntime.jsx(
2981
+ Box,
2982
+ {
2983
+ className: cn("prose prose-slate dark:prose-invert max-w-none", className),
2984
+ style: { direction },
2985
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2986
+ ReactMarkdown__default.default,
2987
+ {
2988
+ remarkPlugins: [remarkMath__default.default, remarkGfm__default.default],
2989
+ rehypePlugins: [
2990
+ [rehypeKatex__default.default, { strict: false, throwOnError: false }]
2991
+ ],
2992
+ components: {
2993
+ // Handle inline code only — fenced code blocks are parsed out separately
2994
+ code({ className: codeClassName, children, ...props }) {
2995
+ return /* @__PURE__ */ jsxRuntime.jsx(
2996
+ "code",
2997
+ {
2998
+ ...props,
2999
+ className: codeClassName,
3000
+ style: {
3001
+ backgroundColor: "#1f2937",
3002
+ color: "#e5e7eb",
3003
+ padding: "0.125rem 0.375rem",
3004
+ borderRadius: "0.25rem",
3005
+ fontSize: "0.875em",
3006
+ fontFamily: "ui-monospace, monospace"
3007
+ },
3008
+ children
3009
+ }
3010
+ );
3011
+ },
3012
+ // Style links
3013
+ a({ href, children, ...props }) {
3014
+ return /* @__PURE__ */ jsxRuntime.jsx(
3015
+ "a",
3016
+ {
3017
+ href,
3018
+ ...props,
3019
+ className: "text-blue-600 dark:text-blue-400 hover:underline",
3020
+ target: href?.startsWith("http") ? "_blank" : void 0,
3021
+ rel: href?.startsWith("http") ? "noopener noreferrer" : void 0,
3022
+ children
3023
+ }
3024
+ );
3025
+ },
3026
+ // Style tables
3027
+ table({ children, ...props }) {
3028
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ jsxRuntime.jsx(
3029
+ "table",
3030
+ {
3031
+ ...props,
3032
+ className: "min-w-full border-collapse border border-gray-300 dark:border-gray-600",
3033
+ children
3034
+ }
3035
+ ) });
3036
+ },
3037
+ th({ children, ...props }) {
3038
+ return /* @__PURE__ */ jsxRuntime.jsx(
3039
+ "th",
3040
+ {
3041
+ ...props,
3042
+ className: "border border-gray-300 dark:border-gray-600 bg-gray-100 dark:bg-gray-800 px-4 py-2 text-left font-semibold",
3043
+ children
3044
+ }
3045
+ );
3046
+ },
3047
+ td({ children, ...props }) {
3048
+ return /* @__PURE__ */ jsxRuntime.jsx(
3049
+ "td",
3050
+ {
3051
+ ...props,
3052
+ className: "border border-gray-300 dark:border-gray-600 px-4 py-2",
3053
+ children
3054
+ }
3055
+ );
3056
+ },
3057
+ // Style blockquotes
3058
+ blockquote({ children, ...props }) {
3059
+ return /* @__PURE__ */ jsxRuntime.jsx(
3060
+ "blockquote",
3061
+ {
3062
+ ...props,
3063
+ className: "border-l-4 border-blue-500 pl-4 italic text-[var(--color-foreground)] my-4",
3064
+ children
3065
+ }
3066
+ );
3067
+ }
3068
+ },
3069
+ children: content
3070
+ }
3071
+ )
3072
+ }
3073
+ );
3074
+ },
3075
+ (prev, next) => prev.content === next.content && prev.className === next.className && prev.direction === next.direction
3076
+ );
3077
+ MarkdownContent.displayName = "MarkdownContent";
3078
+ var CodeBlock = React113__namespace.default.memo(
3079
+ ({
3080
+ code,
3081
+ language = "text",
3082
+ showCopyButton = true,
3083
+ showLanguageBadge = true,
3084
+ maxHeight = "60vh",
3085
+ className
3086
+ }) => {
3087
+ const eventBus = useEventBus();
3088
+ const { t: _t } = useTranslate();
3089
+ const scrollRef = React113.useRef(null);
3090
+ const savedScrollLeftRef = React113.useRef(0);
3091
+ const [copied, setCopied] = React113.useState(false);
3092
+ React113.useLayoutEffect(() => {
3093
+ const el = scrollRef.current;
3094
+ return () => {
3095
+ if (el) savedScrollLeftRef.current = el.scrollLeft;
3096
+ };
3097
+ }, [language, code]);
3098
+ React113.useLayoutEffect(() => {
3099
+ const el = scrollRef.current;
3100
+ if (el) el.scrollLeft = savedScrollLeftRef.current;
3101
+ }, [language, code]);
3102
+ React113.useEffect(() => {
3103
+ const el = scrollRef.current;
3104
+ if (!el) return;
3105
+ const handle = () => {
3106
+ savedScrollLeftRef.current = el.scrollLeft;
3107
+ };
3108
+ el.addEventListener("scroll", handle, { passive: true });
3109
+ return () => el.removeEventListener("scroll", handle);
3110
+ }, [language, code]);
3111
+ const handleCopy = async () => {
3112
+ try {
3113
+ await navigator.clipboard.writeText(code);
3114
+ setCopied(true);
3115
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
3116
+ setTimeout(() => setCopied(false), 2e3);
3117
+ } catch (err) {
3118
+ console.error("Failed to copy code:", err);
3119
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
3120
+ }
3121
+ };
3122
+ return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: `relative group ${className || ""}`, children: [
3123
+ (showLanguageBadge || showCopyButton) && /* @__PURE__ */ jsxRuntime.jsxs(
3124
+ HStack,
3125
+ {
3126
+ justify: "between",
3127
+ align: "center",
3128
+ className: "px-3 py-2 bg-gray-800 rounded-t-lg border-b border-gray-700",
3129
+ children: [
3130
+ showLanguageBadge && /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: "default", size: "sm", children: language }),
3131
+ showCopyButton && /* @__PURE__ */ jsxRuntime.jsx(
3132
+ Button,
3133
+ {
3134
+ variant: "ghost",
3135
+ size: "sm",
3136
+ onClick: handleCopy,
3137
+ className: "opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity text-[var(--color-muted-foreground)] hover:text-white",
3138
+ "aria-label": "Copy code",
3139
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Check, { size: 16, className: "text-green-400" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Copy, { size: 16 })
3140
+ }
3141
+ )
3142
+ ]
3143
+ }
3144
+ ),
3145
+ /* @__PURE__ */ jsxRuntime.jsx(
3146
+ "div",
3147
+ {
3148
+ ref: scrollRef,
3149
+ style: {
3150
+ overflowX: "auto",
3151
+ overflowY: "auto",
3152
+ WebkitOverflowScrolling: "touch",
3153
+ maxHeight,
3154
+ overscrollBehavior: "auto",
3155
+ touchAction: "pan-x pan-y",
3156
+ contain: "paint",
3157
+ backgroundColor: "#1e1e1e",
3158
+ borderRadius: showLanguageBadge || showCopyButton ? "0 0 0.5rem 0.5rem" : "0.5rem",
3159
+ padding: "1rem"
3160
+ },
3161
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3162
+ SyntaxHighlighter__default.default,
3163
+ {
3164
+ PreTag: "div",
3165
+ language,
3166
+ style: dark__default.default,
3167
+ customStyle: {
3168
+ backgroundColor: "transparent",
3169
+ borderRadius: 0,
3170
+ padding: 0,
3171
+ margin: 0,
3172
+ whiteSpace: "pre",
3173
+ minWidth: "100%"
3174
+ },
3175
+ children: code
3176
+ }
3177
+ )
3178
+ }
3179
+ )
3180
+ ] });
3181
+ },
3182
+ (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight
3183
+ );
3184
+ CodeBlock.displayName = "CodeBlock";
3185
+ var Camera3D = React113.forwardRef(
3186
+ ({
3187
+ mode = "isometric",
3188
+ position = [10, 10, 10],
3189
+ target = [0, 0, 0],
3190
+ zoom = 1,
3191
+ fov = 45,
3192
+ enableOrbit = true,
3193
+ minDistance = 2,
3194
+ maxDistance = 100,
3195
+ onChange
3196
+ }, ref) => {
3197
+ const { camera, set, viewport } = fiber.useThree();
3198
+ const controlsRef = React113.useRef(null);
3199
+ const initialPosition = React113.useRef(new THREE__namespace.Vector3(...position));
3200
+ const initialTarget = React113.useRef(new THREE__namespace.Vector3(...target));
3201
+ React113.useEffect(() => {
3202
+ let newCamera;
3203
+ if (mode === "isometric") {
3204
+ const aspect = viewport.aspect;
3205
+ const size = 10 / zoom;
3206
+ newCamera = new THREE__namespace.OrthographicCamera(
3207
+ -size * aspect,
3208
+ size * aspect,
3209
+ size,
3210
+ -size,
3211
+ 0.1,
3212
+ 1e3
3213
+ );
3214
+ } else {
3215
+ newCamera = new THREE__namespace.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
3216
+ }
3217
+ newCamera.position.copy(initialPosition.current);
3218
+ newCamera.lookAt(initialTarget.current);
3219
+ set({ camera: newCamera });
3220
+ if (mode === "top-down") {
3221
+ newCamera.position.set(0, 20 / zoom, 0);
3222
+ newCamera.lookAt(0, 0, 0);
3223
+ }
3224
+ return () => {
3225
+ };
3226
+ }, [mode, fov, zoom, viewport.aspect, set]);
3227
+ fiber.useFrame(() => {
3228
+ if (onChange) {
3229
+ onChange(camera);
3230
+ }
3231
+ });
3232
+ React113.useImperativeHandle(ref, () => ({
3233
+ getCamera: () => camera,
3234
+ setPosition: (x, y, z) => {
3235
+ camera.position.set(x, y, z);
3236
+ if (controlsRef.current) {
3237
+ controlsRef.current.update();
3238
+ }
3239
+ },
3240
+ lookAt: (x, y, z) => {
3241
+ camera.lookAt(x, y, z);
3242
+ if (controlsRef.current) {
3243
+ controlsRef.current.target.set(x, y, z);
3244
+ controlsRef.current.update();
3245
+ }
3246
+ },
3247
+ reset: () => {
3248
+ camera.position.copy(initialPosition.current);
3249
+ camera.lookAt(initialTarget.current);
3250
+ if (controlsRef.current) {
3251
+ controlsRef.current.target.copy(initialTarget.current);
3252
+ controlsRef.current.update();
3253
+ }
3254
+ },
3255
+ getViewBounds: () => {
3256
+ const min = new THREE__namespace.Vector3(-10, -10, -10);
3257
+ const max = new THREE__namespace.Vector3(10, 10, 10);
3258
+ return { min, max };
3259
+ }
3260
+ }));
3261
+ const maxPolarAngle = mode === "top-down" ? 0.1 : Math.PI / 2 - 0.1;
3262
+ return /* @__PURE__ */ jsxRuntime.jsx(
3263
+ drei.OrbitControls,
3264
+ {
3265
+ ref: controlsRef,
3266
+ camera,
3267
+ enabled: enableOrbit,
3268
+ target: initialTarget.current,
3269
+ minDistance,
3270
+ maxDistance,
3271
+ maxPolarAngle,
3272
+ enableDamping: true,
3273
+ dampingFactor: 0.05
3274
+ }
3275
+ );
3276
+ }
3277
+ );
3278
+ Camera3D.displayName = "Camera3D";
3279
+ var Canvas3DErrorBoundary = class extends React113.Component {
3280
+ constructor(props) {
3281
+ super(props);
3282
+ __publicField(this, "handleReset", () => {
3283
+ this.setState({
3284
+ hasError: false,
3285
+ error: null,
3286
+ errorInfo: null
3287
+ });
3288
+ this.props.onReset?.();
3289
+ });
3290
+ this.state = {
3291
+ hasError: false,
3292
+ error: null,
3293
+ errorInfo: null
3294
+ };
3295
+ }
3296
+ static getDerivedStateFromError(error) {
3297
+ return {
3298
+ hasError: true,
3299
+ error,
3300
+ errorInfo: null
3301
+ };
3302
+ }
3303
+ componentDidCatch(error, errorInfo) {
3304
+ this.setState({ errorInfo });
3305
+ this.props.onError?.(error, errorInfo);
3306
+ console.error("[Canvas3DErrorBoundary] Error caught:", error);
3307
+ console.error("[Canvas3DErrorBoundary] Component stack:", errorInfo.componentStack);
3308
+ }
3309
+ render() {
3310
+ if (this.state.hasError) {
3311
+ if (this.props.fallback) {
3312
+ return this.props.fallback;
3313
+ }
3314
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__content", children: [
3315
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
3316
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
3317
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
3318
+ this.state.error && /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "canvas-3d-error__details", children: [
3319
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Error Details" }),
3320
+ /* @__PURE__ */ jsxRuntime.jsxs("pre", { className: "error__stack", children: [
3321
+ this.state.error.message,
3322
+ "\n",
3323
+ this.state.error.stack
3324
+ ] }),
3325
+ this.state.errorInfo && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
3326
+ ] }),
3327
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-error__actions", children: [
3328
+ /* @__PURE__ */ jsxRuntime.jsx(
3329
+ "button",
3330
+ {
3331
+ className: "error__button error__button--primary",
3332
+ onClick: this.handleReset,
3333
+ children: "Try Again"
3334
+ }
3335
+ ),
3336
+ /* @__PURE__ */ jsxRuntime.jsx(
3337
+ "button",
3338
+ {
3339
+ className: "error__button error__button--secondary",
3340
+ onClick: () => window.location.reload(),
3341
+ children: "Reload Page"
3342
+ }
3343
+ )
3344
+ ] })
3345
+ ] }) });
3346
+ }
3347
+ return this.props.children;
3348
+ }
3349
+ };
3350
+ function Canvas3DLoadingState({
3351
+ progress = 0,
3352
+ loaded = 0,
3353
+ total = 0,
3354
+ message = "Loading 3D Scene...",
3355
+ details,
3356
+ showSpinner = true,
3357
+ className
3358
+ }) {
3359
+ const clampedProgress = Math.max(0, Math.min(100, progress));
3360
+ const hasProgress = total > 0;
3361
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
3362
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__content", children: [
3363
+ showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__spinner", children: [
3364
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring" }),
3365
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "spinner__ring spinner__ring--secondary" })
3366
+ ] }),
3367
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__message", children: message }),
3368
+ details && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__details", children: details }),
3369
+ hasProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "canvas-3d-loading__progress", children: [
3370
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsxRuntime.jsx(
3371
+ "div",
3372
+ {
3373
+ className: "progress__fill",
3374
+ style: { width: `${clampedProgress}%` }
3375
+ }
3376
+ ) }),
3377
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "progress__text", children: [
3378
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__percentage", children: [
3379
+ clampedProgress,
3380
+ "%"
3381
+ ] }),
3382
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "progress__count", children: [
3383
+ "(",
3384
+ loaded,
3385
+ "/",
3386
+ total,
3387
+ ")"
3388
+ ] })
3389
+ ] })
3390
+ ] })
3391
+ ] }),
3392
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg__grid" }) })
3393
+ ] });
3394
+ }
3395
+
3396
+ // lib/debug.ts
3397
+ typeof window !== "undefined" && (localStorage.getItem("debug") === "true" || process.env.NODE_ENV === "development");
3398
+ React113.lazy(() => import('react-markdown'));
3399
+ var GameAudioContext = React113.createContext(null);
3400
+ GameAudioContext.displayName = "GameAudioContext";
3401
+ function detectAssetRoot2(modelUrl) {
3402
+ const idx = modelUrl.indexOf("/3d/");
3403
+ if (idx !== -1) {
3404
+ return modelUrl.substring(0, idx + 4);
3405
+ }
3406
+ return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
3407
+ }
3408
+ function createGLTFLoaderForUrl(url) {
3409
+ const loader = new GLTFLoader_js.GLTFLoader();
3410
+ loader.setResourcePath(detectAssetRoot2(url));
3411
+ return loader;
3412
+ }
3413
+ var AssetLoader = class {
3414
+ constructor() {
3415
+ __publicField(this, "objLoader");
3416
+ __publicField(this, "textureLoader");
3417
+ __publicField(this, "modelCache");
3418
+ __publicField(this, "textureCache");
3419
+ __publicField(this, "loadingPromises");
3420
+ this.objLoader = new OBJLoader_js.OBJLoader();
3421
+ this.textureLoader = new THREE__namespace.TextureLoader();
3422
+ this.modelCache = /* @__PURE__ */ new Map();
3423
+ this.textureCache = /* @__PURE__ */ new Map();
3424
+ this.loadingPromises = /* @__PURE__ */ new Map();
3425
+ }
3426
+ /**
3427
+ * Load a GLB/GLTF model
3428
+ * @param url - URL to the .glb or .gltf file
3429
+ * @returns Promise with loaded model scene and animations
3430
+ */
3431
+ async loadModel(url) {
3432
+ if (this.modelCache.has(url)) {
3433
+ return this.modelCache.get(url);
3434
+ }
3435
+ if (this.loadingPromises.has(url)) {
3436
+ return this.loadingPromises.get(url);
3437
+ }
3438
+ const loader = createGLTFLoaderForUrl(url);
3439
+ const loadPromise = loader.loadAsync(url).then((gltf) => {
3440
+ const result = {
3441
+ scene: gltf.scene,
3442
+ animations: gltf.animations || []
3443
+ };
3444
+ this.modelCache.set(url, result);
3445
+ this.loadingPromises.delete(url);
3446
+ return result;
3447
+ }).catch((error) => {
3448
+ this.loadingPromises.delete(url);
3449
+ throw new Error(`Failed to load model ${url}: ${error.message}`);
3450
+ });
3451
+ this.loadingPromises.set(url, loadPromise);
3452
+ return loadPromise;
3453
+ }
3454
+ /**
3455
+ * Load an OBJ model (fallback for non-GLB assets)
3456
+ * @param url - URL to the .obj file
3457
+ * @returns Promise with loaded object group
3458
+ */
3459
+ async loadOBJ(url) {
3460
+ if (this.modelCache.has(url)) {
3461
+ return this.modelCache.get(url).scene;
3462
+ }
3463
+ if (this.loadingPromises.has(url)) {
3464
+ const result = await this.loadingPromises.get(url);
3465
+ return result.scene;
3466
+ }
3467
+ const loadPromise = this.objLoader.loadAsync(url).then((group) => {
3468
+ const result = {
3469
+ scene: group,
3470
+ animations: []
3471
+ };
3472
+ this.modelCache.set(url, result);
3473
+ this.loadingPromises.delete(url);
3474
+ return result;
3475
+ }).catch((error) => {
3476
+ this.loadingPromises.delete(url);
3477
+ throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
3478
+ });
3479
+ this.loadingPromises.set(url, loadPromise);
3480
+ return (await loadPromise).scene;
3481
+ }
3482
+ /**
3483
+ * Load a texture
3484
+ * @param url - URL to the texture image
3485
+ * @returns Promise with loaded texture
3486
+ */
3487
+ async loadTexture(url) {
3488
+ if (this.textureCache.has(url)) {
3489
+ return this.textureCache.get(url);
3490
+ }
3491
+ if (this.loadingPromises.has(`texture:${url}`)) {
3492
+ return this.loadingPromises.get(`texture:${url}`);
3493
+ }
3494
+ const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
3495
+ texture.colorSpace = THREE__namespace.SRGBColorSpace;
3496
+ this.textureCache.set(url, texture);
3497
+ this.loadingPromises.delete(`texture:${url}`);
3498
+ return texture;
3499
+ }).catch((error) => {
3500
+ this.loadingPromises.delete(`texture:${url}`);
3501
+ throw new Error(`Failed to load texture ${url}: ${error.message}`);
3502
+ });
3503
+ this.loadingPromises.set(`texture:${url}`, loadPromise);
3504
+ return loadPromise;
3505
+ }
3506
+ /**
3507
+ * Preload multiple assets
3508
+ * @param urls - Array of asset URLs to preload
3509
+ * @returns Promise that resolves when all assets are loaded
3510
+ */
3511
+ async preload(urls) {
3512
+ const promises = urls.map((url) => {
3513
+ if (url.endsWith(".glb") || url.endsWith(".gltf")) {
3514
+ return this.loadModel(url).catch(() => null);
3515
+ } else if (url.endsWith(".obj")) {
3516
+ return this.loadOBJ(url).catch(() => null);
3517
+ } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
3518
+ return this.loadTexture(url).catch(() => null);
3519
+ }
3520
+ return Promise.resolve(null);
3521
+ });
3522
+ await Promise.all(promises);
3523
+ }
3524
+ /**
3525
+ * Check if a model is cached
3526
+ * @param url - Model URL
3527
+ */
3528
+ hasModel(url) {
3529
+ return this.modelCache.has(url);
3530
+ }
3531
+ /**
3532
+ * Check if a texture is cached
3533
+ * @param url - Texture URL
3534
+ */
3535
+ hasTexture(url) {
3536
+ return this.textureCache.has(url);
3537
+ }
3538
+ /**
3539
+ * Get cached model (throws if not cached)
3540
+ * @param url - Model URL
3541
+ */
3542
+ getModel(url) {
3543
+ const model = this.modelCache.get(url);
3544
+ if (!model) {
3545
+ throw new Error(`Model ${url} not in cache`);
3546
+ }
3547
+ return model;
3548
+ }
3549
+ /**
3550
+ * Get cached texture (throws if not cached)
3551
+ * @param url - Texture URL
3552
+ */
3553
+ getTexture(url) {
3554
+ const texture = this.textureCache.get(url);
3555
+ if (!texture) {
3556
+ throw new Error(`Texture ${url} not in cache`);
3557
+ }
3558
+ return texture;
3559
+ }
3560
+ /**
3561
+ * Clear all caches
3562
+ */
3563
+ clearCache() {
3564
+ this.textureCache.forEach((texture) => {
3565
+ texture.dispose();
3566
+ });
3567
+ this.modelCache.forEach((model) => {
3568
+ model.scene.traverse((child) => {
3569
+ if (child instanceof THREE__namespace.Mesh) {
3570
+ child.geometry.dispose();
3571
+ if (Array.isArray(child.material)) {
3572
+ child.material.forEach((m) => m.dispose());
3573
+ } else {
3574
+ child.material.dispose();
3575
+ }
3576
+ }
3577
+ });
3578
+ });
3579
+ this.modelCache.clear();
3580
+ this.textureCache.clear();
3581
+ this.loadingPromises.clear();
3582
+ }
3583
+ /**
3584
+ * Get cache statistics
3585
+ */
3586
+ getStats() {
3587
+ return {
3588
+ models: this.modelCache.size,
3589
+ textures: this.textureCache.size,
3590
+ loading: this.loadingPromises.size
3591
+ };
3592
+ }
3593
+ };
3594
+ new AssetLoader();
3595
+ function useAssetLoader(options = {}) {
3596
+ const { preloadUrls = [], loader: customLoader } = options;
3597
+ const loaderRef = React113.useRef(customLoader || new AssetLoader());
3598
+ const [state, setState] = React113.useState({
3599
+ isLoading: false,
3600
+ progress: 0,
3601
+ loaded: 0,
3602
+ total: 0,
3603
+ errors: []
3604
+ });
3605
+ React113.useEffect(() => {
3606
+ if (preloadUrls.length > 0) {
3607
+ preload(preloadUrls);
3608
+ }
3609
+ }, []);
3610
+ const updateProgress = React113.useCallback((loaded, total) => {
3611
+ setState((prev) => ({
3612
+ ...prev,
3613
+ loaded,
3614
+ total,
3615
+ progress: total > 0 ? Math.round(loaded / total * 100) : 0
3616
+ }));
3617
+ }, []);
3618
+ const loadModel = React113.useCallback(
3619
+ async (url) => {
3620
+ setState((prev) => ({ ...prev, isLoading: true }));
3621
+ try {
3622
+ const model = await loaderRef.current.loadModel(url);
3623
+ setState((prev) => ({
3624
+ ...prev,
3625
+ isLoading: false,
3626
+ loaded: prev.loaded + 1
3627
+ }));
3628
+ return model;
3629
+ } catch (error) {
3630
+ const errorMsg = error instanceof Error ? error.message : String(error);
3631
+ setState((prev) => ({
3632
+ ...prev,
3633
+ isLoading: false,
3634
+ errors: [...prev.errors, errorMsg]
3635
+ }));
3636
+ throw error;
3637
+ }
3638
+ },
3639
+ []
3640
+ );
3641
+ const loadOBJ = React113.useCallback(
3642
+ async (url) => {
3643
+ setState((prev) => ({ ...prev, isLoading: true }));
3644
+ try {
3645
+ const model = await loaderRef.current.loadOBJ(url);
3646
+ setState((prev) => ({
3647
+ ...prev,
3648
+ isLoading: false,
3649
+ loaded: prev.loaded + 1
3650
+ }));
3651
+ return model;
3652
+ } catch (error) {
3653
+ const errorMsg = error instanceof Error ? error.message : String(error);
3654
+ setState((prev) => ({
3655
+ ...prev,
3656
+ isLoading: false,
3657
+ errors: [...prev.errors, errorMsg]
3658
+ }));
3659
+ throw error;
3660
+ }
3661
+ },
3662
+ []
3663
+ );
3664
+ const loadTexture = React113.useCallback(
3665
+ async (url) => {
3666
+ setState((prev) => ({ ...prev, isLoading: true }));
3667
+ try {
3668
+ const texture = await loaderRef.current.loadTexture(url);
3669
+ setState((prev) => ({
3670
+ ...prev,
3671
+ isLoading: false,
3672
+ loaded: prev.loaded + 1
3673
+ }));
3674
+ return texture;
3675
+ } catch (error) {
3676
+ const errorMsg = error instanceof Error ? error.message : String(error);
3677
+ setState((prev) => ({
3678
+ ...prev,
3679
+ isLoading: false,
3680
+ errors: [...prev.errors, errorMsg]
3681
+ }));
3682
+ throw error;
3683
+ }
3684
+ },
3685
+ []
3686
+ );
3687
+ const preload = React113.useCallback(
3688
+ async (urls) => {
3689
+ setState((prev) => ({
3690
+ ...prev,
3691
+ isLoading: true,
3692
+ total: urls.length,
3693
+ loaded: 0,
3694
+ errors: []
3695
+ }));
3696
+ let completed = 0;
3697
+ const errors = [];
3698
+ await Promise.all(
3699
+ urls.map(async (url) => {
3700
+ try {
3701
+ if (url.endsWith(".glb") || url.endsWith(".gltf")) {
3702
+ await loaderRef.current.loadModel(url);
3703
+ } else if (url.endsWith(".obj")) {
3704
+ await loaderRef.current.loadOBJ(url);
3705
+ } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
3706
+ await loaderRef.current.loadTexture(url);
3707
+ }
3708
+ completed++;
3709
+ updateProgress(completed, urls.length);
3710
+ } catch (error) {
3711
+ const errorMsg = error instanceof Error ? error.message : String(error);
3712
+ errors.push(`${url}: ${errorMsg}`);
3713
+ completed++;
3714
+ updateProgress(completed, urls.length);
3715
+ }
3716
+ })
3717
+ );
3718
+ setState((prev) => ({
3719
+ ...prev,
3720
+ isLoading: false,
3721
+ errors
3722
+ }));
3723
+ },
3724
+ [updateProgress]
3725
+ );
3726
+ const hasModel = React113.useCallback((url) => {
3727
+ return loaderRef.current.hasModel(url);
3728
+ }, []);
3729
+ const hasTexture = React113.useCallback((url) => {
3730
+ return loaderRef.current.hasTexture(url);
3731
+ }, []);
3732
+ const getModel = React113.useCallback((url) => {
3733
+ try {
3734
+ return loaderRef.current.getModel(url);
3735
+ } catch {
3736
+ return void 0;
3737
+ }
3738
+ }, []);
3739
+ const getTexture = React113.useCallback((url) => {
3740
+ try {
3741
+ return loaderRef.current.getTexture(url);
3742
+ } catch {
3743
+ return void 0;
3744
+ }
3745
+ }, []);
3746
+ const clearCache = React113.useCallback(() => {
3747
+ loaderRef.current.clearCache();
3748
+ setState({
3749
+ isLoading: false,
3750
+ progress: 0,
3751
+ loaded: 0,
3752
+ total: 0,
3753
+ errors: []
3754
+ });
3755
+ }, []);
3756
+ return {
3757
+ ...state,
3758
+ loadModel,
3759
+ loadOBJ,
3760
+ loadTexture,
3761
+ preload,
3762
+ hasModel,
3763
+ hasTexture,
3764
+ getModel,
3765
+ getTexture,
3766
+ clearCache
3767
+ };
3768
+ }
3769
+ function useGameCanvas3DEvents(options) {
3770
+ const {
3771
+ tileClickEvent,
3772
+ unitClickEvent,
3773
+ featureClickEvent,
3774
+ canvasClickEvent,
3775
+ tileHoverEvent,
3776
+ tileLeaveEvent,
3777
+ unitAnimationEvent,
3778
+ cameraChangeEvent,
3779
+ onTileClick,
3780
+ onUnitClick,
3781
+ onFeatureClick,
3782
+ onCanvasClick,
3783
+ onTileHover,
3784
+ onUnitAnimation
3785
+ } = options;
3786
+ const emit = useEmitEvent();
3787
+ const optionsRef = React113.useRef(options);
3788
+ optionsRef.current = options;
3789
+ const handleTileClick = React113.useCallback(
3790
+ (tile, event) => {
3791
+ if (tileClickEvent) {
3792
+ emit(tileClickEvent, {
3793
+ tileId: tile.id,
3794
+ x: tile.x,
3795
+ z: tile.z ?? tile.y ?? 0,
3796
+ type: tile.type,
3797
+ terrain: tile.terrain,
3798
+ elevation: tile.elevation
3799
+ });
3800
+ }
3801
+ optionsRef.current.onTileClick?.(tile, event);
3802
+ },
3803
+ [tileClickEvent, emit]
3804
+ );
3805
+ const handleUnitClick = React113.useCallback(
3806
+ (unit, event) => {
3807
+ if (unitClickEvent) {
3808
+ emit(unitClickEvent, {
3809
+ unitId: unit.id,
3810
+ x: unit.x,
3811
+ z: unit.z ?? unit.y ?? 0,
3812
+ unitType: unit.unitType,
3813
+ name: unit.name,
3814
+ team: unit.team,
3815
+ faction: unit.faction,
3816
+ health: unit.health,
3817
+ maxHealth: unit.maxHealth
3818
+ });
3819
+ }
3820
+ optionsRef.current.onUnitClick?.(unit, event);
3821
+ },
3822
+ [unitClickEvent, emit]
3823
+ );
3824
+ const handleFeatureClick = React113.useCallback(
3825
+ (feature, event) => {
3826
+ if (featureClickEvent) {
3827
+ emit(featureClickEvent, {
3828
+ featureId: feature.id,
3829
+ x: feature.x,
3830
+ z: feature.z ?? feature.y ?? 0,
3831
+ type: feature.type,
3832
+ elevation: feature.elevation
3833
+ });
3834
+ }
3835
+ optionsRef.current.onFeatureClick?.(feature, event);
3836
+ },
3837
+ [featureClickEvent, emit]
3838
+ );
3839
+ const handleCanvasClick = React113.useCallback(
3840
+ (event) => {
3841
+ if (canvasClickEvent) {
3842
+ emit(canvasClickEvent, {
3843
+ clientX: event.clientX,
3844
+ clientY: event.clientY,
3845
+ button: event.button
3846
+ });
3847
+ }
3848
+ optionsRef.current.onCanvasClick?.(event);
3849
+ },
3850
+ [canvasClickEvent, emit]
3851
+ );
3852
+ const handleTileHover = React113.useCallback(
3853
+ (tile, event) => {
3854
+ if (tile) {
3855
+ if (tileHoverEvent) {
3856
+ emit(tileHoverEvent, {
3857
+ tileId: tile.id,
3858
+ x: tile.x,
3859
+ z: tile.z ?? tile.y ?? 0,
3860
+ type: tile.type
3861
+ });
3862
+ }
3863
+ } else {
3864
+ if (tileLeaveEvent) {
3865
+ emit(tileLeaveEvent, {});
3866
+ }
3867
+ }
3868
+ optionsRef.current.onTileHover?.(tile, event);
3869
+ },
3870
+ [tileHoverEvent, tileLeaveEvent, emit]
3871
+ );
3872
+ const handleUnitAnimation = React113.useCallback(
3873
+ (unitId, state) => {
3874
+ if (unitAnimationEvent) {
3875
+ emit(unitAnimationEvent, {
3876
+ unitId,
3877
+ state,
3878
+ timestamp: Date.now()
3879
+ });
3880
+ }
3881
+ optionsRef.current.onUnitAnimation?.(unitId, state);
3882
+ },
3883
+ [unitAnimationEvent, emit]
3884
+ );
3885
+ const handleCameraChange = React113.useCallback(
3886
+ (position) => {
3887
+ if (cameraChangeEvent) {
3888
+ emit(cameraChangeEvent, {
3889
+ position,
3890
+ timestamp: Date.now()
3891
+ });
3892
+ }
3893
+ },
3894
+ [cameraChangeEvent, emit]
3895
+ );
3896
+ return {
3897
+ handleTileClick,
3898
+ handleUnitClick,
3899
+ handleFeatureClick,
3900
+ handleCanvasClick,
3901
+ handleTileHover,
3902
+ handleUnitAnimation,
3903
+ handleCameraChange
3904
+ };
3905
+ }
3906
+ function detectAssetRoot3(modelUrl) {
3907
+ const idx = modelUrl.indexOf("/3d/");
3908
+ if (idx !== -1) {
3909
+ return modelUrl.substring(0, idx + 4);
3910
+ }
3911
+ return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
3912
+ }
3913
+ function useGLTFModel2(url, resourceBasePath) {
3914
+ const [state, setState] = React113.useState({
3915
+ model: null,
3916
+ isLoading: false,
3917
+ error: null
3918
+ });
3919
+ React113.useEffect(() => {
3920
+ if (!url) {
3921
+ setState({ model: null, isLoading: false, error: null });
3922
+ return;
3923
+ }
3924
+ console.log("[ModelLoader] Loading:", url);
3925
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
3926
+ const assetRoot = resourceBasePath || detectAssetRoot3(url);
3927
+ const loader = new GLTFLoader.GLTFLoader();
3928
+ loader.setResourcePath(assetRoot);
3929
+ loader.load(
3930
+ url,
3931
+ (gltf) => {
3932
+ console.log("[ModelLoader] Loaded:", url);
3933
+ setState({
3934
+ model: gltf.scene,
3935
+ isLoading: false,
3936
+ error: null
3937
+ });
3938
+ },
3939
+ void 0,
3940
+ (err) => {
3941
+ const errorMsg = err instanceof Error ? err.message : String(err);
3942
+ console.warn("[ModelLoader] Failed:", url, errorMsg);
3943
+ setState({
3944
+ model: null,
3945
+ isLoading: false,
3946
+ error: err instanceof Error ? err : new Error(String(err))
3947
+ });
3948
+ }
3949
+ );
3950
+ }, [url, resourceBasePath]);
3951
+ return state;
3952
+ }
3953
+ function ModelLoader({
3954
+ url,
3955
+ position = [0, 0, 0],
3956
+ scale = 1,
3957
+ rotation = [0, 0, 0],
3958
+ isSelected = false,
3959
+ isHovered = false,
3960
+ onClick,
3961
+ onHover,
3962
+ fallbackGeometry = "box",
3963
+ castShadow = true,
3964
+ receiveShadow = true,
3965
+ resourceBasePath
3966
+ }) {
3967
+ const { model: loadedModel, isLoading, error } = useGLTFModel2(url, resourceBasePath);
3968
+ const model = React113.useMemo(() => {
3969
+ if (!loadedModel) return null;
3970
+ const cloned = loadedModel.clone();
3971
+ cloned.traverse((child) => {
3972
+ if (child instanceof THREE__namespace.Mesh) {
3973
+ child.castShadow = castShadow;
3974
+ child.receiveShadow = receiveShadow;
3975
+ }
3976
+ });
3977
+ return cloned;
3978
+ }, [loadedModel, castShadow, receiveShadow]);
3979
+ const scaleArray = React113.useMemo(() => {
3980
+ if (typeof scale === "number") {
3981
+ return [scale, scale, scale];
3982
+ }
3983
+ return scale;
3984
+ }, [scale]);
3985
+ const rotationRad = React113.useMemo(() => {
3986
+ return [
3987
+ rotation[0] * Math.PI / 180,
3988
+ rotation[1] * Math.PI / 180,
3989
+ rotation[2] * Math.PI / 180
3990
+ ];
3991
+ }, [rotation]);
3992
+ if (isLoading) {
3993
+ return /* @__PURE__ */ jsxRuntime.jsx("group", { position, children: /* @__PURE__ */ jsxRuntime.jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
3994
+ /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
3995
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
3996
+ ] }) });
3997
+ }
3998
+ if (error || !model) {
3999
+ if (fallbackGeometry === "none") {
4000
+ return /* @__PURE__ */ jsxRuntime.jsx("group", { position });
4001
+ }
4002
+ const fallbackProps = {
4003
+ onClick,
4004
+ onPointerOver: () => onHover?.(true),
4005
+ onPointerOut: () => onHover?.(false)
4006
+ };
4007
+ return /* @__PURE__ */ jsxRuntime.jsxs("group", { position, children: [
4008
+ (isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
4009
+ /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
4010
+ /* @__PURE__ */ jsxRuntime.jsx(
4011
+ "meshBasicMaterial",
4012
+ {
4013
+ color: isSelected ? 16755200 : 16777215,
4014
+ transparent: true,
4015
+ opacity: 0.5
4016
+ }
4017
+ )
4018
+ ] }),
4019
+ fallbackGeometry === "box" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
4020
+ /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
4021
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
4022
+ ] }),
4023
+ fallbackGeometry === "sphere" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
4024
+ /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.4, 16, 16] }),
4025
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
4026
+ ] }),
4027
+ fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
4028
+ /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
4029
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
4030
+ ] })
4031
+ ] });
4032
+ }
4033
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4034
+ "group",
4035
+ {
4036
+ position,
4037
+ rotation: rotationRad,
4038
+ onClick,
4039
+ onPointerOver: () => onHover?.(true),
4040
+ onPointerOut: () => onHover?.(false),
4041
+ children: [
4042
+ (isSelected || isHovered) && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
4043
+ /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
4044
+ /* @__PURE__ */ jsxRuntime.jsx(
4045
+ "meshBasicMaterial",
4046
+ {
4047
+ color: isSelected ? 16755200 : 16777215,
4048
+ transparent: true,
4049
+ opacity: 0.5
4050
+ }
4051
+ )
4052
+ ] }),
4053
+ /* @__PURE__ */ jsxRuntime.jsx("primitive", { object: model, scale: scaleArray })
4054
+ ]
4055
+ }
4056
+ );
4057
+ }
4058
+ var DEFAULT_GRID_CONFIG = {
4059
+ cellSize: 1,
4060
+ offsetX: 0,
4061
+ offsetZ: 0
4062
+ };
4063
+ function CameraController({
4064
+ onCameraChange
4065
+ }) {
4066
+ const { camera } = fiber.useThree();
4067
+ React113.useEffect(() => {
4068
+ if (onCameraChange) {
4069
+ onCameraChange({
4070
+ x: camera.position.x,
4071
+ y: camera.position.y,
4072
+ z: camera.position.z
4073
+ });
4074
+ }
4075
+ }, [camera.position, onCameraChange]);
4076
+ return null;
4077
+ }
4078
+ var GameCanvas3D = React113.forwardRef(
4079
+ ({
4080
+ tiles = [],
4081
+ units = [],
4082
+ features = [],
4083
+ events: events2 = [],
4084
+ orientation = "standard",
4085
+ cameraMode = "isometric",
4086
+ showGrid = true,
4087
+ showCoordinates = false,
4088
+ showTileInfo = false,
4089
+ overlay = "default",
4090
+ shadows = true,
4091
+ backgroundColor = "#1a1a2e",
4092
+ onTileClick,
4093
+ onUnitClick,
4094
+ onFeatureClick,
4095
+ onCanvasClick,
4096
+ onTileHover,
4097
+ onUnitAnimation,
4098
+ assetLoader: customAssetLoader,
4099
+ tileRenderer: CustomTileRenderer,
4100
+ unitRenderer: CustomUnitRenderer,
4101
+ featureRenderer: CustomFeatureRenderer,
4102
+ className,
4103
+ isLoading: externalLoading,
4104
+ error: externalError,
4105
+ entity,
4106
+ preloadAssets = [],
4107
+ tileClickEvent,
4108
+ unitClickEvent,
4109
+ featureClickEvent,
4110
+ canvasClickEvent,
4111
+ tileHoverEvent,
4112
+ tileLeaveEvent,
4113
+ unitAnimationEvent,
4114
+ cameraChangeEvent,
4115
+ loadingMessage = "Loading 3D Scene...",
4116
+ useInstancing = true,
4117
+ validMoves = [],
4118
+ attackTargets = [],
4119
+ selectedTileIds = [],
4120
+ selectedUnitId = null,
4121
+ children
4122
+ }, ref) => {
4123
+ const containerRef = React113.useRef(null);
4124
+ const controlsRef = React113.useRef(null);
4125
+ const [hoveredTile, setHoveredTile] = React113.useState(null);
4126
+ const [internalError, setInternalError] = React113.useState(null);
4127
+ const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
4128
+ preloadUrls: preloadAssets,
4129
+ loader: customAssetLoader
4130
+ });
4131
+ const eventHandlers = useGameCanvas3DEvents({
4132
+ tileClickEvent,
4133
+ unitClickEvent,
4134
+ featureClickEvent,
4135
+ canvasClickEvent,
4136
+ tileHoverEvent,
4137
+ tileLeaveEvent,
4138
+ unitAnimationEvent,
4139
+ cameraChangeEvent,
4140
+ onTileClick,
4141
+ onUnitClick,
4142
+ onFeatureClick,
4143
+ onCanvasClick,
4144
+ onTileHover,
4145
+ onUnitAnimation
4146
+ });
4147
+ const gridBounds = React113.useMemo(() => {
4148
+ if (tiles.length === 0) {
4149
+ return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
4150
+ }
4151
+ const xs = tiles.map((t) => t.x);
4152
+ const zs = tiles.map((t) => t.z || t.y || 0);
4153
+ return {
4154
+ minX: Math.min(...xs),
4155
+ maxX: Math.max(...xs),
4156
+ minZ: Math.min(...zs),
4157
+ maxZ: Math.max(...zs)
4158
+ };
4159
+ }, [tiles]);
4160
+ const cameraTarget = React113.useMemo(() => {
4161
+ return [
4162
+ (gridBounds.minX + gridBounds.maxX) / 2,
4163
+ 0,
4164
+ (gridBounds.minZ + gridBounds.maxZ) / 2
4165
+ ];
4166
+ }, [gridBounds]);
4167
+ const gridConfig = React113.useMemo(
4168
+ () => ({
4169
+ ...DEFAULT_GRID_CONFIG,
4170
+ offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
4171
+ offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
4172
+ }),
4173
+ [gridBounds]
4174
+ );
4175
+ const gridToWorld = React113.useCallback(
4176
+ (x, z, y = 0) => {
4177
+ const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
4178
+ const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
4179
+ return [worldX, y * gridConfig.cellSize, worldZ];
4180
+ },
4181
+ [gridBounds, gridConfig]
4182
+ );
4183
+ React113.useImperativeHandle(ref, () => ({
4184
+ getCameraPosition: () => {
4185
+ if (controlsRef.current) {
4186
+ const pos = controlsRef.current.object.position;
4187
+ return new THREE__namespace.Vector3(pos.x, pos.y, pos.z);
4188
+ }
4189
+ return null;
4190
+ },
4191
+ setCameraPosition: (x, y, z) => {
4192
+ if (controlsRef.current) {
4193
+ controlsRef.current.object.position.set(x, y, z);
4194
+ controlsRef.current.update();
4195
+ }
4196
+ },
4197
+ lookAt: (x, y, z) => {
4198
+ if (controlsRef.current) {
4199
+ controlsRef.current.target.set(x, y, z);
4200
+ controlsRef.current.update();
4201
+ }
4202
+ },
4203
+ resetCamera: () => {
4204
+ if (controlsRef.current) {
4205
+ controlsRef.current.reset();
4206
+ }
4207
+ },
4208
+ screenshot: () => {
4209
+ const canvas = containerRef.current?.querySelector("canvas");
4210
+ if (canvas) {
4211
+ return canvas.toDataURL("image/png");
4212
+ }
4213
+ return null;
4214
+ },
4215
+ export: () => ({
4216
+ tiles,
4217
+ units,
4218
+ features
4219
+ })
4220
+ }));
4221
+ const handleTileClick = React113.useCallback(
4222
+ (tile, event) => {
4223
+ eventHandlers.handleTileClick(tile, event);
4224
+ },
4225
+ [eventHandlers]
4226
+ );
4227
+ const handleUnitClick = React113.useCallback(
4228
+ (unit, event) => {
4229
+ eventHandlers.handleUnitClick(unit, event);
4230
+ },
4231
+ [eventHandlers]
4232
+ );
4233
+ const handleFeatureClick = React113.useCallback(
4234
+ (feature, event) => {
4235
+ if (event) {
4236
+ eventHandlers.handleFeatureClick(feature, event);
4237
+ }
4238
+ },
4239
+ [eventHandlers]
4240
+ );
4241
+ const handleTileHover = React113.useCallback(
4242
+ (tile, event) => {
4243
+ setHoveredTile(tile);
4244
+ if (event) {
4245
+ eventHandlers.handleTileHover(tile, event);
4246
+ }
4247
+ },
4248
+ [eventHandlers]
4249
+ );
4250
+ const cameraConfig = React113.useMemo(() => {
4251
+ const size = Math.max(
4252
+ gridBounds.maxX - gridBounds.minX,
4253
+ gridBounds.maxZ - gridBounds.minZ
4254
+ );
4255
+ const distance = size * 1.5;
4256
+ switch (cameraMode) {
4257
+ case "isometric":
4258
+ return {
4259
+ position: [distance, distance * 0.8, distance],
4260
+ fov: 45
4261
+ };
4262
+ case "top-down":
4263
+ return {
4264
+ position: [0, distance * 2, 0],
4265
+ fov: 45
4266
+ };
4267
+ case "perspective":
4268
+ default:
4269
+ return {
4270
+ position: [distance, distance, distance],
4271
+ fov: 45
4272
+ };
4273
+ }
4274
+ }, [cameraMode, gridBounds]);
4275
+ const DefaultTileRenderer = React113.useCallback(
4276
+ ({ tile, position }) => {
4277
+ const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
4278
+ const isHovered = hoveredTile?.id === tile.id;
4279
+ const isValidMove = validMoves.some(
4280
+ (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
4281
+ );
4282
+ const isAttackTarget = attackTargets.some(
4283
+ (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
4284
+ );
4285
+ let color = 8421504;
4286
+ if (tile.type === "water") color = 4491468;
4287
+ else if (tile.type === "grass") color = 4500036;
4288
+ else if (tile.type === "sand") color = 14535816;
4289
+ else if (tile.type === "rock") color = 8947848;
4290
+ else if (tile.type === "snow") color = 15658734;
4291
+ let emissive = 0;
4292
+ if (isSelected) emissive = 4473924;
4293
+ else if (isAttackTarget) emissive = 4456448;
4294
+ else if (isValidMove) emissive = 17408;
4295
+ else if (isHovered) emissive = 2236962;
4296
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4297
+ "mesh",
4298
+ {
4299
+ position,
4300
+ onClick: (e) => handleTileClick(tile, e),
4301
+ onPointerEnter: (e) => handleTileHover(tile, e),
4302
+ onPointerLeave: (e) => handleTileHover(null, e),
4303
+ userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
4304
+ children: [
4305
+ /* @__PURE__ */ jsxRuntime.jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
4306
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color, emissive })
4307
+ ]
4308
+ }
4309
+ );
4310
+ },
4311
+ [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
4312
+ );
4313
+ const DefaultUnitRenderer = React113.useCallback(
4314
+ ({ unit, position }) => {
4315
+ const isSelected = selectedUnitId === unit.id;
4316
+ const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
4317
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4318
+ "group",
4319
+ {
4320
+ position,
4321
+ onClick: (e) => handleUnitClick(unit, e),
4322
+ userData: { type: "unit", unitId: unit.id },
4323
+ children: [
4324
+ isSelected && /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
4325
+ /* @__PURE__ */ jsxRuntime.jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
4326
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
4327
+ ] }),
4328
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.3, 0], children: [
4329
+ /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
4330
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
4331
+ ] }),
4332
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.6, 0], children: [
4333
+ /* @__PURE__ */ jsxRuntime.jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
4334
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
4335
+ ] }),
4336
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
4337
+ /* @__PURE__ */ jsxRuntime.jsx("sphereGeometry", { args: [0.12, 8, 8] }),
4338
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color })
4339
+ ] }),
4340
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("group", { position: [0, 1.2, 0], children: [
4341
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [-0.25, 0, 0], children: [
4342
+ /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5, 0.05] }),
4343
+ /* @__PURE__ */ jsxRuntime.jsx("meshBasicMaterial", { color: 3355443 })
4344
+ ] }),
4345
+ /* @__PURE__ */ jsxRuntime.jsxs(
4346
+ "mesh",
4347
+ {
4348
+ position: [
4349
+ -0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
4350
+ 0,
4351
+ 0.01
4352
+ ],
4353
+ children: [
4354
+ /* @__PURE__ */ jsxRuntime.jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
4355
+ /* @__PURE__ */ jsxRuntime.jsx(
4356
+ "meshBasicMaterial",
4357
+ {
4358
+ color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
4359
+ }
4360
+ )
4361
+ ]
4362
+ }
4363
+ )
4364
+ ] })
4365
+ ]
4366
+ }
4367
+ );
4368
+ },
4369
+ [selectedUnitId, handleUnitClick]
4370
+ );
4371
+ const DefaultFeatureRenderer = React113.useCallback(
4372
+ ({
4373
+ feature,
4374
+ position
4375
+ }) => {
4376
+ if (feature.assetUrl) {
4377
+ return /* @__PURE__ */ jsxRuntime.jsx(
4378
+ ModelLoader,
4379
+ {
4380
+ url: feature.assetUrl,
4381
+ position,
4382
+ scale: 0.5,
4383
+ rotation: [0, feature.rotation ?? 0, 0],
4384
+ onClick: () => handleFeatureClick(feature, null),
4385
+ fallbackGeometry: "box"
4386
+ },
4387
+ feature.id
4388
+ );
4389
+ }
4390
+ if (feature.type === "tree") {
4391
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4392
+ "group",
4393
+ {
4394
+ position,
4395
+ onClick: (e) => handleFeatureClick(feature, e),
4396
+ userData: { type: "feature", featureId: feature.id },
4397
+ children: [
4398
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.4, 0], children: [
4399
+ /* @__PURE__ */ jsxRuntime.jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
4400
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 9127187 })
4401
+ ] }),
4402
+ /* @__PURE__ */ jsxRuntime.jsxs("mesh", { position: [0, 0.9, 0], children: [
4403
+ /* @__PURE__ */ jsxRuntime.jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
4404
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 2263842 })
4405
+ ] })
4406
+ ]
4407
+ }
4408
+ );
4409
+ }
4410
+ if (feature.type === "rock") {
4411
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4412
+ "mesh",
4413
+ {
4414
+ position: [position[0], position[1] + 0.3, position[2]],
4415
+ onClick: (e) => handleFeatureClick(feature, e),
4416
+ userData: { type: "feature", featureId: feature.id },
4417
+ children: [
4418
+ /* @__PURE__ */ jsxRuntime.jsx("dodecahedronGeometry", { args: [0.3, 0] }),
4419
+ /* @__PURE__ */ jsxRuntime.jsx("meshStandardMaterial", { color: 8421504 })
4420
+ ]
4421
+ }
4422
+ );
4423
+ }
4424
+ return null;
4425
+ },
4426
+ [handleFeatureClick]
4427
+ );
4428
+ if (externalLoading || assetsLoading && preloadAssets.length > 0) {
4429
+ return /* @__PURE__ */ jsxRuntime.jsx(
4430
+ Canvas3DLoadingState,
4431
+ {
4432
+ progress,
4433
+ loaded,
4434
+ total,
4435
+ message: loadingMessage,
4436
+ className
4437
+ }
4438
+ );
4439
+ }
4440
+ const displayError = externalError || internalError;
4441
+ if (displayError) {
4442
+ return /* @__PURE__ */ jsxRuntime.jsx(Canvas3DErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "game-canvas-3d game-canvas-3d--error", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__error", children: [
4443
+ "Error: ",
4444
+ displayError
4445
+ ] }) }) });
4446
+ }
4447
+ return /* @__PURE__ */ jsxRuntime.jsx(
4448
+ Canvas3DErrorBoundary,
4449
+ {
4450
+ onError: (err) => setInternalError(err.message),
4451
+ onReset: () => setInternalError(null),
4452
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
4453
+ "div",
4454
+ {
4455
+ ref: containerRef,
4456
+ className: `game-canvas-3d ${className || ""}`,
4457
+ "data-orientation": orientation,
4458
+ "data-camera-mode": cameraMode,
4459
+ "data-overlay": overlay,
4460
+ children: [
4461
+ /* @__PURE__ */ jsxRuntime.jsxs(
4462
+ fiber.Canvas,
4463
+ {
4464
+ shadows,
4465
+ camera: {
4466
+ position: cameraConfig.position,
4467
+ fov: cameraConfig.fov,
4468
+ near: 0.1,
4469
+ far: 1e3
4470
+ },
4471
+ style: { background: backgroundColor },
4472
+ onClick: (e) => {
4473
+ if (e.target === e.currentTarget) {
4474
+ eventHandlers.handleCanvasClick(e);
4475
+ }
4476
+ },
4477
+ children: [
4478
+ /* @__PURE__ */ jsxRuntime.jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
4479
+ /* @__PURE__ */ jsxRuntime.jsx("ambientLight", { intensity: 0.6 }),
4480
+ /* @__PURE__ */ jsxRuntime.jsx(
4481
+ "directionalLight",
4482
+ {
4483
+ position: [10, 20, 10],
4484
+ intensity: 0.8,
4485
+ castShadow: shadows,
4486
+ "shadow-mapSize": [2048, 2048]
4487
+ }
4488
+ ),
4489
+ /* @__PURE__ */ jsxRuntime.jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
4490
+ showGrid && /* @__PURE__ */ jsxRuntime.jsx(
4491
+ drei.Grid,
4492
+ {
4493
+ args: [
4494
+ Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
4495
+ Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
4496
+ ],
4497
+ position: [
4498
+ (gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
4499
+ 0,
4500
+ (gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
4501
+ ],
4502
+ cellSize: 1,
4503
+ cellThickness: 1,
4504
+ cellColor: "#444444",
4505
+ sectionSize: 5,
4506
+ sectionThickness: 1.5,
4507
+ sectionColor: "#666666",
4508
+ fadeDistance: 50,
4509
+ fadeStrength: 1
4510
+ }
4511
+ ),
4512
+ tiles.map((tile, index) => {
4513
+ const position = gridToWorld(
4514
+ tile.x,
4515
+ tile.z ?? tile.y ?? 0,
4516
+ tile.elevation ?? 0
4517
+ );
4518
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
4519
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
4520
+ }),
4521
+ features.map((feature, index) => {
4522
+ const position = gridToWorld(
4523
+ feature.x,
4524
+ feature.z ?? feature.y ?? 0,
4525
+ (feature.elevation ?? 0) + 0.5
4526
+ );
4527
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
4528
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
4529
+ }),
4530
+ units.map((unit) => {
4531
+ const position = gridToWorld(
4532
+ unit.x ?? 0,
4533
+ unit.z ?? unit.y ?? 0,
4534
+ (unit.elevation ?? 0) + 0.5
4535
+ );
4536
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
4537
+ return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { unit, position }, unit.id);
4538
+ }),
4539
+ children,
4540
+ /* @__PURE__ */ jsxRuntime.jsx(
4541
+ drei.OrbitControls,
4542
+ {
4543
+ ref: controlsRef,
4544
+ target: cameraTarget,
4545
+ enableDamping: true,
4546
+ dampingFactor: 0.05,
4547
+ minDistance: 2,
4548
+ maxDistance: 100,
4549
+ maxPolarAngle: Math.PI / 2 - 0.1
4550
+ }
4551
+ )
4552
+ ]
4553
+ }
4554
+ ),
4555
+ showCoordinates && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__coordinates", children: [
4556
+ "X: ",
4557
+ hoveredTile.x,
4558
+ ", Z: ",
4559
+ hoveredTile.z ?? hoveredTile.y ?? 0
4560
+ ] }),
4561
+ showTileInfo && hoveredTile && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "game-canvas-3d__tile-info", children: [
4562
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
4563
+ hoveredTile.terrain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
4564
+ ] })
4565
+ ]
4566
+ }
4567
+ )
4568
+ }
4569
+ );
4570
+ }
4571
+ );
4572
+ GameCanvas3D.displayName = "GameCanvas3D";
4573
+ var SuspenseConfigContext = React113.createContext({ enabled: false });
4574
+ React113.createContext(false);
4575
+ function SuspenseConfigProvider({
4576
+ config,
4577
+ children
4578
+ }) {
4579
+ return React113__namespace.default.createElement(
4580
+ SuspenseConfigContext.Provider,
4581
+ { value: config },
4582
+ children
4583
+ );
4584
+ }
4585
+ SuspenseConfigProvider.displayName = "SuspenseConfigProvider";
4586
+ var DISPATCH_SUFFIX = ":DISPATCH";
4587
+ var SUCCESS_SUFFIX = ":SUCCESS";
4588
+ var ERROR_SUFFIX = ":ERROR";
4589
+ function parseLifecycleEvent(type) {
4590
+ if (type.endsWith(DISPATCH_SUFFIX)) {
4591
+ const traitName = type.slice(0, -DISPATCH_SUFFIX.length);
4592
+ if (traitName) return { kind: "dispatch", traitName };
4593
+ } else if (type.endsWith(SUCCESS_SUFFIX)) {
4594
+ const rest = type.slice(0, -SUCCESS_SUFFIX.length);
4595
+ const colonIdx = rest.indexOf(":");
4596
+ if (colonIdx > 0) {
4597
+ return {
4598
+ kind: "success",
4599
+ traitName: rest.slice(0, colonIdx),
4600
+ event: rest.slice(colonIdx + 1)
4601
+ };
4602
+ }
4603
+ } else if (type.endsWith(ERROR_SUFFIX)) {
4604
+ const rest = type.slice(0, -ERROR_SUFFIX.length);
4605
+ const colonIdx = rest.indexOf(":");
4606
+ if (colonIdx > 0) {
4607
+ return {
4608
+ kind: "error",
4609
+ traitName: rest.slice(0, colonIdx),
4610
+ event: rest.slice(colonIdx + 1)
4611
+ };
4612
+ }
4613
+ }
4614
+ return null;
4615
+ }
4616
+ function VerificationProvider({
4617
+ children,
4618
+ enabled,
4619
+ runtimeManager,
4620
+ traitStateGetter
4621
+ }) {
4622
+ const isEnabled = enabled ?? (typeof process !== "undefined" && process.env?.NODE_ENV !== "production");
4623
+ const eventBus = useEventBus();
4624
+ const pendingRef = React113.useRef(/* @__PURE__ */ new Map());
4625
+ React113.useEffect(() => {
4626
+ if (!isEnabled) return;
4627
+ if (!eventBus.onAny) return;
4628
+ const unsub = eventBus.onAny((evt) => {
4629
+ const parsed = parseLifecycleEvent(evt.type);
4630
+ if (!parsed) return;
4631
+ const payload = evt.payload ?? {};
4632
+ if (parsed.kind === "dispatch") {
4633
+ const key = `${parsed.traitName}:${String(payload["event"] ?? "")}`;
4634
+ pendingRef.current.set(key, {
4635
+ traitName: parsed.traitName,
4636
+ event: String(payload["event"] ?? ""),
4637
+ from: payload["currentState"],
4638
+ timestamp: evt.timestamp
4639
+ });
4640
+ } else if (parsed.kind === "success" && parsed.event) {
4641
+ const key = `${parsed.traitName}:${parsed.event}`;
4642
+ const pending = pendingRef.current.get(key);
4643
+ pendingRef.current.delete(key);
4644
+ const newState = payload["newState"] ?? payload["state"] ?? "unknown";
4645
+ const effects = Array.isArray(payload["clientEffects"]) ? payload["clientEffects"].map((e) => ({
4646
+ type: String(e["type"] ?? "unknown"),
4647
+ args: Array.isArray(e["args"]) ? e["args"] : [],
4648
+ status: "executed"
4649
+ })) : [];
4650
+ recordTransition({
4651
+ traitName: parsed.traitName,
4652
+ from: pending?.from ?? "unknown",
4653
+ to: newState,
4654
+ event: parsed.event,
4655
+ effects,
4656
+ timestamp: Date.now()
4657
+ });
4658
+ } else if (parsed.kind === "error" && parsed.event) {
4659
+ const key = `${parsed.traitName}:${parsed.event}`;
4660
+ const pending = pendingRef.current.get(key);
4661
+ pendingRef.current.delete(key);
4662
+ const errorMsg = payload["error"] ?? "Unknown error";
4663
+ recordTransition({
4664
+ traitName: parsed.traitName,
4665
+ from: pending?.from ?? "unknown",
4666
+ to: pending?.from ?? "unknown",
4667
+ // state didn't change on error
4668
+ event: parsed.event,
4669
+ effects: [{
4670
+ type: "server-call",
4671
+ args: [],
4672
+ status: "failed",
4673
+ error: errorMsg
4674
+ }],
4675
+ timestamp: Date.now()
4676
+ });
4677
+ }
4678
+ });
4679
+ registerCheck(
4680
+ "verification-provider",
4681
+ "VerificationProvider active (compiled path)",
4682
+ "pass"
4683
+ );
4684
+ return unsub;
4685
+ }, [isEnabled, eventBus]);
4686
+ React113.useEffect(() => {
4687
+ if (!isEnabled) return;
4688
+ if (!runtimeManager) return;
4689
+ runtimeManager.setObserver({
4690
+ onTransition(trace) {
4691
+ recordTransition({
4692
+ traitName: trace.traitName,
4693
+ from: trace.from,
4694
+ to: trace.to,
4695
+ event: trace.event,
4696
+ guardResult: trace.guardResult,
4697
+ effects: trace.effects,
4698
+ timestamp: Date.now()
4699
+ });
4700
+ }
4701
+ });
4702
+ registerCheck(
4703
+ "verification-provider",
4704
+ "VerificationProvider active (runtime path)",
4705
+ "pass"
4706
+ );
4707
+ }, [isEnabled, runtimeManager]);
4708
+ React113.useEffect(() => {
4709
+ if (!isEnabled) return;
4710
+ bindEventBus(eventBus);
4711
+ }, [isEnabled, eventBus]);
4712
+ React113.useEffect(() => {
4713
+ if (!isEnabled) return;
4714
+ if (traitStateGetter) {
4715
+ bindTraitStateGetter(traitStateGetter);
4716
+ } else if (runtimeManager?.getState) {
4717
+ const mgr = runtimeManager;
4718
+ bindTraitStateGetter((traitName) => mgr.getState(traitName));
4719
+ }
4720
+ }, [isEnabled, traitStateGetter, runtimeManager]);
4721
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
4722
+ }
4723
+ VerificationProvider.displayName = "VerificationProvider";
4724
+ function FetchedDataBridge({ children }) {
4725
+ const fetchedData = useFetchedData();
4726
+ const adapter = React113.useMemo(() => ({
4727
+ getData: (entity) => fetchedData.getData(entity),
4728
+ getById: (entity, id) => fetchedData.getById(entity, id),
4729
+ isLoading: fetchedData.loading,
4730
+ error: fetchedData.error
4731
+ }), [fetchedData.getData, fetchedData.getById, fetchedData.loading, fetchedData.error]);
4732
+ return /* @__PURE__ */ jsxRuntime.jsx(EntityDataProvider, { adapter, children });
4733
+ }
4734
+ function OrbitalProvider({
4735
+ children,
4736
+ themes,
4737
+ defaultTheme = "wireframe",
4738
+ defaultMode = "system",
4739
+ targetRef,
4740
+ skipTheme = false,
4741
+ debug: debug2 = false,
4742
+ initialData,
4743
+ suspense = false,
4744
+ verification
4745
+ }) {
4746
+ const suspenseConfig = React113.useMemo(
4747
+ () => ({ enabled: suspense }),
4748
+ [suspense]
4749
+ );
4750
+ const inner = /* @__PURE__ */ jsxRuntime.jsx(FetchedDataProvider, { initialData, children: /* @__PURE__ */ jsxRuntime.jsx(FetchedDataBridge, { children: /* @__PURE__ */ jsxRuntime.jsx(EventBusProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(VerificationProvider, { enabled: verification, children: /* @__PURE__ */ jsxRuntime.jsx(SelectionProvider, { debug: debug2, children: /* @__PURE__ */ jsxRuntime.jsx(SuspenseConfigProvider, { config: suspenseConfig, children }) }) }) }) }) });
4751
+ if (skipTheme) {
4752
+ return inner;
4753
+ }
4754
+ return /* @__PURE__ */ jsxRuntime.jsx(
4755
+ ThemeProvider,
4756
+ {
4757
+ themes,
4758
+ defaultTheme,
4759
+ defaultMode,
4760
+ targetRef,
4761
+ children: inner
4762
+ }
4763
+ );
4764
+ }
4765
+ OrbitalProvider.displayName = "OrbitalProvider";
4766
+ var OfflineModeContext = React113.createContext(null);
4767
+ function OfflineModeProvider({
4768
+ children,
4769
+ ...executorOptions
4770
+ }) {
4771
+ const [forceOffline, setForceOffline] = React113.useState(false);
4772
+ const executor = useOfflineExecutor(executorOptions);
4773
+ const effectivelyOffline = executor.isOffline || forceOffline;
4774
+ const contextValue = React113.useMemo(
4775
+ () => ({
4776
+ ...executor,
4777
+ forceOffline,
4778
+ setForceOffline,
4779
+ effectivelyOffline
4780
+ }),
4781
+ [executor, forceOffline, effectivelyOffline]
4782
+ );
4783
+ return /* @__PURE__ */ jsxRuntime.jsx(OfflineModeContext.Provider, { value: contextValue, children });
4784
+ }
4785
+ function useOfflineMode() {
4786
+ const context = React113.useContext(OfflineModeContext);
4787
+ if (!context) {
4788
+ throw new Error("useOfflineMode must be used within OfflineModeProvider");
4789
+ }
4790
+ return context;
4791
+ }
4792
+ function useOptionalOfflineMode() {
4793
+ return React113.useContext(OfflineModeContext);
4794
+ }
4795
+
4796
+ exports.EventBusContext = EventBusContext;
4797
+ exports.EventBusProvider = EventBusProvider;
4798
+ exports.FetchedDataContext = FetchedDataContext;
4799
+ exports.FetchedDataProvider = FetchedDataProvider;
4800
+ exports.OfflineModeProvider = OfflineModeProvider;
4801
+ exports.OrbitalProvider = OrbitalProvider;
4802
+ exports.SelectionContext = SelectionContext;
4803
+ exports.SelectionProvider = SelectionProvider;
4804
+ exports.VerificationProvider = VerificationProvider;
4805
+ exports.useFetchedData = useFetchedData;
4806
+ exports.useFetchedDataContext = useFetchedDataContext;
4807
+ exports.useFetchedEntity = useFetchedEntity;
4808
+ exports.useOfflineMode = useOfflineMode;
4809
+ exports.useOptionalOfflineMode = useOptionalOfflineMode;
4810
+ exports.useSelection = useSelection;
4811
+ exports.useSelectionOptional = useSelectionOptional;