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