@almadar/ui 2.15.7 → 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 (127) 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-K43H3ZDY.js → components/index.cjs} +24780 -16651
  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/UISlotRenderer.d.ts +1 -0
  76. package/dist/components/organisms/game/three/index.cjs +2525 -0
  77. package/dist/components/organisms/game/three/index.js +1795 -50
  78. package/dist/components/organisms/index.d.ts +9 -0
  79. package/dist/components/organisms/marketing-types.d.ts +87 -0
  80. package/dist/components/templates/AboutPageTemplate.d.ts +26 -0
  81. package/dist/components/templates/DashboardLayout.d.ts +2 -1
  82. package/dist/components/templates/FeatureDetailPageTemplate.d.ts +27 -0
  83. package/dist/components/templates/LandingPageTemplate.d.ts +31 -0
  84. package/dist/components/templates/PricingPageTemplate.d.ts +26 -0
  85. package/dist/components/templates/index.d.ts +4 -0
  86. package/dist/context/index.cjs +550 -0
  87. package/dist/context/index.js +420 -6
  88. package/dist/docs/index.cjs +4015 -0
  89. package/dist/docs/index.d.cts +412 -0
  90. package/dist/docs/index.d.ts +29 -0
  91. package/dist/docs/index.js +3977 -0
  92. package/dist/hooks/index.cjs +2606 -0
  93. package/dist/hooks/index.js +2535 -8
  94. package/dist/illustrations/index.cjs +3004 -0
  95. package/dist/illustrations/index.d.cts +261 -0
  96. package/dist/illustrations/index.d.ts +35 -0
  97. package/dist/illustrations/index.js +2971 -0
  98. package/dist/{chunk-XL7WB2O5.js → lib/index.cjs} +454 -274
  99. package/dist/lib/index.js +1407 -3
  100. package/dist/locales/index.cjs +340 -0
  101. package/dist/locales/index.js +105 -2
  102. package/dist/marketing/index.cjs +4683 -0
  103. package/dist/marketing/index.d.cts +831 -0
  104. package/dist/marketing/index.d.ts +62 -0
  105. package/dist/marketing/index.js +4626 -0
  106. package/dist/providers/index.cjs +4811 -0
  107. package/dist/providers/index.js +4765 -11
  108. package/dist/{chunk-K2D5D3WK.js → renderer/index.cjs} +101 -42
  109. package/dist/renderer/index.js +1036 -2
  110. package/dist/runtime/index.cjs +4400 -0
  111. package/dist/runtime/index.js +3615 -19
  112. package/dist/{chunk-N7MVUW4R.js → stores/index.cjs} +24 -1
  113. package/dist/stores/index.js +194 -2
  114. package/dist/tsup.config.d.ts +2 -1
  115. package/package.json +27 -12
  116. package/tailwind-preset.cjs +27 -2
  117. package/themes/index.css +22 -20
  118. package/dist/chunk-3HJHHULT.js +0 -93
  119. package/dist/chunk-3JGAROCW.js +0 -149
  120. package/dist/chunk-4N3BAPDB.js +0 -1667
  121. package/dist/chunk-CDIOHSKG.js +0 -661
  122. package/dist/chunk-DKQN5FVU.js +0 -279
  123. package/dist/chunk-GF6RQBO7.js +0 -375
  124. package/dist/chunk-PKBMQBKP.js +0 -5
  125. package/dist/chunk-QIABKRCN.js +0 -107
  126. package/dist/chunk-SD3KVCY6.js +0 -1465
  127. package/dist/chunk-YXZM3WCF.js +0 -222
@@ -1,22 +1,3574 @@
1
- import '../chunk-SD3KVCY6.js';
2
- import '../chunk-N7MVUW4R.js';
3
- import '../chunk-3HJHHULT.js';
4
- import { useFetchedDataContext } from '../chunk-GF6RQBO7.js';
5
- import '../chunk-K43H3ZDY.js';
6
- import '../chunk-4N3BAPDB.js';
7
- import '../chunk-DKQN5FVU.js';
8
- import '../chunk-CDIOHSKG.js';
9
- import { useEventBus } from '../chunk-YXZM3WCF.js';
10
- import '../chunk-3JGAROCW.js';
11
- import { registerTrait, unregisterTrait, updateTraitState, recordTransition } from '../chunk-XL7WB2O5.js';
12
- import '../chunk-QIABKRCN.js';
13
- import '../chunk-K2D5D3WK.js';
14
- import '../chunk-PKBMQBKP.js';
15
- import { createContext, useMemo, useContext, useState, useRef, useEffect, useCallback } from 'react';
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 '@tanstack/react-query';
5
+ import 'react-dom';
6
+ import '@almadar/ui/context';
7
+ import * as LucideIcons from 'lucide-react';
8
+ import { Loader2, ChevronDown, X, ArrowRight, TrendingDown, TrendingUp, Check, Copy, AlertCircle } from 'lucide-react';
9
+ import { clsx } from 'clsx';
10
+ import { twMerge } from 'tailwind-merge';
11
+ import '@almadar/evaluator';
12
+ import { isEntityAwarePattern } from '@almadar/patterns';
13
+ import 'react-leaflet';
14
+ import L from 'leaflet';
15
+ import 'leaflet/dist/leaflet.css';
16
+ import 'react-router-dom';
17
+ import ReactMarkdown from 'react-markdown';
18
+ import remarkGfm from 'remark-gfm';
19
+ import remarkMath from 'remark-math';
20
+ import rehypeKatex from 'rehype-katex';
21
+ import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/prism';
22
+ import dark from 'react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus';
23
+ import { useThree, useFrame, Canvas } from '@react-three/fiber';
24
+ import { OrbitControls, Grid } from '@react-three/drei';
25
+ import * as THREE from 'three';
26
+ import { GLTFLoader as GLTFLoader$1 } from 'three/examples/jsm/loaders/GLTFLoader';
27
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
28
+ import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
16
29
  import { isCircuitEvent, schemaToIR, getPage, clearSchemaCache as clearSchemaCache$1 } from '@almadar/core';
17
30
  import { StateMachineManager, createContextFromBindings, interpolateValue, EffectExecutor } from '@almadar/runtime';
18
- import { isEntityAwarePattern } from '@almadar/patterns';
19
- import { jsx } from 'react/jsx-runtime';
31
+
32
+ var __defProp = Object.defineProperty;
33
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
34
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
35
+ var EventBusContext = createContext(null);
36
+ function getGlobalEventBus() {
37
+ if (typeof window !== "undefined") {
38
+ return window.__kflowEventBus ?? null;
39
+ }
40
+ return null;
41
+ }
42
+ var fallbackListeners = /* @__PURE__ */ new Map();
43
+ var fallbackAnyListeners = /* @__PURE__ */ new Set();
44
+ var fallbackEventBus = {
45
+ emit: (type, payload) => {
46
+ const event = {
47
+ type,
48
+ payload,
49
+ timestamp: Date.now()
50
+ };
51
+ const handlers = fallbackListeners.get(type);
52
+ if (handlers) {
53
+ handlers.forEach((handler) => {
54
+ try {
55
+ handler(event);
56
+ } catch (error) {
57
+ console.error(`[EventBus] Error in listener for '${type}':`, error);
58
+ }
59
+ });
60
+ }
61
+ fallbackAnyListeners.forEach((handler) => {
62
+ try {
63
+ handler(event);
64
+ } catch (error) {
65
+ console.error(`[EventBus] Error in onAny listener for '${type}':`, error);
66
+ }
67
+ });
68
+ },
69
+ on: (type, listener) => {
70
+ if (!fallbackListeners.has(type)) {
71
+ fallbackListeners.set(type, /* @__PURE__ */ new Set());
72
+ }
73
+ fallbackListeners.get(type).add(listener);
74
+ return () => {
75
+ const handlers = fallbackListeners.get(type);
76
+ if (handlers) {
77
+ handlers.delete(listener);
78
+ if (handlers.size === 0) {
79
+ fallbackListeners.delete(type);
80
+ }
81
+ }
82
+ };
83
+ },
84
+ once: (type, listener) => {
85
+ const wrappedListener = (event) => {
86
+ fallbackListeners.get(type)?.delete(wrappedListener);
87
+ listener(event);
88
+ };
89
+ return fallbackEventBus.on(type, wrappedListener);
90
+ },
91
+ hasListeners: (type) => {
92
+ const handlers = fallbackListeners.get(type);
93
+ return handlers !== void 0 && handlers.size > 0;
94
+ },
95
+ onAny: (listener) => {
96
+ fallbackAnyListeners.add(listener);
97
+ return () => {
98
+ fallbackAnyListeners.delete(listener);
99
+ };
100
+ }
101
+ };
102
+ function useEventBus() {
103
+ const context = useContext(EventBusContext);
104
+ return context ?? getGlobalEventBus() ?? fallbackEventBus;
105
+ }
106
+ function useEmitEvent() {
107
+ const eventBus = useEventBus();
108
+ return useCallback(
109
+ (type, payload) => {
110
+ eventBus.emit(type, payload);
111
+ },
112
+ [eventBus]
113
+ );
114
+ }
115
+ createContext(null);
116
+ createContext(null);
117
+
118
+ // lib/api-client.ts
119
+ typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "/api";
120
+
121
+ // locales/en.json
122
+ var en_default = {
123
+ $meta: { locale: "en", direction: "ltr" },
124
+ "common.save": "Save",
125
+ "common.cancel": "Cancel",
126
+ "common.delete": "Delete",
127
+ "common.close": "Close",
128
+ "common.confirm": "Are you sure?",
129
+ "common.create": "Create",
130
+ "common.edit": "Edit",
131
+ "common.view": "View",
132
+ "common.add": "Add",
133
+ "common.remove": "Remove",
134
+ "common.search": "Search...",
135
+ "common.filter": "Filter",
136
+ "common.actions": "Actions",
137
+ "common.yes": "Yes",
138
+ "common.no": "No",
139
+ "common.selected": "selected",
140
+ "common.ok": "OK",
141
+ "common.done": "Done",
142
+ "common.apply": "Apply",
143
+ "common.reset": "Reset",
144
+ "common.refresh": "Refresh",
145
+ "common.export": "Export",
146
+ "common.import": "Import",
147
+ "common.copy": "Copy",
148
+ "common.settings": "Settings",
149
+ "nav.previous": "Previous",
150
+ "nav.next": "Next",
151
+ "nav.back": "Back",
152
+ "nav.home": "Home",
153
+ "form.submit": "Submit",
154
+ "form.saving": "Saving...",
155
+ "form.required": "This field is required",
156
+ "form.invalidEmail": "Enter a valid email address",
157
+ "form.selectPlaceholder": "Select {{label}}...",
158
+ "form.searchPlaceholder": "Search {{entity}}...",
159
+ "table.empty.title": "No items found",
160
+ "table.empty.description": "No items to display.",
161
+ "table.search.placeholder": "Search...",
162
+ "table.pagination.showing": "Showing {{start}} to {{end}} of {{total}} results",
163
+ "table.pagination.page": "Page {{page}} of {{totalPages}}",
164
+ "table.bulk.selected": "{{count}} selected",
165
+ "table.loading": "Loading...",
166
+ "status.loading": "Loading...",
167
+ "status.scheduled": "Scheduled",
168
+ "status.inProgress": "In Progress",
169
+ "status.completed": "Completed",
170
+ "status.cancelled": "Cancelled",
171
+ "status.pending": "Pending",
172
+ "status.active": "Active",
173
+ "status.inactive": "Inactive",
174
+ "status.draft": "Draft",
175
+ "status.archived": "Archived",
176
+ "error.generic": "Something went wrong",
177
+ "error.retry": "Try again",
178
+ "error.notFound": "Not found",
179
+ "error.loadFailed": "Failed to load: {{message}}",
180
+ "error.configMissing": "Configuration not found for: {{id}}",
181
+ "common.loading": "Loading...",
182
+ "common.showMore": "Show More",
183
+ "common.showLess": "Show Less",
184
+ "common.noResults": "No results found",
185
+ "common.saveChanges": "Save Changes",
186
+ "common.retry": "Retry",
187
+ "common.open": "Open",
188
+ "common.back": "Back",
189
+ "empty.noItems": "No items",
190
+ "empty.noData": "No data available",
191
+ "empty.noItemsYet": "No items yet",
192
+ "empty.noItemsAdded": "No items added yet",
193
+ "empty.noOptionsFound": "No options found",
194
+ "list.addItemPlaceholder": "Add new item...",
195
+ "error.occurred": "An error occurred",
196
+ "error.failedToLoad": "Failed to load data",
197
+ "wizard.back": "Back",
198
+ "wizard.next": "Next",
199
+ "wizard.complete": "Complete",
200
+ "wizard.stepOf": "Step {{current}} of {{total}}",
201
+ "pagination.previous": "Previous",
202
+ "pagination.next": "Next",
203
+ "pagination.total": "Total:",
204
+ "pagination.show": "Show:",
205
+ "pagination.goTo": "Go to:",
206
+ "pagination.go": "Go",
207
+ "auth.signIn": "Sign in",
208
+ "auth.signOut": "Sign out",
209
+ "dialog.confirm": "Confirm",
210
+ "dialog.cancel": "Cancel",
211
+ "dialog.loading": "Loading...",
212
+ "dialog.delete.title": "Delete {{item}}?",
213
+ "dialog.delete.message": "This action cannot be undone.",
214
+ "trait.availableActions": "Available Actions",
215
+ "trait.transitions": "Transitions",
216
+ "trait.availableNow": "Available now",
217
+ "book.startReading": "Start Reading",
218
+ "book.tableOfContents": "Table of Contents",
219
+ "book.partNumber": "Part {{number}}",
220
+ "book.print": "Print",
221
+ "book.previousPage": "Previous page",
222
+ "book.nextPage": "Next page",
223
+ "quiz.showAnswer": "Show answer",
224
+ "quiz.hideAnswer": "Hide answer"
225
+ };
226
+
227
+ // hooks/useTranslate.ts
228
+ var { $meta: _meta, ...coreMessages } = en_default;
229
+ var coreLocale = coreMessages;
230
+ var I18nContext = createContext({
231
+ locale: "en",
232
+ direction: "ltr",
233
+ t: (key) => coreLocale[key] ?? key
234
+ // core locale fallback
235
+ });
236
+ I18nContext.displayName = "I18nContext";
237
+ I18nContext.Provider;
238
+ function useTranslate() {
239
+ return useContext(I18nContext);
240
+ }
241
+ typeof process !== "undefined" && process.env?.VITE_API_URL ? process.env.VITE_API_URL : "http://localhost:3000";
242
+ createContext(void 0);
243
+ var FetchedDataContext = createContext(null);
244
+ function useFetchedDataContext() {
245
+ return useContext(FetchedDataContext);
246
+ }
247
+ function cn(...inputs) {
248
+ return twMerge(clsx(inputs));
249
+ }
250
+ var iconAliases = {
251
+ "close": LucideIcons.X,
252
+ "trash": LucideIcons.Trash2,
253
+ "loader": LucideIcons.Loader2,
254
+ "stop": LucideIcons.Square,
255
+ "volume": LucideIcons.Volume2,
256
+ "volume-off": LucideIcons.VolumeX,
257
+ "refresh": LucideIcons.RefreshCw,
258
+ "share": LucideIcons.Share2,
259
+ "sort-asc": LucideIcons.ArrowUpNarrowWide,
260
+ "sort-desc": LucideIcons.ArrowDownNarrowWide
261
+ };
262
+ function kebabToPascal(name) {
263
+ return name.split("-").map((part) => {
264
+ if (/^\d+$/.test(part)) return part;
265
+ return part.charAt(0).toUpperCase() + part.slice(1);
266
+ }).join("");
267
+ }
268
+ var resolvedCache = /* @__PURE__ */ new Map();
269
+ function resolveIcon(name) {
270
+ const cached = resolvedCache.get(name);
271
+ if (cached) return cached;
272
+ const resolved = doResolve(name);
273
+ resolvedCache.set(name, resolved);
274
+ return resolved;
275
+ }
276
+ function doResolve(name) {
277
+ if (iconAliases[name]) return iconAliases[name];
278
+ const pascalName = kebabToPascal(name);
279
+ const directLookup = LucideIcons[pascalName];
280
+ if (directLookup && typeof directLookup === "object") return directLookup;
281
+ const asIs = LucideIcons[name];
282
+ if (asIs && typeof asIs === "object") return asIs;
283
+ return LucideIcons.HelpCircle;
284
+ }
285
+ var paddingStyles = {
286
+ none: "p-0",
287
+ xs: "p-1",
288
+ sm: "p-2",
289
+ md: "p-4",
290
+ lg: "p-6",
291
+ xl: "p-8",
292
+ "2xl": "p-12"
293
+ };
294
+ var paddingXStyles = {
295
+ none: "px-0",
296
+ xs: "px-1",
297
+ sm: "px-2",
298
+ md: "px-4",
299
+ lg: "px-6",
300
+ xl: "px-8",
301
+ "2xl": "px-12"
302
+ };
303
+ var paddingYStyles = {
304
+ none: "py-0",
305
+ xs: "py-1",
306
+ sm: "py-2",
307
+ md: "py-4",
308
+ lg: "py-6",
309
+ xl: "py-8",
310
+ "2xl": "py-12"
311
+ };
312
+ var marginStyles = {
313
+ none: "m-0",
314
+ xs: "m-1",
315
+ sm: "m-2",
316
+ md: "m-4",
317
+ lg: "m-6",
318
+ xl: "m-8",
319
+ "2xl": "m-12",
320
+ auto: "m-auto"
321
+ };
322
+ var marginXStyles = {
323
+ none: "mx-0",
324
+ xs: "mx-1",
325
+ sm: "mx-2",
326
+ md: "mx-4",
327
+ lg: "mx-6",
328
+ xl: "mx-8",
329
+ "2xl": "mx-12",
330
+ auto: "mx-auto"
331
+ };
332
+ var marginYStyles = {
333
+ none: "my-0",
334
+ xs: "my-1",
335
+ sm: "my-2",
336
+ md: "my-4",
337
+ lg: "my-6",
338
+ xl: "my-8",
339
+ "2xl": "my-12",
340
+ auto: "my-auto"
341
+ };
342
+ var bgStyles = {
343
+ transparent: "bg-transparent",
344
+ primary: "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
345
+ secondary: "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
346
+ muted: "bg-[var(--color-muted)] text-[var(--color-foreground)]",
347
+ accent: "bg-[var(--color-accent)] text-[var(--color-accent-foreground)]",
348
+ surface: "bg-[var(--color-card)]",
349
+ overlay: "bg-[var(--color-card)]/80 backdrop-blur-sm"
350
+ };
351
+ var roundedStyles = {
352
+ none: "rounded-none",
353
+ sm: "rounded-[var(--radius-sm)]",
354
+ md: "rounded-[var(--radius-md)]",
355
+ lg: "rounded-[var(--radius-lg)]",
356
+ xl: "rounded-[var(--radius-xl)]",
357
+ "2xl": "rounded-[var(--radius-xl)]",
358
+ full: "rounded-[var(--radius-full)]"
359
+ };
360
+ var shadowStyles = {
361
+ none: "shadow-none",
362
+ sm: "shadow-[var(--shadow-sm)]",
363
+ md: "shadow-[var(--shadow-main)]",
364
+ lg: "shadow-[var(--shadow-lg)]",
365
+ xl: "shadow-[var(--shadow-lg)]"
366
+ };
367
+ var displayStyles = {
368
+ block: "block",
369
+ inline: "inline",
370
+ "inline-block": "inline-block",
371
+ flex: "flex",
372
+ "inline-flex": "inline-flex",
373
+ grid: "grid"
374
+ };
375
+ var overflowStyles = {
376
+ auto: "overflow-auto",
377
+ hidden: "overflow-hidden",
378
+ visible: "overflow-visible",
379
+ scroll: "overflow-scroll"
380
+ };
381
+ var positionStyles = {
382
+ relative: "relative",
383
+ absolute: "absolute",
384
+ fixed: "fixed",
385
+ sticky: "sticky"
386
+ };
387
+ var Box = React113__default.forwardRef(
388
+ ({
389
+ padding,
390
+ paddingX,
391
+ paddingY,
392
+ margin,
393
+ marginX,
394
+ marginY,
395
+ bg = "transparent",
396
+ border = false,
397
+ rounded = "none",
398
+ shadow = "none",
399
+ display,
400
+ fullWidth = false,
401
+ fullHeight = false,
402
+ overflow,
403
+ position,
404
+ className,
405
+ children,
406
+ as: Component2 = "div",
407
+ action,
408
+ actionPayload,
409
+ hoverEvent,
410
+ onClick,
411
+ onMouseEnter,
412
+ onMouseLeave,
413
+ ...rest
414
+ }, ref) => {
415
+ const eventBus = useEventBus();
416
+ const handleClick = useCallback((e) => {
417
+ if (action) {
418
+ e.stopPropagation();
419
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
420
+ }
421
+ onClick?.(e);
422
+ }, [action, actionPayload, eventBus, onClick]);
423
+ const handleMouseEnter = useCallback((e) => {
424
+ if (hoverEvent) {
425
+ eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
426
+ }
427
+ onMouseEnter?.(e);
428
+ }, [hoverEvent, eventBus, onMouseEnter]);
429
+ const handleMouseLeave = useCallback((e) => {
430
+ if (hoverEvent) {
431
+ eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
432
+ }
433
+ onMouseLeave?.(e);
434
+ }, [hoverEvent, eventBus, onMouseLeave]);
435
+ const isClickable = action || onClick;
436
+ const Comp = Component2;
437
+ return /* @__PURE__ */ jsx(
438
+ Comp,
439
+ {
440
+ ref,
441
+ className: cn(
442
+ // Padding
443
+ padding && paddingStyles[padding],
444
+ paddingX && paddingXStyles[paddingX],
445
+ paddingY && paddingYStyles[paddingY],
446
+ // Margin
447
+ margin && marginStyles[margin],
448
+ marginX && marginXStyles[marginX],
449
+ marginY && marginYStyles[marginY],
450
+ // Background
451
+ bgStyles[bg],
452
+ // Border - uses theme variables
453
+ border && "border-[length:var(--border-width)] border-[var(--color-border)]",
454
+ // Rounded
455
+ roundedStyles[rounded],
456
+ // Shadow
457
+ shadowStyles[shadow],
458
+ // Display
459
+ display && displayStyles[display],
460
+ // Dimensions
461
+ fullWidth && "w-full",
462
+ fullHeight && "h-full",
463
+ // Overflow
464
+ overflow && overflowStyles[overflow],
465
+ // Position
466
+ position && positionStyles[position],
467
+ // Cursor for clickable
468
+ isClickable && "cursor-pointer",
469
+ className
470
+ ),
471
+ onClick: isClickable ? handleClick : void 0,
472
+ onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
473
+ onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
474
+ ...rest,
475
+ children
476
+ }
477
+ );
478
+ }
479
+ );
480
+ Box.displayName = "Box";
481
+ var variantStyles = {
482
+ h1: "text-4xl font-bold tracking-tight text-[var(--color-foreground)]",
483
+ h2: "text-3xl font-bold tracking-tight text-[var(--color-foreground)]",
484
+ h3: "text-2xl font-bold text-[var(--color-foreground)]",
485
+ h4: "text-xl font-bold text-[var(--color-foreground)]",
486
+ h5: "text-lg font-bold text-[var(--color-foreground)]",
487
+ h6: "text-base font-bold text-[var(--color-foreground)]",
488
+ heading: "text-2xl font-bold text-[var(--color-foreground)]",
489
+ subheading: "text-lg font-semibold text-[var(--color-foreground)]",
490
+ body1: "text-base font-normal text-[var(--color-foreground)]",
491
+ body2: "text-sm font-normal text-[var(--color-foreground)]",
492
+ body: "text-base font-normal text-[var(--color-foreground)]",
493
+ caption: "text-xs font-normal text-[var(--color-muted-foreground)]",
494
+ overline: "text-xs uppercase tracking-wide font-bold text-[var(--color-muted-foreground)]",
495
+ small: "text-sm font-normal text-[var(--color-foreground)]",
496
+ large: "text-lg font-medium text-[var(--color-foreground)]",
497
+ label: "text-sm font-medium text-[var(--color-foreground)]"
498
+ };
499
+ var colorStyles = {
500
+ primary: "text-[var(--color-foreground)]",
501
+ secondary: "text-[var(--color-muted-foreground)]",
502
+ muted: "text-[var(--color-muted-foreground)]",
503
+ error: "text-[var(--color-error)]",
504
+ success: "text-[var(--color-success)]",
505
+ warning: "text-[var(--color-warning)]",
506
+ inherit: "text-inherit"
507
+ };
508
+ var weightStyles = {
509
+ light: "font-light",
510
+ normal: "font-normal",
511
+ medium: "font-medium",
512
+ semibold: "font-semibold",
513
+ bold: "font-bold"
514
+ };
515
+ var defaultElements = {
516
+ h1: "h1",
517
+ h2: "h2",
518
+ h3: "h3",
519
+ h4: "h4",
520
+ h5: "h5",
521
+ h6: "h6",
522
+ heading: "h2",
523
+ subheading: "h3",
524
+ body1: "p",
525
+ body2: "p",
526
+ body: "p",
527
+ caption: "span",
528
+ overline: "span",
529
+ small: "span",
530
+ large: "p",
531
+ label: "span"
532
+ };
533
+ var typographySizeStyles = {
534
+ xs: "text-xs",
535
+ sm: "text-sm",
536
+ md: "text-base",
537
+ lg: "text-lg",
538
+ xl: "text-xl",
539
+ "2xl": "text-2xl",
540
+ "3xl": "text-3xl"
541
+ };
542
+ var overflowStyles2 = {
543
+ visible: "overflow-visible",
544
+ hidden: "overflow-hidden",
545
+ wrap: "break-words overflow-hidden",
546
+ "clamp-2": "overflow-hidden line-clamp-2",
547
+ "clamp-3": "overflow-hidden line-clamp-3"
548
+ };
549
+ var Typography = ({
550
+ variant: variantProp,
551
+ level,
552
+ color = "primary",
553
+ align,
554
+ weight,
555
+ size,
556
+ truncate = false,
557
+ overflow,
558
+ as,
559
+ id,
560
+ className,
561
+ style,
562
+ content,
563
+ children
564
+ }) => {
565
+ const variant = variantProp ?? (level ? `h${level}` : "body1");
566
+ const Component2 = as || defaultElements[variant];
567
+ const Comp = Component2;
568
+ return /* @__PURE__ */ jsx(
569
+ Comp,
570
+ {
571
+ id,
572
+ className: cn(
573
+ variantStyles[variant],
574
+ colorStyles[color],
575
+ weight && weightStyles[weight],
576
+ size && typographySizeStyles[size],
577
+ align && `text-${align}`,
578
+ truncate && "truncate overflow-hidden text-ellipsis",
579
+ overflow && overflowStyles2[overflow],
580
+ className
581
+ ),
582
+ style,
583
+ children: children ?? content
584
+ }
585
+ );
586
+ };
587
+ Typography.displayName = "Typography";
588
+ var variantStyles2 = {
589
+ primary: [
590
+ "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
591
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
592
+ "shadow-[var(--shadow-sm)]",
593
+ "hover:bg-[var(--color-primary-hover)] hover:shadow-[var(--shadow-hover)]",
594
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
595
+ ].join(" "),
596
+ secondary: [
597
+ "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
598
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]",
599
+ "hover:bg-[var(--color-secondary-hover)]",
600
+ "active:scale-[var(--active-scale)]"
601
+ ].join(" "),
602
+ ghost: [
603
+ "bg-transparent text-[var(--color-muted-foreground)]",
604
+ "hover:text-[var(--color-foreground)] hover:bg-[var(--color-muted)]",
605
+ "active:scale-[var(--active-scale)]"
606
+ ].join(" "),
607
+ danger: [
608
+ "bg-[var(--color-surface)] text-[var(--color-error)]",
609
+ "border-[length:var(--border-width)] border-[var(--color-error)]",
610
+ "shadow-[var(--shadow-sm)]",
611
+ "hover:bg-[var(--color-error)] hover:text-[var(--color-error-foreground)] hover:shadow-[var(--shadow-hover)]",
612
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
613
+ ].join(" "),
614
+ success: [
615
+ "bg-[var(--color-surface)] text-[var(--color-success)]",
616
+ "border-[length:var(--border-width)] border-[var(--color-success)]",
617
+ "shadow-[var(--shadow-sm)]",
618
+ "hover:bg-[var(--color-success)] hover:text-[var(--color-success-foreground)] hover:shadow-[var(--shadow-hover)]",
619
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
620
+ ].join(" "),
621
+ warning: [
622
+ "bg-[var(--color-surface)] text-[var(--color-warning)]",
623
+ "border-[length:var(--border-width)] border-[var(--color-warning)]",
624
+ "shadow-[var(--shadow-sm)]",
625
+ "hover:bg-[var(--color-warning)] hover:text-[var(--color-warning-foreground)] hover:shadow-[var(--shadow-hover)]",
626
+ "active:scale-[var(--active-scale)] active:shadow-[var(--shadow-active)]"
627
+ ].join(" "),
628
+ // "default" is an alias for secondary
629
+ default: [
630
+ "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
631
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]",
632
+ "hover:bg-[var(--color-secondary-hover)]",
633
+ "active:scale-[var(--active-scale)]"
634
+ ].join(" ")
635
+ };
636
+ variantStyles2.destructive = variantStyles2.danger;
637
+ var sizeStyles2 = {
638
+ sm: "px-3 py-1.5 text-sm",
639
+ md: "px-4 py-2 text-sm",
640
+ lg: "px-6 py-3 text-base"
641
+ };
642
+ var iconSizeStyles = {
643
+ sm: "h-3.5 w-3.5",
644
+ md: "h-4 w-4",
645
+ lg: "h-5 w-5"
646
+ };
647
+ function resolveIconProp(value, sizeClass) {
648
+ if (!value) return null;
649
+ if (typeof value === "string") {
650
+ const Resolved = resolveIcon(value);
651
+ return Resolved ? /* @__PURE__ */ jsx(Resolved, { className: sizeClass }) : null;
652
+ }
653
+ if (typeof value === "function") {
654
+ const IconComp = value;
655
+ return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
656
+ }
657
+ if (React113__default.isValidElement(value)) {
658
+ return value;
659
+ }
660
+ if (typeof value === "object" && value !== null && "render" in value) {
661
+ const IconComp = value;
662
+ return /* @__PURE__ */ jsx(IconComp, { className: sizeClass });
663
+ }
664
+ return value;
665
+ }
666
+ var Button = React113__default.forwardRef(
667
+ ({
668
+ className,
669
+ variant = "primary",
670
+ size = "md",
671
+ isLoading = false,
672
+ disabled,
673
+ leftIcon,
674
+ rightIcon,
675
+ icon: iconProp,
676
+ iconRight: iconRightProp,
677
+ action,
678
+ actionPayload,
679
+ label,
680
+ children,
681
+ onClick,
682
+ ...props
683
+ }, ref) => {
684
+ const eventBus = useEventBus();
685
+ const leftIconValue = leftIcon || iconProp;
686
+ const rightIconValue = rightIcon || iconRightProp;
687
+ const resolvedLeftIcon = resolveIconProp(leftIconValue, iconSizeStyles[size]);
688
+ const resolvedRightIcon = resolveIconProp(rightIconValue, iconSizeStyles[size]);
689
+ const handleClick = (e) => {
690
+ if (action) {
691
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
692
+ }
693
+ onClick?.(e);
694
+ };
695
+ return /* @__PURE__ */ jsxs(
696
+ "button",
697
+ {
698
+ ref,
699
+ disabled: disabled || isLoading,
700
+ className: cn(
701
+ "inline-flex items-center justify-center gap-2",
702
+ "font-[var(--font-weight-medium)]",
703
+ "rounded-[var(--radius-sm)]",
704
+ "transition-all duration-[var(--transition-normal)]",
705
+ "focus:outline-none focus:ring-[length:var(--focus-ring-width)] focus:ring-[var(--color-ring)] focus:ring-offset-[length:var(--focus-ring-offset)]",
706
+ "disabled:opacity-50 disabled:cursor-not-allowed",
707
+ variantStyles2[variant],
708
+ sizeStyles2[size],
709
+ className
710
+ ),
711
+ onClick: handleClick,
712
+ ...props,
713
+ "data-testid": props["data-testid"] ?? (action ? `action-${action}` : void 0),
714
+ children: [
715
+ isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : resolvedLeftIcon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
716
+ children || label,
717
+ resolvedRightIcon && !isLoading && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedRightIcon })
718
+ ]
719
+ }
720
+ );
721
+ }
722
+ );
723
+ Button.displayName = "Button";
724
+ var variantStyles3 = {
725
+ default: [
726
+ "bg-[var(--color-muted)] text-[var(--color-foreground)]",
727
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]"
728
+ ].join(" "),
729
+ primary: "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]",
730
+ secondary: "bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]",
731
+ success: [
732
+ "bg-[var(--color-surface)] text-[var(--color-success)]",
733
+ "border-[length:var(--border-width)] border-[var(--color-success)]"
734
+ ].join(" "),
735
+ warning: [
736
+ "bg-[var(--color-surface)] text-[var(--color-warning)]",
737
+ "border-[length:var(--border-width)] border-[var(--color-warning)]"
738
+ ].join(" "),
739
+ danger: [
740
+ "bg-[var(--color-surface)] text-[var(--color-error)]",
741
+ "border-[length:var(--border-width)] border-[var(--color-error)]"
742
+ ].join(" "),
743
+ error: [
744
+ "bg-[var(--color-surface)] text-[var(--color-error)]",
745
+ "border-[length:var(--border-width)] border-[var(--color-error)]"
746
+ ].join(" "),
747
+ info: [
748
+ "bg-[var(--color-surface)] text-[var(--color-info)]",
749
+ "border-[length:var(--border-width)] border-[var(--color-info)]"
750
+ ].join(" "),
751
+ neutral: [
752
+ "bg-[var(--color-muted)] text-[var(--color-muted-foreground)]",
753
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]"
754
+ ].join(" ")
755
+ };
756
+ var sizeStyles3 = {
757
+ sm: "px-2 py-0.5 text-xs",
758
+ md: "px-2.5 py-1 text-sm",
759
+ lg: "px-3 py-1.5 text-base"
760
+ };
761
+ var Badge = React113__default.forwardRef(
762
+ ({ className, variant = "default", size = "sm", amount, label, icon, children, ...props }, ref) => {
763
+ const iconSizes2 = { sm: "w-3 h-3", md: "w-3.5 h-3.5", lg: "w-4 h-4" };
764
+ const resolvedIcon = typeof icon === "string" ? (() => {
765
+ const I = resolveIcon(icon);
766
+ return I ? /* @__PURE__ */ jsx(I, { className: iconSizes2[size] }) : null;
767
+ })() : icon;
768
+ return /* @__PURE__ */ jsxs(
769
+ "span",
770
+ {
771
+ ref,
772
+ className: cn(
773
+ "inline-flex items-center gap-1 font-bold rounded-[var(--radius-sm)]",
774
+ variantStyles3[variant],
775
+ sizeStyles3[size],
776
+ className
777
+ ),
778
+ ...props,
779
+ children: [
780
+ resolvedIcon,
781
+ children || (amount != null ? `${label ? `${label} ` : ""}${amount}` : label)
782
+ ]
783
+ }
784
+ );
785
+ }
786
+ );
787
+ Badge.displayName = "Badge";
788
+ var Input = React113__default.forwardRef(
789
+ ({
790
+ className,
791
+ inputType,
792
+ type: htmlType,
793
+ error,
794
+ leftIcon,
795
+ rightIcon,
796
+ icon: IconComponent,
797
+ clearable,
798
+ onClear,
799
+ value,
800
+ options,
801
+ rows = 3,
802
+ onChange,
803
+ ...props
804
+ }, ref) => {
805
+ const type = inputType || htmlType || "text";
806
+ const resolvedLeftIcon = leftIcon || IconComponent && /* @__PURE__ */ jsx(IconComponent, { className: "h-4 w-4" });
807
+ const showClearButton = clearable && value && String(value).length > 0;
808
+ const baseClassName = cn(
809
+ "block w-full rounded-[var(--radius-sm)] transition-all duration-[var(--transition-fast)]",
810
+ "border-[length:var(--border-width-thin)] border-[var(--color-border)]",
811
+ "px-3 py-2 text-sm",
812
+ "bg-[var(--color-card)] hover:bg-[var(--color-muted)] focus:bg-[var(--color-card)]",
813
+ "text-[var(--color-foreground)] placeholder:text-[var(--color-muted-foreground)]",
814
+ "focus:outline-none focus:ring-1 focus:ring-[var(--color-ring)] focus:border-[var(--color-ring)]",
815
+ "disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-[var(--color-muted)]",
816
+ error ? "border-[var(--color-error)] focus:border-[var(--color-error)] focus:ring-[var(--color-error)]" : "",
817
+ resolvedLeftIcon && "pl-10",
818
+ (rightIcon || showClearButton) && "pr-10",
819
+ className
820
+ );
821
+ if (type === "select") {
822
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
823
+ 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 }),
824
+ /* @__PURE__ */ jsxs(
825
+ "select",
826
+ {
827
+ ref,
828
+ value,
829
+ onChange,
830
+ className: cn(baseClassName, "appearance-none pr-10", className),
831
+ ...props,
832
+ children: [
833
+ /* @__PURE__ */ jsx("option", { value: "", children: "Select..." }),
834
+ options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
835
+ ]
836
+ }
837
+ ),
838
+ /* @__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" }) })
839
+ ] });
840
+ }
841
+ if (type === "textarea") {
842
+ return /* @__PURE__ */ jsx("div", { className: "relative", children: /* @__PURE__ */ jsx(
843
+ "textarea",
844
+ {
845
+ ref,
846
+ value,
847
+ onChange,
848
+ rows,
849
+ className: baseClassName,
850
+ ...props
851
+ }
852
+ ) });
853
+ }
854
+ if (type === "checkbox") {
855
+ return /* @__PURE__ */ jsx(
856
+ "input",
857
+ {
858
+ ref,
859
+ type: "checkbox",
860
+ checked: props.checked,
861
+ onChange,
862
+ className: cn(
863
+ "h-4 w-4 rounded-[var(--radius-sm)]",
864
+ "border-[var(--color-border)]",
865
+ "text-[var(--color-primary)] focus:ring-[var(--color-ring)]",
866
+ "disabled:opacity-50 disabled:cursor-not-allowed",
867
+ className
868
+ ),
869
+ ...props
870
+ }
871
+ );
872
+ }
873
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
874
+ 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 }),
875
+ /* @__PURE__ */ jsx(
876
+ "input",
877
+ {
878
+ ref,
879
+ type,
880
+ value,
881
+ onChange,
882
+ className: baseClassName,
883
+ ...props
884
+ }
885
+ ),
886
+ showClearButton && /* @__PURE__ */ jsx(
887
+ "button",
888
+ {
889
+ type: "button",
890
+ onClick: onClear,
891
+ className: "absolute inset-y-0 right-0 pr-3 flex items-center text-[var(--color-muted-foreground)] hover:text-[var(--color-foreground)]",
892
+ children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
893
+ }
894
+ ),
895
+ rightIcon && !showClearButton && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center text-[var(--color-muted-foreground)]", children: rightIcon })
896
+ ] });
897
+ }
898
+ );
899
+ Input.displayName = "Input";
900
+ var Label = React113__default.forwardRef(
901
+ ({ className, required, children, ...props }, ref) => {
902
+ return /* @__PURE__ */ jsxs(
903
+ "label",
904
+ {
905
+ ref,
906
+ className: cn(
907
+ "block text-sm font-bold text-[var(--color-foreground)]",
908
+ className
909
+ ),
910
+ ...props,
911
+ children: [
912
+ children,
913
+ required && /* @__PURE__ */ jsx("span", { className: "text-[var(--color-error)] ml-1", children: "*" })
914
+ ]
915
+ }
916
+ );
917
+ }
918
+ );
919
+ Label.displayName = "Label";
920
+ var Textarea = React113__default.forwardRef(
921
+ ({ className, error, ...props }, ref) => {
922
+ return /* @__PURE__ */ jsx(
923
+ "textarea",
924
+ {
925
+ ref,
926
+ className: cn(
927
+ "block w-full border-[length:var(--border-width)] shadow-[var(--shadow-sm)]",
928
+ "px-3 py-2 text-sm text-[var(--color-foreground)]",
929
+ "bg-[var(--color-card)]",
930
+ "placeholder:text-[var(--color-placeholder)]",
931
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-[var(--color-ring)]",
932
+ "disabled:bg-[var(--color-muted)] disabled:text-[var(--color-muted-foreground)] disabled:cursor-not-allowed",
933
+ "resize-y min-h-[80px]",
934
+ error ? "border-[var(--color-error)] focus:border-[var(--color-error)]" : "border-[var(--color-border)] focus:border-[var(--color-primary)]",
935
+ className
936
+ ),
937
+ ...props
938
+ }
939
+ );
940
+ }
941
+ );
942
+ Textarea.displayName = "Textarea";
943
+ var Select = React113__default.forwardRef(
944
+ ({ className, options, placeholder, error, ...props }, ref) => {
945
+ return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
946
+ /* @__PURE__ */ jsxs(
947
+ "select",
948
+ {
949
+ ref,
950
+ className: cn(
951
+ "block w-full border-[length:var(--border-width)] shadow-[var(--shadow-sm)] appearance-none",
952
+ "px-3 py-2 pr-10 text-sm text-[var(--color-foreground)] font-medium",
953
+ "bg-[var(--color-card)]",
954
+ "focus:outline-none focus:ring-2 focus:ring-offset-0 focus:ring-[var(--color-ring)]",
955
+ "disabled:bg-[var(--color-muted)] disabled:text-[var(--color-muted-foreground)] disabled:cursor-not-allowed",
956
+ error ? "border-[var(--color-error)] focus:border-[var(--color-error)]" : "border-[var(--color-border)] focus:border-[var(--color-primary)]",
957
+ className
958
+ ),
959
+ ...props,
960
+ children: [
961
+ placeholder && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
962
+ options.map((option) => /* @__PURE__ */ jsx(
963
+ "option",
964
+ {
965
+ value: option.value,
966
+ disabled: option.disabled,
967
+ children: option.label
968
+ },
969
+ option.value
970
+ ))
971
+ ]
972
+ }
973
+ ),
974
+ /* @__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)]" }) })
975
+ ] });
976
+ }
977
+ );
978
+ Select.displayName = "Select";
979
+ var Checkbox = React113__default.forwardRef(
980
+ ({ className, label, id, ...props }, ref) => {
981
+ const inputId = id || `checkbox-${Math.random().toString(36).substr(2, 9)}`;
982
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
983
+ /* @__PURE__ */ jsx("div", { className: "relative flex items-center", children: /* @__PURE__ */ jsx(
984
+ "input",
985
+ {
986
+ ref,
987
+ type: "checkbox",
988
+ id: inputId,
989
+ className: cn(
990
+ "peer h-4 w-4 border-[length:var(--border-width)] border-[var(--color-border)]",
991
+ "accent-[var(--color-primary)] focus:ring-[var(--color-ring)] focus:ring-offset-0",
992
+ "bg-[var(--color-card)] checked:bg-[var(--color-primary)]",
993
+ "disabled:opacity-50 disabled:cursor-not-allowed",
994
+ className
995
+ ),
996
+ ...props
997
+ }
998
+ ) }),
999
+ label && /* @__PURE__ */ jsx(
1000
+ "label",
1001
+ {
1002
+ htmlFor: inputId,
1003
+ className: "ml-2 text-sm text-[var(--color-foreground)] font-medium cursor-pointer select-none",
1004
+ children: label
1005
+ }
1006
+ )
1007
+ ] });
1008
+ }
1009
+ );
1010
+ Checkbox.displayName = "Checkbox";
1011
+ var variantStyles4 = {
1012
+ default: [
1013
+ "bg-[var(--color-card)] border-none",
1014
+ "transition-all duration-[var(--transition-normal)]",
1015
+ "hover:shadow-[var(--shadow-hover)] hover:-translate-y-0.5"
1016
+ ].join(" "),
1017
+ bordered: [
1018
+ "bg-[var(--color-card)]",
1019
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1020
+ "shadow-none",
1021
+ "transition-all duration-[var(--transition-normal)]",
1022
+ "hover:shadow-[var(--shadow-hover)] hover:-translate-y-0.5"
1023
+ ].join(" "),
1024
+ elevated: [
1025
+ "bg-[var(--color-card)]",
1026
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1027
+ "shadow-[var(--shadow-main)]",
1028
+ "transition-all duration-[var(--transition-normal)]",
1029
+ "hover:shadow-[var(--shadow-hover)] hover:-translate-y-0.5"
1030
+ ].join(" "),
1031
+ // Interactive variant with theme-specific hover effects
1032
+ interactive: [
1033
+ "bg-[var(--color-card)]",
1034
+ "border-[length:var(--border-width)] border-[var(--color-border)]",
1035
+ "shadow-[var(--shadow-main)]",
1036
+ "cursor-pointer",
1037
+ "transition-all duration-[var(--transition-normal)]",
1038
+ "hover:shadow-[var(--shadow-hover)]"
1039
+ ].join(" ")
1040
+ };
1041
+ var paddingStyles2 = {
1042
+ none: "",
1043
+ sm: "p-3",
1044
+ md: "p-4",
1045
+ lg: "p-6"
1046
+ };
1047
+ var shadowStyles2 = {
1048
+ none: "shadow-none",
1049
+ sm: "shadow-[var(--shadow-sm)]",
1050
+ md: "shadow-[var(--shadow-main)]",
1051
+ lg: "shadow-[var(--shadow-lg)]"
1052
+ };
1053
+ var Card = React113__default.forwardRef(
1054
+ ({
1055
+ className,
1056
+ variant = "bordered",
1057
+ padding = "md",
1058
+ title,
1059
+ subtitle,
1060
+ shadow,
1061
+ children,
1062
+ ...props
1063
+ }, ref) => {
1064
+ return /* @__PURE__ */ jsxs(
1065
+ "div",
1066
+ {
1067
+ ref,
1068
+ className: cn(
1069
+ "rounded-[var(--radius-md)]",
1070
+ "transition-all duration-[var(--transition-normal)]",
1071
+ variantStyles4[variant],
1072
+ paddingStyles2[padding],
1073
+ shadow && shadowStyles2[shadow],
1074
+ className
1075
+ ),
1076
+ ...props,
1077
+ children: [
1078
+ (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-4", children: [
1079
+ title && /* @__PURE__ */ jsx("h3", { className: "text-lg text-[var(--color-card-foreground)] font-[var(--font-weight-bold)]", children: title }),
1080
+ subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--color-muted-foreground)] mt-1", children: subtitle })
1081
+ ] }),
1082
+ children
1083
+ ]
1084
+ }
1085
+ );
1086
+ }
1087
+ );
1088
+ Card.displayName = "Card";
1089
+ var CardHeader = React113__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("mb-4", className), ...props }));
1090
+ CardHeader.displayName = "CardHeader";
1091
+ var CardTitle = React113__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1092
+ "h3",
1093
+ {
1094
+ ref,
1095
+ className: cn(
1096
+ "text-lg text-[var(--color-card-foreground)]",
1097
+ "font-[var(--font-weight-bold)]",
1098
+ className
1099
+ ),
1100
+ ...props
1101
+ }
1102
+ ));
1103
+ CardTitle.displayName = "CardTitle";
1104
+ var CardContent = React113__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, className: cn("", className), ...props }));
1105
+ CardContent.displayName = "CardContent";
1106
+ var CardBody = CardContent;
1107
+ CardBody.displayName = "CardBody";
1108
+ var CardFooter = React113__default.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1109
+ "div",
1110
+ {
1111
+ ref,
1112
+ className: cn("mt-4 flex items-center", className),
1113
+ ...props
1114
+ }
1115
+ ));
1116
+ CardFooter.displayName = "CardFooter";
1117
+ var sizeStyles4 = {
1118
+ xs: "h-3 w-3",
1119
+ sm: "h-4 w-4",
1120
+ md: "h-6 w-6",
1121
+ lg: "h-8 w-8"
1122
+ };
1123
+ var Spinner = React113__default.forwardRef(
1124
+ ({ className, size = "md", ...props }, ref) => {
1125
+ return /* @__PURE__ */ jsx(
1126
+ "div",
1127
+ {
1128
+ ref,
1129
+ className: cn("text-[var(--color-foreground)]", className),
1130
+ ...props,
1131
+ children: /* @__PURE__ */ jsx(Loader2, { className: cn("animate-spin", sizeStyles4[size]) })
1132
+ }
1133
+ );
1134
+ }
1135
+ );
1136
+ Spinner.displayName = "Spinner";
1137
+ var Radio = React113__default.forwardRef(
1138
+ ({
1139
+ label,
1140
+ helperText,
1141
+ error,
1142
+ size = "md",
1143
+ className,
1144
+ id,
1145
+ checked,
1146
+ disabled,
1147
+ ...props
1148
+ }, ref) => {
1149
+ const radioId = id || `radio-${Math.random().toString(36).substr(2, 9)}`;
1150
+ const hasError = !!error;
1151
+ const sizeClasses6 = {
1152
+ sm: "w-4 h-4",
1153
+ md: "w-5 h-5",
1154
+ lg: "w-6 h-6"
1155
+ };
1156
+ const dotSizeClasses = {
1157
+ sm: "w-2 h-2",
1158
+ md: "w-2.5 h-2.5",
1159
+ lg: "w-3 h-3"
1160
+ };
1161
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1162
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
1163
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-shrink-0 mt-0.5", children: [
1164
+ /* @__PURE__ */ jsx(
1165
+ "input",
1166
+ {
1167
+ ref,
1168
+ type: "radio",
1169
+ id: radioId,
1170
+ checked,
1171
+ disabled,
1172
+ className: cn("sr-only peer", className),
1173
+ "aria-invalid": hasError,
1174
+ "aria-describedby": error ? `${radioId}-error` : helperText ? `${radioId}-helper` : void 0,
1175
+ ...props
1176
+ }
1177
+ ),
1178
+ /* @__PURE__ */ jsx(
1179
+ "label",
1180
+ {
1181
+ htmlFor: radioId,
1182
+ className: cn(
1183
+ "flex items-center justify-center",
1184
+ "border-[length:var(--border-width)] transition-all cursor-pointer",
1185
+ sizeClasses6[size],
1186
+ hasError ? "border-[var(--color-error)] peer-focus:ring-[var(--color-error)]/20" : "border-[var(--color-border)] peer-focus:ring-[var(--color-ring)]/20",
1187
+ checked ? hasError ? "border-[var(--color-error)]" : "border-[var(--color-primary)] bg-[var(--color-primary)]" : "",
1188
+ "peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-offset-2",
1189
+ disabled && "opacity-50 cursor-not-allowed",
1190
+ !disabled && "hover:border-[var(--color-border-hover)]"
1191
+ ),
1192
+ children: checked && /* @__PURE__ */ jsx(
1193
+ "div",
1194
+ {
1195
+ className: cn(
1196
+ "transition-all",
1197
+ dotSizeClasses[size],
1198
+ hasError ? "bg-[var(--color-error)]" : "bg-[var(--color-primary-foreground)]"
1199
+ )
1200
+ }
1201
+ )
1202
+ }
1203
+ )
1204
+ ] }),
1205
+ label && /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(
1206
+ "label",
1207
+ {
1208
+ htmlFor: radioId,
1209
+ className: cn(
1210
+ "block text-sm font-medium cursor-pointer select-none",
1211
+ hasError ? "text-[var(--color-error)]" : "text-[var(--color-foreground)]",
1212
+ disabled && "opacity-50 cursor-not-allowed"
1213
+ ),
1214
+ children: label
1215
+ }
1216
+ ) })
1217
+ ] }),
1218
+ (helperText || error) && /* @__PURE__ */ jsxs("div", { className: "mt-1.5 ml-8", children: [
1219
+ error && /* @__PURE__ */ jsx(
1220
+ "p",
1221
+ {
1222
+ id: `${radioId}-error`,
1223
+ className: "text-sm text-[var(--color-error)] font-medium",
1224
+ role: "alert",
1225
+ children: error
1226
+ }
1227
+ ),
1228
+ !error && helperText && /* @__PURE__ */ jsx(
1229
+ "p",
1230
+ {
1231
+ id: `${radioId}-helper`,
1232
+ className: "text-sm text-[var(--color-muted-foreground)]",
1233
+ children: helperText
1234
+ }
1235
+ )
1236
+ ] })
1237
+ ] });
1238
+ }
1239
+ );
1240
+ Radio.displayName = "Radio";
1241
+ var Switch = React113.forwardRef(
1242
+ ({
1243
+ checked,
1244
+ defaultChecked = false,
1245
+ onChange,
1246
+ disabled = false,
1247
+ label,
1248
+ id,
1249
+ name,
1250
+ className
1251
+ }, ref) => {
1252
+ const [isChecked, setIsChecked] = React113.useState(
1253
+ checked !== void 0 ? checked : defaultChecked
1254
+ );
1255
+ React113.useEffect(() => {
1256
+ if (checked !== void 0) {
1257
+ setIsChecked(checked);
1258
+ }
1259
+ }, [checked]);
1260
+ const handleClick = () => {
1261
+ if (disabled) return;
1262
+ const newValue = !isChecked;
1263
+ if (checked === void 0) {
1264
+ setIsChecked(newValue);
1265
+ }
1266
+ onChange?.(newValue);
1267
+ };
1268
+ return /* @__PURE__ */ jsxs("div", { className: cn("inline-flex items-center gap-2", className), children: [
1269
+ /* @__PURE__ */ jsx(
1270
+ "button",
1271
+ {
1272
+ ref,
1273
+ type: "button",
1274
+ role: "switch",
1275
+ "aria-checked": isChecked,
1276
+ "aria-label": label,
1277
+ id,
1278
+ name,
1279
+ disabled,
1280
+ onClick: handleClick,
1281
+ className: cn(
1282
+ "relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors",
1283
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
1284
+ isChecked ? "bg-primary" : "bg-muted",
1285
+ disabled && "cursor-not-allowed opacity-50"
1286
+ ),
1287
+ children: /* @__PURE__ */ jsx(
1288
+ "span",
1289
+ {
1290
+ className: cn(
1291
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
1292
+ isChecked ? "translate-x-5" : "translate-x-0"
1293
+ )
1294
+ }
1295
+ )
1296
+ }
1297
+ ),
1298
+ label && /* @__PURE__ */ jsx(
1299
+ "label",
1300
+ {
1301
+ htmlFor: id,
1302
+ className: cn(
1303
+ "text-sm font-medium leading-none cursor-pointer",
1304
+ disabled && "cursor-not-allowed opacity-70"
1305
+ ),
1306
+ onClick: handleClick,
1307
+ children: label
1308
+ }
1309
+ )
1310
+ ] });
1311
+ }
1312
+ );
1313
+ Switch.displayName = "Switch";
1314
+ var gapStyles = {
1315
+ none: "gap-0",
1316
+ xs: "gap-1",
1317
+ sm: "gap-2",
1318
+ md: "gap-4",
1319
+ lg: "gap-6",
1320
+ xl: "gap-8",
1321
+ "2xl": "gap-12"
1322
+ };
1323
+ var alignStyles = {
1324
+ start: "items-start",
1325
+ center: "items-center",
1326
+ end: "items-end",
1327
+ stretch: "items-stretch",
1328
+ baseline: "items-baseline"
1329
+ };
1330
+ var justifyStyles = {
1331
+ start: "justify-start",
1332
+ center: "justify-center",
1333
+ end: "justify-end",
1334
+ between: "justify-between",
1335
+ around: "justify-around",
1336
+ evenly: "justify-evenly"
1337
+ };
1338
+ var Stack = ({
1339
+ direction = "vertical",
1340
+ gap = "md",
1341
+ align = "stretch",
1342
+ justify = "start",
1343
+ wrap = false,
1344
+ reverse = false,
1345
+ flex = false,
1346
+ className,
1347
+ style,
1348
+ children,
1349
+ as: Component2 = "div",
1350
+ onClick,
1351
+ onKeyDown,
1352
+ role,
1353
+ tabIndex,
1354
+ action,
1355
+ actionPayload,
1356
+ responsive = false
1357
+ }) => {
1358
+ const eventBus = useEventBus();
1359
+ const handleClick = (e) => {
1360
+ if (action) {
1361
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
1362
+ }
1363
+ onClick?.(e);
1364
+ };
1365
+ const isHorizontal = direction === "horizontal";
1366
+ 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";
1367
+ const Comp = Component2;
1368
+ return /* @__PURE__ */ jsx(
1369
+ Comp,
1370
+ {
1371
+ className: cn(
1372
+ "flex",
1373
+ directionClass,
1374
+ gapStyles[gap],
1375
+ alignStyles[align],
1376
+ justifyStyles[justify],
1377
+ wrap && "flex-wrap",
1378
+ flex && "flex-1",
1379
+ className
1380
+ ),
1381
+ style,
1382
+ onClick: action || onClick ? handleClick : void 0,
1383
+ onKeyDown,
1384
+ role,
1385
+ tabIndex,
1386
+ children
1387
+ }
1388
+ );
1389
+ };
1390
+ var VStack = (props) => /* @__PURE__ */ jsx(Stack, { direction: "vertical", ...props });
1391
+ var HStack = (props) => /* @__PURE__ */ jsx(Stack, { direction: "horizontal", ...props });
1392
+ var statusColors = {
1393
+ online: "bg-[var(--color-success)]",
1394
+ offline: "bg-[var(--color-muted-foreground)]",
1395
+ away: "bg-[var(--color-warning)]",
1396
+ busy: "bg-[var(--color-error)]",
1397
+ warning: "bg-[var(--color-warning)]",
1398
+ critical: "bg-[var(--color-error)]"
1399
+ };
1400
+ var pulseRingColors = {
1401
+ online: "ring-[var(--color-success)]",
1402
+ offline: "ring-[var(--color-muted-foreground)]",
1403
+ away: "ring-[var(--color-warning)]",
1404
+ busy: "ring-[var(--color-error)]",
1405
+ warning: "ring-[var(--color-warning)]",
1406
+ critical: "ring-[var(--color-error)]"
1407
+ };
1408
+ var sizeStyles5 = {
1409
+ sm: "w-2 h-2",
1410
+ md: "w-2.5 h-2.5",
1411
+ lg: "w-3 h-3"
1412
+ };
1413
+ var StatusDot = React113__default.forwardRef(
1414
+ ({ className, status = "offline", pulse = false, size = "md", label, ...props }, ref) => {
1415
+ return /* @__PURE__ */ jsx(
1416
+ "span",
1417
+ {
1418
+ ref,
1419
+ className: cn(
1420
+ "inline-block rounded-full flex-shrink-0",
1421
+ statusColors[status],
1422
+ sizeStyles5[size],
1423
+ pulse && [
1424
+ "animate-pulse",
1425
+ "ring-2 ring-offset-1",
1426
+ pulseRingColors[status],
1427
+ "ring-opacity-40"
1428
+ ],
1429
+ className
1430
+ ),
1431
+ role: "status",
1432
+ "aria-label": label ?? status,
1433
+ ...props
1434
+ }
1435
+ );
1436
+ }
1437
+ );
1438
+ StatusDot.displayName = "StatusDot";
1439
+ var sizeStyles6 = {
1440
+ sm: { icon: "w-3 h-3", text: "text-xs" },
1441
+ md: { icon: "w-4 h-4", text: "text-sm" },
1442
+ lg: { icon: "w-5 h-5", text: "text-base" }
1443
+ };
1444
+ function resolveDirection(value, direction) {
1445
+ if (direction) return direction;
1446
+ if (value === void 0 || value === 0) return "flat";
1447
+ return value > 0 ? "up" : "down";
1448
+ }
1449
+ function resolveColor(dir, invert) {
1450
+ if (dir === "flat") return "text-[var(--color-muted-foreground)]";
1451
+ const isPositive = dir === "up";
1452
+ const isGood = invert ? !isPositive : isPositive;
1453
+ return isGood ? "text-[var(--color-success)]" : "text-[var(--color-error)]";
1454
+ }
1455
+ var iconMap2 = {
1456
+ up: TrendingUp,
1457
+ down: TrendingDown,
1458
+ flat: ArrowRight
1459
+ };
1460
+ var TrendIndicator = React113__default.forwardRef(
1461
+ ({
1462
+ className,
1463
+ value,
1464
+ direction,
1465
+ showValue = true,
1466
+ invert = false,
1467
+ label,
1468
+ size = "md",
1469
+ ...props
1470
+ }, ref) => {
1471
+ const dir = resolveDirection(value, direction);
1472
+ const colorClass = resolveColor(dir, invert);
1473
+ const IconComponent = iconMap2[dir];
1474
+ const styles = sizeStyles6[size];
1475
+ const formattedValue = value !== void 0 ? `${value > 0 ? "+" : ""}${value}%` : void 0;
1476
+ const ariaLabel = label ?? (formattedValue ? `${dir} ${formattedValue}` : dir);
1477
+ return /* @__PURE__ */ jsxs(
1478
+ "span",
1479
+ {
1480
+ ref,
1481
+ className: cn(
1482
+ "inline-flex items-center gap-1 font-medium",
1483
+ colorClass,
1484
+ styles.text,
1485
+ className
1486
+ ),
1487
+ role: "status",
1488
+ "aria-label": ariaLabel,
1489
+ ...props,
1490
+ children: [
1491
+ /* @__PURE__ */ jsx(IconComponent, { className: styles.icon }),
1492
+ showValue && formattedValue && /* @__PURE__ */ jsx("span", { children: formattedValue })
1493
+ ]
1494
+ }
1495
+ );
1496
+ }
1497
+ );
1498
+ TrendIndicator.displayName = "TrendIndicator";
1499
+ function useSafeEventBus() {
1500
+ try {
1501
+ return useEventBus();
1502
+ } catch {
1503
+ return { emit: () => {
1504
+ }, on: () => () => {
1505
+ }, once: () => {
1506
+ } };
1507
+ }
1508
+ }
1509
+ var trackSizes = {
1510
+ sm: "h-1",
1511
+ md: "h-1.5",
1512
+ lg: "h-2"
1513
+ };
1514
+ var thumbSizes = {
1515
+ sm: "w-3 h-3",
1516
+ md: "w-4 h-4",
1517
+ lg: "w-5 h-5"
1518
+ };
1519
+ var RangeSlider = React113__default.forwardRef(
1520
+ ({
1521
+ className,
1522
+ min = 0,
1523
+ max = 100,
1524
+ value = 0,
1525
+ step = 1,
1526
+ showTooltip = false,
1527
+ showTicks = false,
1528
+ buffered,
1529
+ size = "md",
1530
+ disabled = false,
1531
+ action,
1532
+ actionPayload,
1533
+ onChange,
1534
+ formatValue: formatValue5,
1535
+ ...props
1536
+ }, ref) => {
1537
+ const [isDragging, setIsDragging] = useState(false);
1538
+ const [showTip, setShowTip] = useState(false);
1539
+ const inputRef = useRef(null);
1540
+ const eventBus = useSafeEventBus();
1541
+ const percentage = max !== min ? (value - min) / (max - min) * 100 : 0;
1542
+ const bufferedPercentage = buffered !== void 0 ? Math.min(buffered, 100) : void 0;
1543
+ const displayValue = formatValue5 ? formatValue5(value) : String(value);
1544
+ const handleChange = useCallback(
1545
+ (e) => {
1546
+ const newValue = Number(e.target.value);
1547
+ onChange?.(newValue);
1548
+ if (action) {
1549
+ eventBus.emit(`UI:${action}`, { ...actionPayload, value: newValue });
1550
+ }
1551
+ },
1552
+ [onChange, action, actionPayload, eventBus]
1553
+ );
1554
+ const tickCount = showTicks ? Math.min(Math.floor((max - min) / step), 20) : 0;
1555
+ return /* @__PURE__ */ jsxs(
1556
+ "div",
1557
+ {
1558
+ ref,
1559
+ className: cn(
1560
+ "relative w-full",
1561
+ disabled && "opacity-50 cursor-not-allowed",
1562
+ className
1563
+ ),
1564
+ ...props,
1565
+ children: [
1566
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full py-2", children: [
1567
+ /* @__PURE__ */ jsx(
1568
+ "div",
1569
+ {
1570
+ className: cn(
1571
+ "absolute inset-x-0 rounded-full bg-[var(--color-muted)]",
1572
+ trackSizes[size]
1573
+ ),
1574
+ style: { top: "50%", transform: "translateY(-50%)" }
1575
+ }
1576
+ ),
1577
+ bufferedPercentage !== void 0 && /* @__PURE__ */ jsx(
1578
+ "div",
1579
+ {
1580
+ className: cn(
1581
+ "absolute rounded-full bg-[var(--color-muted-foreground)] opacity-30",
1582
+ trackSizes[size]
1583
+ ),
1584
+ style: {
1585
+ top: "50%",
1586
+ transform: "translateY(-50%)",
1587
+ left: 0,
1588
+ width: `${bufferedPercentage}%`
1589
+ }
1590
+ }
1591
+ ),
1592
+ /* @__PURE__ */ jsx(
1593
+ "div",
1594
+ {
1595
+ className: cn(
1596
+ "absolute rounded-full bg-[var(--color-primary)]",
1597
+ trackSizes[size]
1598
+ ),
1599
+ style: {
1600
+ top: "50%",
1601
+ transform: "translateY(-50%)",
1602
+ left: 0,
1603
+ width: `${percentage}%`
1604
+ }
1605
+ }
1606
+ ),
1607
+ /* @__PURE__ */ jsx(
1608
+ "input",
1609
+ {
1610
+ ref: inputRef,
1611
+ type: "range",
1612
+ min,
1613
+ max,
1614
+ step,
1615
+ value,
1616
+ disabled,
1617
+ onChange: handleChange,
1618
+ onMouseDown: () => {
1619
+ setIsDragging(true);
1620
+ setShowTip(true);
1621
+ },
1622
+ onMouseUp: () => {
1623
+ setIsDragging(false);
1624
+ setShowTip(false);
1625
+ },
1626
+ onTouchStart: () => {
1627
+ setIsDragging(true);
1628
+ setShowTip(true);
1629
+ },
1630
+ onTouchEnd: () => {
1631
+ setIsDragging(false);
1632
+ setShowTip(false);
1633
+ },
1634
+ onFocus: () => setShowTip(true),
1635
+ onBlur: () => {
1636
+ if (!isDragging) setShowTip(false);
1637
+ },
1638
+ className: cn(
1639
+ "absolute inset-0 w-full opacity-0 cursor-pointer",
1640
+ disabled && "cursor-not-allowed",
1641
+ // Thumb sizing via pseudo-element
1642
+ "[&::-webkit-slider-thumb]:appearance-none",
1643
+ "[&::-webkit-slider-thumb]:w-5 [&::-webkit-slider-thumb]:h-5",
1644
+ "[&::-moz-range-thumb]:w-5 [&::-moz-range-thumb]:h-5"
1645
+ ),
1646
+ style: { height: "100%", margin: 0 },
1647
+ "aria-label": props["aria-label"] ?? "Range slider",
1648
+ "aria-valuemin": min,
1649
+ "aria-valuemax": max,
1650
+ "aria-valuenow": value,
1651
+ "aria-valuetext": displayValue
1652
+ }
1653
+ ),
1654
+ /* @__PURE__ */ jsx(
1655
+ "div",
1656
+ {
1657
+ className: cn(
1658
+ "absolute rounded-full bg-[var(--color-primary-foreground)]",
1659
+ "border-2 border-[var(--color-primary)]",
1660
+ "shadow-[var(--shadow-sm)]",
1661
+ "pointer-events-none",
1662
+ "transition-transform duration-100",
1663
+ isDragging && "scale-110",
1664
+ thumbSizes[size]
1665
+ ),
1666
+ style: {
1667
+ top: "50%",
1668
+ transform: `translateY(-50%) translateX(-50%)${isDragging ? " scale(1.1)" : ""}`,
1669
+ left: `${percentage}%`
1670
+ }
1671
+ }
1672
+ ),
1673
+ showTooltip && showTip && /* @__PURE__ */ jsx(
1674
+ "div",
1675
+ {
1676
+ className: cn(
1677
+ "absolute -top-8 px-2 py-0.5 rounded",
1678
+ "bg-[var(--color-foreground)] text-[var(--color-background)]",
1679
+ "text-xs font-medium whitespace-nowrap",
1680
+ "pointer-events-none"
1681
+ ),
1682
+ style: {
1683
+ left: `${percentage}%`,
1684
+ transform: "translateX(-50%)"
1685
+ },
1686
+ children: displayValue
1687
+ }
1688
+ )
1689
+ ] }),
1690
+ showTicks && tickCount > 0 && /* @__PURE__ */ jsx("div", { className: "relative w-full h-2 mt-1", children: Array.from({ length: tickCount + 1 }, (_, i) => {
1691
+ const tickPercent = i / tickCount * 100;
1692
+ return /* @__PURE__ */ jsx(
1693
+ "div",
1694
+ {
1695
+ className: "absolute w-px h-1.5 bg-[var(--color-muted-foreground)]",
1696
+ style: { left: `${tickPercent}%` }
1697
+ },
1698
+ i
1699
+ );
1700
+ }) })
1701
+ ]
1702
+ }
1703
+ );
1704
+ }
1705
+ );
1706
+ RangeSlider.displayName = "RangeSlider";
1707
+ var backgroundClasses = {
1708
+ default: "",
1709
+ alt: "bg-[var(--color-surface)]",
1710
+ dark: "bg-[var(--color-foreground)] text-[var(--color-background)]",
1711
+ gradient: [
1712
+ "bg-gradient-to-b",
1713
+ "from-[var(--color-primary)]/5",
1714
+ "to-[var(--color-secondary)]/5"
1715
+ ].join(" ")
1716
+ };
1717
+ var paddingClasses = {
1718
+ sm: "py-12",
1719
+ md: "py-16",
1720
+ lg: "py-24"
1721
+ };
1722
+ var ContentSection = React113__default.forwardRef(
1723
+ ({ children, background = "default", padding = "lg", id, className }, ref) => {
1724
+ return /* @__PURE__ */ jsx(
1725
+ Box,
1726
+ {
1727
+ ref,
1728
+ as: "section",
1729
+ id,
1730
+ className: cn(
1731
+ backgroundClasses[background],
1732
+ paddingClasses[padding],
1733
+ className
1734
+ ),
1735
+ children: /* @__PURE__ */ jsx(Box, { className: "mx-auto max-w-7xl px-4 sm:px-6 lg:px-8", children })
1736
+ }
1737
+ );
1738
+ }
1739
+ );
1740
+ ContentSection.displayName = "ContentSection";
1741
+ var ErrorState = ({
1742
+ title,
1743
+ message,
1744
+ description,
1745
+ onRetry,
1746
+ className,
1747
+ retryEvent
1748
+ }) => {
1749
+ const eventBus = useEventBus();
1750
+ const { t } = useTranslate();
1751
+ const handleRetry = () => {
1752
+ if (retryEvent) eventBus.emit(`UI:${retryEvent}`, {});
1753
+ onRetry?.();
1754
+ };
1755
+ const resolvedTitle = title ?? t("error.generic");
1756
+ const resolvedMessage = message ?? description ?? t("error.occurred");
1757
+ return /* @__PURE__ */ jsxs(
1758
+ VStack,
1759
+ {
1760
+ align: "center",
1761
+ className: cn(
1762
+ "justify-center py-12 text-center",
1763
+ className
1764
+ ),
1765
+ children: [
1766
+ /* @__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)]" }) }),
1767
+ /* @__PURE__ */ jsx(Typography, { variant: "h3", className: "text-lg font-medium text-[var(--color-foreground)]", children: resolvedTitle }),
1768
+ /* @__PURE__ */ jsx(Typography, { variant: "small", className: "mt-1 text-[var(--color-muted-foreground)] max-w-sm", children: resolvedMessage }),
1769
+ (onRetry || retryEvent) && /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: handleRetry, children: t("error.retry") })
1770
+ ]
1771
+ }
1772
+ );
1773
+ };
1774
+ ErrorState.displayName = "ErrorState";
1775
+ var ErrorBoundary = class extends React113__default.Component {
1776
+ constructor(props) {
1777
+ super(props);
1778
+ __publicField(this, "reset", () => {
1779
+ this.setState({ error: null });
1780
+ });
1781
+ this.state = { error: null };
1782
+ }
1783
+ static getDerivedStateFromError(error) {
1784
+ return { error };
1785
+ }
1786
+ componentDidCatch(error, errorInfo) {
1787
+ this.props.onError?.(error, errorInfo);
1788
+ }
1789
+ render() {
1790
+ const { error } = this.state;
1791
+ const { children, fallback, className } = this.props;
1792
+ if (error) {
1793
+ const wrapper = className ? /* @__PURE__ */ jsx("div", { className: cn(className), children: this.renderFallback(error, fallback) }) : this.renderFallback(error, fallback);
1794
+ return wrapper;
1795
+ }
1796
+ return children;
1797
+ }
1798
+ renderFallback(error, fallback) {
1799
+ if (typeof fallback === "function") {
1800
+ return fallback(error, this.reset);
1801
+ }
1802
+ if (fallback) {
1803
+ return fallback;
1804
+ }
1805
+ return /* @__PURE__ */ jsx(
1806
+ ErrorState,
1807
+ {
1808
+ title: "Something went wrong",
1809
+ message: error.message,
1810
+ onRetry: this.reset
1811
+ }
1812
+ );
1813
+ }
1814
+ };
1815
+ __publicField(ErrorBoundary, "displayName", "ErrorBoundary");
1816
+ var ClientEffectConfigContext = createContext(null);
1817
+ ClientEffectConfigContext.Provider;
1818
+ createContext(null);
1819
+ var defaultIcon = L.icon({
1820
+ iconUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
1821
+ iconRetinaUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon-2x.png",
1822
+ shadowUrl: "https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
1823
+ iconSize: [25, 41],
1824
+ iconAnchor: [12, 41],
1825
+ popupAnchor: [1, -34],
1826
+ shadowSize: [41, 41]
1827
+ });
1828
+ L.Marker.prototype.options.icon = defaultIcon;
1829
+
1830
+ // lib/verificationRegistry.ts
1831
+ var checks = /* @__PURE__ */ new Map();
1832
+ var transitions = [];
1833
+ var MAX_TRANSITIONS = 500;
1834
+ var listeners = /* @__PURE__ */ new Set();
1835
+ function notifyListeners() {
1836
+ listeners.forEach((l) => l());
1837
+ exposeOnWindow();
1838
+ }
1839
+ function registerCheck(id, label, status = "pending", details) {
1840
+ checks.set(id, { id, label, status, details, updatedAt: Date.now() });
1841
+ notifyListeners();
1842
+ }
1843
+ function getAllChecks() {
1844
+ return Array.from(checks.values());
1845
+ }
1846
+ function recordTransition(trace) {
1847
+ const entry = {
1848
+ ...trace,
1849
+ id: `t-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
1850
+ };
1851
+ transitions.push(entry);
1852
+ if (transitions.length > MAX_TRANSITIONS) {
1853
+ transitions.shift();
1854
+ }
1855
+ if (entry.event === "INIT") {
1856
+ const hasFetch = entry.effects.some((e) => e.type === "fetch");
1857
+ const checkId = `init-fetch-${entry.traitName}`;
1858
+ if (hasFetch) {
1859
+ registerCheck(
1860
+ checkId,
1861
+ `INIT transition for "${entry.traitName}" has fetch effect`,
1862
+ "pass"
1863
+ );
1864
+ } else {
1865
+ const hasRenderUI = entry.effects.some((e) => e.type === "render-ui");
1866
+ if (hasRenderUI) {
1867
+ registerCheck(
1868
+ checkId,
1869
+ `INIT transition for "${entry.traitName}" missing fetch effect`,
1870
+ "fail",
1871
+ "Entity-bound render-ui without a fetch effect will show empty data"
1872
+ );
1873
+ }
1874
+ }
1875
+ }
1876
+ const failedEffects = entry.effects.filter((e) => e.status === "failed");
1877
+ if (failedEffects.length > 0) {
1878
+ registerCheck(
1879
+ `effects-${entry.id}`,
1880
+ `Effects failed in ${entry.traitName}: ${entry.from} -> ${entry.to}`,
1881
+ "fail",
1882
+ failedEffects.map((e) => `${e.type}: ${e.error}`).join("; ")
1883
+ );
1884
+ }
1885
+ notifyListeners();
1886
+ }
1887
+ function getTransitions() {
1888
+ return [...transitions];
1889
+ }
1890
+ function getBridgeHealth() {
1891
+ return null;
1892
+ }
1893
+ function getSummary() {
1894
+ const allChecks = getAllChecks();
1895
+ return {
1896
+ totalChecks: allChecks.length,
1897
+ passed: allChecks.filter((c) => c.status === "pass").length,
1898
+ failed: allChecks.filter((c) => c.status === "fail").length,
1899
+ warnings: allChecks.filter((c) => c.status === "warn").length,
1900
+ pending: allChecks.filter((c) => c.status === "pending").length
1901
+ };
1902
+ }
1903
+ function getSnapshot2() {
1904
+ return {
1905
+ checks: getAllChecks(),
1906
+ transitions: getTransitions(),
1907
+ bridge: getBridgeHealth(),
1908
+ summary: getSummary()
1909
+ };
1910
+ }
1911
+ function subscribeToVerification(listener) {
1912
+ listeners.add(listener);
1913
+ return () => listeners.delete(listener);
1914
+ }
1915
+ function exposeOnWindow() {
1916
+ if (typeof window === "undefined") return;
1917
+ if (!window.__orbitalVerification) {
1918
+ window.__orbitalVerification = {
1919
+ getSnapshot: getSnapshot2,
1920
+ getChecks: getAllChecks,
1921
+ getTransitions,
1922
+ getBridge: getBridgeHealth,
1923
+ getSummary,
1924
+ waitForTransition
1925
+ };
1926
+ }
1927
+ }
1928
+ function waitForTransition(event, timeoutMs = 1e4) {
1929
+ return new Promise((resolve) => {
1930
+ const existing = transitions.find((t) => t.event === event);
1931
+ if (existing) {
1932
+ resolve(existing);
1933
+ return;
1934
+ }
1935
+ const timeout = setTimeout(() => {
1936
+ unsub();
1937
+ resolve(null);
1938
+ }, timeoutMs);
1939
+ const unsub = subscribeToVerification(() => {
1940
+ const found = transitions.find((t) => t.event === event);
1941
+ if (found) {
1942
+ clearTimeout(timeout);
1943
+ unsub();
1944
+ resolve(found);
1945
+ }
1946
+ });
1947
+ });
1948
+ }
1949
+ exposeOnWindow();
1950
+ var MarkdownContent = React113__default.memo(
1951
+ ({ content, direction, className }) => {
1952
+ const { t: _t } = useTranslate();
1953
+ return /* @__PURE__ */ jsx(
1954
+ Box,
1955
+ {
1956
+ className: cn("prose prose-slate dark:prose-invert max-w-none", className),
1957
+ style: { direction },
1958
+ children: /* @__PURE__ */ jsx(
1959
+ ReactMarkdown,
1960
+ {
1961
+ remarkPlugins: [remarkMath, remarkGfm],
1962
+ rehypePlugins: [
1963
+ [rehypeKatex, { strict: false, throwOnError: false }]
1964
+ ],
1965
+ components: {
1966
+ // Handle inline code only — fenced code blocks are parsed out separately
1967
+ code({ className: codeClassName, children, ...props }) {
1968
+ return /* @__PURE__ */ jsx(
1969
+ "code",
1970
+ {
1971
+ ...props,
1972
+ className: codeClassName,
1973
+ style: {
1974
+ backgroundColor: "#1f2937",
1975
+ color: "#e5e7eb",
1976
+ padding: "0.125rem 0.375rem",
1977
+ borderRadius: "0.25rem",
1978
+ fontSize: "0.875em",
1979
+ fontFamily: "ui-monospace, monospace"
1980
+ },
1981
+ children
1982
+ }
1983
+ );
1984
+ },
1985
+ // Style links
1986
+ a({ href, children, ...props }) {
1987
+ return /* @__PURE__ */ jsx(
1988
+ "a",
1989
+ {
1990
+ href,
1991
+ ...props,
1992
+ className: "text-blue-600 dark:text-blue-400 hover:underline",
1993
+ target: href?.startsWith("http") ? "_blank" : void 0,
1994
+ rel: href?.startsWith("http") ? "noopener noreferrer" : void 0,
1995
+ children
1996
+ }
1997
+ );
1998
+ },
1999
+ // Style tables
2000
+ table({ children, ...props }) {
2001
+ return /* @__PURE__ */ jsx("div", { className: "overflow-x-auto my-4", children: /* @__PURE__ */ jsx(
2002
+ "table",
2003
+ {
2004
+ ...props,
2005
+ className: "min-w-full border-collapse border border-gray-300 dark:border-gray-600",
2006
+ children
2007
+ }
2008
+ ) });
2009
+ },
2010
+ th({ children, ...props }) {
2011
+ return /* @__PURE__ */ jsx(
2012
+ "th",
2013
+ {
2014
+ ...props,
2015
+ className: "border border-gray-300 dark:border-gray-600 bg-gray-100 dark:bg-gray-800 px-4 py-2 text-left font-semibold",
2016
+ children
2017
+ }
2018
+ );
2019
+ },
2020
+ td({ children, ...props }) {
2021
+ return /* @__PURE__ */ jsx(
2022
+ "td",
2023
+ {
2024
+ ...props,
2025
+ className: "border border-gray-300 dark:border-gray-600 px-4 py-2",
2026
+ children
2027
+ }
2028
+ );
2029
+ },
2030
+ // Style blockquotes
2031
+ blockquote({ children, ...props }) {
2032
+ return /* @__PURE__ */ jsx(
2033
+ "blockquote",
2034
+ {
2035
+ ...props,
2036
+ className: "border-l-4 border-blue-500 pl-4 italic text-[var(--color-foreground)] my-4",
2037
+ children
2038
+ }
2039
+ );
2040
+ }
2041
+ },
2042
+ children: content
2043
+ }
2044
+ )
2045
+ }
2046
+ );
2047
+ },
2048
+ (prev, next) => prev.content === next.content && prev.className === next.className && prev.direction === next.direction
2049
+ );
2050
+ MarkdownContent.displayName = "MarkdownContent";
2051
+ var CodeBlock = React113__default.memo(
2052
+ ({
2053
+ code,
2054
+ language = "text",
2055
+ showCopyButton = true,
2056
+ showLanguageBadge = true,
2057
+ maxHeight = "60vh",
2058
+ className
2059
+ }) => {
2060
+ const eventBus = useEventBus();
2061
+ const { t: _t } = useTranslate();
2062
+ const scrollRef = useRef(null);
2063
+ const savedScrollLeftRef = useRef(0);
2064
+ const [copied, setCopied] = useState(false);
2065
+ useLayoutEffect(() => {
2066
+ const el = scrollRef.current;
2067
+ return () => {
2068
+ if (el) savedScrollLeftRef.current = el.scrollLeft;
2069
+ };
2070
+ }, [language, code]);
2071
+ useLayoutEffect(() => {
2072
+ const el = scrollRef.current;
2073
+ if (el) el.scrollLeft = savedScrollLeftRef.current;
2074
+ }, [language, code]);
2075
+ useEffect(() => {
2076
+ const el = scrollRef.current;
2077
+ if (!el) return;
2078
+ const handle = () => {
2079
+ savedScrollLeftRef.current = el.scrollLeft;
2080
+ };
2081
+ el.addEventListener("scroll", handle, { passive: true });
2082
+ return () => el.removeEventListener("scroll", handle);
2083
+ }, [language, code]);
2084
+ const handleCopy = async () => {
2085
+ try {
2086
+ await navigator.clipboard.writeText(code);
2087
+ setCopied(true);
2088
+ eventBus.emit("UI:COPY_CODE", { language, success: true });
2089
+ setTimeout(() => setCopied(false), 2e3);
2090
+ } catch (err) {
2091
+ console.error("Failed to copy code:", err);
2092
+ eventBus.emit("UI:COPY_CODE", { language, success: false });
2093
+ }
2094
+ };
2095
+ return /* @__PURE__ */ jsxs(Box, { className: `relative group ${className || ""}`, children: [
2096
+ (showLanguageBadge || showCopyButton) && /* @__PURE__ */ jsxs(
2097
+ HStack,
2098
+ {
2099
+ justify: "between",
2100
+ align: "center",
2101
+ className: "px-3 py-2 bg-gray-800 rounded-t-lg border-b border-gray-700",
2102
+ children: [
2103
+ showLanguageBadge && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: language }),
2104
+ showCopyButton && /* @__PURE__ */ jsx(
2105
+ Button,
2106
+ {
2107
+ variant: "ghost",
2108
+ size: "sm",
2109
+ onClick: handleCopy,
2110
+ className: "opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity text-[var(--color-muted-foreground)] hover:text-white",
2111
+ "aria-label": "Copy code",
2112
+ children: copied ? /* @__PURE__ */ jsx(Check, { size: 16, className: "text-green-400" }) : /* @__PURE__ */ jsx(Copy, { size: 16 })
2113
+ }
2114
+ )
2115
+ ]
2116
+ }
2117
+ ),
2118
+ /* @__PURE__ */ jsx(
2119
+ "div",
2120
+ {
2121
+ ref: scrollRef,
2122
+ style: {
2123
+ overflowX: "auto",
2124
+ overflowY: "auto",
2125
+ WebkitOverflowScrolling: "touch",
2126
+ maxHeight,
2127
+ overscrollBehavior: "auto",
2128
+ touchAction: "pan-x pan-y",
2129
+ contain: "paint",
2130
+ backgroundColor: "#1e1e1e",
2131
+ borderRadius: showLanguageBadge || showCopyButton ? "0 0 0.5rem 0.5rem" : "0.5rem",
2132
+ padding: "1rem"
2133
+ },
2134
+ children: /* @__PURE__ */ jsx(
2135
+ SyntaxHighlighter,
2136
+ {
2137
+ PreTag: "div",
2138
+ language,
2139
+ style: dark,
2140
+ customStyle: {
2141
+ backgroundColor: "transparent",
2142
+ borderRadius: 0,
2143
+ padding: 0,
2144
+ margin: 0,
2145
+ whiteSpace: "pre",
2146
+ minWidth: "100%"
2147
+ },
2148
+ children: code
2149
+ }
2150
+ )
2151
+ }
2152
+ )
2153
+ ] });
2154
+ },
2155
+ (prev, next) => prev.language === next.language && prev.code === next.code && prev.showCopyButton === next.showCopyButton && prev.maxHeight === next.maxHeight
2156
+ );
2157
+ CodeBlock.displayName = "CodeBlock";
2158
+ var Camera3D = forwardRef(
2159
+ ({
2160
+ mode = "isometric",
2161
+ position = [10, 10, 10],
2162
+ target = [0, 0, 0],
2163
+ zoom = 1,
2164
+ fov = 45,
2165
+ enableOrbit = true,
2166
+ minDistance = 2,
2167
+ maxDistance = 100,
2168
+ onChange
2169
+ }, ref) => {
2170
+ const { camera, set, viewport } = useThree();
2171
+ const controlsRef = useRef(null);
2172
+ const initialPosition = useRef(new THREE.Vector3(...position));
2173
+ const initialTarget = useRef(new THREE.Vector3(...target));
2174
+ useEffect(() => {
2175
+ let newCamera;
2176
+ if (mode === "isometric") {
2177
+ const aspect = viewport.aspect;
2178
+ const size = 10 / zoom;
2179
+ newCamera = new THREE.OrthographicCamera(
2180
+ -size * aspect,
2181
+ size * aspect,
2182
+ size,
2183
+ -size,
2184
+ 0.1,
2185
+ 1e3
2186
+ );
2187
+ } else {
2188
+ newCamera = new THREE.PerspectiveCamera(fov, viewport.aspect, 0.1, 1e3);
2189
+ }
2190
+ newCamera.position.copy(initialPosition.current);
2191
+ newCamera.lookAt(initialTarget.current);
2192
+ set({ camera: newCamera });
2193
+ if (mode === "top-down") {
2194
+ newCamera.position.set(0, 20 / zoom, 0);
2195
+ newCamera.lookAt(0, 0, 0);
2196
+ }
2197
+ return () => {
2198
+ };
2199
+ }, [mode, fov, zoom, viewport.aspect, set]);
2200
+ useFrame(() => {
2201
+ if (onChange) {
2202
+ onChange(camera);
2203
+ }
2204
+ });
2205
+ useImperativeHandle(ref, () => ({
2206
+ getCamera: () => camera,
2207
+ setPosition: (x, y, z) => {
2208
+ camera.position.set(x, y, z);
2209
+ if (controlsRef.current) {
2210
+ controlsRef.current.update();
2211
+ }
2212
+ },
2213
+ lookAt: (x, y, z) => {
2214
+ camera.lookAt(x, y, z);
2215
+ if (controlsRef.current) {
2216
+ controlsRef.current.target.set(x, y, z);
2217
+ controlsRef.current.update();
2218
+ }
2219
+ },
2220
+ reset: () => {
2221
+ camera.position.copy(initialPosition.current);
2222
+ camera.lookAt(initialTarget.current);
2223
+ if (controlsRef.current) {
2224
+ controlsRef.current.target.copy(initialTarget.current);
2225
+ controlsRef.current.update();
2226
+ }
2227
+ },
2228
+ getViewBounds: () => {
2229
+ const min = new THREE.Vector3(-10, -10, -10);
2230
+ const max = new THREE.Vector3(10, 10, 10);
2231
+ return { min, max };
2232
+ }
2233
+ }));
2234
+ const maxPolarAngle = mode === "top-down" ? 0.1 : Math.PI / 2 - 0.1;
2235
+ return /* @__PURE__ */ jsx(
2236
+ OrbitControls,
2237
+ {
2238
+ ref: controlsRef,
2239
+ camera,
2240
+ enabled: enableOrbit,
2241
+ target: initialTarget.current,
2242
+ minDistance,
2243
+ maxDistance,
2244
+ maxPolarAngle,
2245
+ enableDamping: true,
2246
+ dampingFactor: 0.05
2247
+ }
2248
+ );
2249
+ }
2250
+ );
2251
+ Camera3D.displayName = "Camera3D";
2252
+ var Canvas3DErrorBoundary = class extends Component {
2253
+ constructor(props) {
2254
+ super(props);
2255
+ __publicField(this, "handleReset", () => {
2256
+ this.setState({
2257
+ hasError: false,
2258
+ error: null,
2259
+ errorInfo: null
2260
+ });
2261
+ this.props.onReset?.();
2262
+ });
2263
+ this.state = {
2264
+ hasError: false,
2265
+ error: null,
2266
+ errorInfo: null
2267
+ };
2268
+ }
2269
+ static getDerivedStateFromError(error) {
2270
+ return {
2271
+ hasError: true,
2272
+ error,
2273
+ errorInfo: null
2274
+ };
2275
+ }
2276
+ componentDidCatch(error, errorInfo) {
2277
+ this.setState({ errorInfo });
2278
+ this.props.onError?.(error, errorInfo);
2279
+ console.error("[Canvas3DErrorBoundary] Error caught:", error);
2280
+ console.error("[Canvas3DErrorBoundary] Component stack:", errorInfo.componentStack);
2281
+ }
2282
+ render() {
2283
+ if (this.state.hasError) {
2284
+ if (this.props.fallback) {
2285
+ return this.props.fallback;
2286
+ }
2287
+ return /* @__PURE__ */ jsx("div", { className: "canvas-3d-error", children: /* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__content", children: [
2288
+ /* @__PURE__ */ jsx("div", { className: "canvas-3d-error__icon", children: "\u26A0\uFE0F" }),
2289
+ /* @__PURE__ */ jsx("h2", { className: "canvas-3d-error__title", children: "3D Scene Error" }),
2290
+ /* @__PURE__ */ jsx("p", { className: "canvas-3d-error__message", children: "Something went wrong while rendering the 3D scene." }),
2291
+ this.state.error && /* @__PURE__ */ jsxs("details", { className: "canvas-3d-error__details", children: [
2292
+ /* @__PURE__ */ jsx("summary", { children: "Error Details" }),
2293
+ /* @__PURE__ */ jsxs("pre", { className: "error__stack", children: [
2294
+ this.state.error.message,
2295
+ "\n",
2296
+ this.state.error.stack
2297
+ ] }),
2298
+ this.state.errorInfo && /* @__PURE__ */ jsx("pre", { className: "error__component-stack", children: this.state.errorInfo.componentStack })
2299
+ ] }),
2300
+ /* @__PURE__ */ jsxs("div", { className: "canvas-3d-error__actions", children: [
2301
+ /* @__PURE__ */ jsx(
2302
+ "button",
2303
+ {
2304
+ className: "error__button error__button--primary",
2305
+ onClick: this.handleReset,
2306
+ children: "Try Again"
2307
+ }
2308
+ ),
2309
+ /* @__PURE__ */ jsx(
2310
+ "button",
2311
+ {
2312
+ className: "error__button error__button--secondary",
2313
+ onClick: () => window.location.reload(),
2314
+ children: "Reload Page"
2315
+ }
2316
+ )
2317
+ ] })
2318
+ ] }) });
2319
+ }
2320
+ return this.props.children;
2321
+ }
2322
+ };
2323
+ function Canvas3DLoadingState({
2324
+ progress = 0,
2325
+ loaded = 0,
2326
+ total = 0,
2327
+ message = "Loading 3D Scene...",
2328
+ details,
2329
+ showSpinner = true,
2330
+ className
2331
+ }) {
2332
+ const clampedProgress = Math.max(0, Math.min(100, progress));
2333
+ const hasProgress = total > 0;
2334
+ return /* @__PURE__ */ jsxs("div", { className: `canvas-3d-loading ${className || ""}`, children: [
2335
+ /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__content", children: [
2336
+ showSpinner && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__spinner", children: [
2337
+ /* @__PURE__ */ jsx("div", { className: "spinner__ring" }),
2338
+ /* @__PURE__ */ jsx("div", { className: "spinner__ring spinner__ring--secondary" })
2339
+ ] }),
2340
+ /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__message", children: message }),
2341
+ details && /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__details", children: details }),
2342
+ hasProgress && /* @__PURE__ */ jsxs("div", { className: "canvas-3d-loading__progress", children: [
2343
+ /* @__PURE__ */ jsx("div", { className: "progress__bar", children: /* @__PURE__ */ jsx(
2344
+ "div",
2345
+ {
2346
+ className: "progress__fill",
2347
+ style: { width: `${clampedProgress}%` }
2348
+ }
2349
+ ) }),
2350
+ /* @__PURE__ */ jsxs("div", { className: "progress__text", children: [
2351
+ /* @__PURE__ */ jsxs("span", { className: "progress__percentage", children: [
2352
+ clampedProgress,
2353
+ "%"
2354
+ ] }),
2355
+ /* @__PURE__ */ jsxs("span", { className: "progress__count", children: [
2356
+ "(",
2357
+ loaded,
2358
+ "/",
2359
+ total,
2360
+ ")"
2361
+ ] })
2362
+ ] })
2363
+ ] })
2364
+ ] }),
2365
+ /* @__PURE__ */ jsx("div", { className: "canvas-3d-loading__background", children: /* @__PURE__ */ jsx("div", { className: "bg__grid" }) })
2366
+ ] });
2367
+ }
2368
+
2369
+ // lib/debug.ts
2370
+ typeof window !== "undefined" && (localStorage.getItem("debug") === "true" || process.env.NODE_ENV === "development");
2371
+ lazy(() => import('react-markdown'));
2372
+ var GameAudioContext = createContext(null);
2373
+ GameAudioContext.displayName = "GameAudioContext";
2374
+ function detectAssetRoot2(modelUrl) {
2375
+ const idx = modelUrl.indexOf("/3d/");
2376
+ if (idx !== -1) {
2377
+ return modelUrl.substring(0, idx + 4);
2378
+ }
2379
+ return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
2380
+ }
2381
+ function createGLTFLoaderForUrl(url) {
2382
+ const loader = new GLTFLoader();
2383
+ loader.setResourcePath(detectAssetRoot2(url));
2384
+ return loader;
2385
+ }
2386
+ var AssetLoader = class {
2387
+ constructor() {
2388
+ __publicField(this, "objLoader");
2389
+ __publicField(this, "textureLoader");
2390
+ __publicField(this, "modelCache");
2391
+ __publicField(this, "textureCache");
2392
+ __publicField(this, "loadingPromises");
2393
+ this.objLoader = new OBJLoader();
2394
+ this.textureLoader = new THREE.TextureLoader();
2395
+ this.modelCache = /* @__PURE__ */ new Map();
2396
+ this.textureCache = /* @__PURE__ */ new Map();
2397
+ this.loadingPromises = /* @__PURE__ */ new Map();
2398
+ }
2399
+ /**
2400
+ * Load a GLB/GLTF model
2401
+ * @param url - URL to the .glb or .gltf file
2402
+ * @returns Promise with loaded model scene and animations
2403
+ */
2404
+ async loadModel(url) {
2405
+ if (this.modelCache.has(url)) {
2406
+ return this.modelCache.get(url);
2407
+ }
2408
+ if (this.loadingPromises.has(url)) {
2409
+ return this.loadingPromises.get(url);
2410
+ }
2411
+ const loader = createGLTFLoaderForUrl(url);
2412
+ const loadPromise = loader.loadAsync(url).then((gltf) => {
2413
+ const result = {
2414
+ scene: gltf.scene,
2415
+ animations: gltf.animations || []
2416
+ };
2417
+ this.modelCache.set(url, result);
2418
+ this.loadingPromises.delete(url);
2419
+ return result;
2420
+ }).catch((error) => {
2421
+ this.loadingPromises.delete(url);
2422
+ throw new Error(`Failed to load model ${url}: ${error.message}`);
2423
+ });
2424
+ this.loadingPromises.set(url, loadPromise);
2425
+ return loadPromise;
2426
+ }
2427
+ /**
2428
+ * Load an OBJ model (fallback for non-GLB assets)
2429
+ * @param url - URL to the .obj file
2430
+ * @returns Promise with loaded object group
2431
+ */
2432
+ async loadOBJ(url) {
2433
+ if (this.modelCache.has(url)) {
2434
+ return this.modelCache.get(url).scene;
2435
+ }
2436
+ if (this.loadingPromises.has(url)) {
2437
+ const result = await this.loadingPromises.get(url);
2438
+ return result.scene;
2439
+ }
2440
+ const loadPromise = this.objLoader.loadAsync(url).then((group) => {
2441
+ const result = {
2442
+ scene: group,
2443
+ animations: []
2444
+ };
2445
+ this.modelCache.set(url, result);
2446
+ this.loadingPromises.delete(url);
2447
+ return result;
2448
+ }).catch((error) => {
2449
+ this.loadingPromises.delete(url);
2450
+ throw new Error(`Failed to load OBJ ${url}: ${error.message}`);
2451
+ });
2452
+ this.loadingPromises.set(url, loadPromise);
2453
+ return (await loadPromise).scene;
2454
+ }
2455
+ /**
2456
+ * Load a texture
2457
+ * @param url - URL to the texture image
2458
+ * @returns Promise with loaded texture
2459
+ */
2460
+ async loadTexture(url) {
2461
+ if (this.textureCache.has(url)) {
2462
+ return this.textureCache.get(url);
2463
+ }
2464
+ if (this.loadingPromises.has(`texture:${url}`)) {
2465
+ return this.loadingPromises.get(`texture:${url}`);
2466
+ }
2467
+ const loadPromise = this.textureLoader.loadAsync(url).then((texture) => {
2468
+ texture.colorSpace = THREE.SRGBColorSpace;
2469
+ this.textureCache.set(url, texture);
2470
+ this.loadingPromises.delete(`texture:${url}`);
2471
+ return texture;
2472
+ }).catch((error) => {
2473
+ this.loadingPromises.delete(`texture:${url}`);
2474
+ throw new Error(`Failed to load texture ${url}: ${error.message}`);
2475
+ });
2476
+ this.loadingPromises.set(`texture:${url}`, loadPromise);
2477
+ return loadPromise;
2478
+ }
2479
+ /**
2480
+ * Preload multiple assets
2481
+ * @param urls - Array of asset URLs to preload
2482
+ * @returns Promise that resolves when all assets are loaded
2483
+ */
2484
+ async preload(urls) {
2485
+ const promises = urls.map((url) => {
2486
+ if (url.endsWith(".glb") || url.endsWith(".gltf")) {
2487
+ return this.loadModel(url).catch(() => null);
2488
+ } else if (url.endsWith(".obj")) {
2489
+ return this.loadOBJ(url).catch(() => null);
2490
+ } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
2491
+ return this.loadTexture(url).catch(() => null);
2492
+ }
2493
+ return Promise.resolve(null);
2494
+ });
2495
+ await Promise.all(promises);
2496
+ }
2497
+ /**
2498
+ * Check if a model is cached
2499
+ * @param url - Model URL
2500
+ */
2501
+ hasModel(url) {
2502
+ return this.modelCache.has(url);
2503
+ }
2504
+ /**
2505
+ * Check if a texture is cached
2506
+ * @param url - Texture URL
2507
+ */
2508
+ hasTexture(url) {
2509
+ return this.textureCache.has(url);
2510
+ }
2511
+ /**
2512
+ * Get cached model (throws if not cached)
2513
+ * @param url - Model URL
2514
+ */
2515
+ getModel(url) {
2516
+ const model = this.modelCache.get(url);
2517
+ if (!model) {
2518
+ throw new Error(`Model ${url} not in cache`);
2519
+ }
2520
+ return model;
2521
+ }
2522
+ /**
2523
+ * Get cached texture (throws if not cached)
2524
+ * @param url - Texture URL
2525
+ */
2526
+ getTexture(url) {
2527
+ const texture = this.textureCache.get(url);
2528
+ if (!texture) {
2529
+ throw new Error(`Texture ${url} not in cache`);
2530
+ }
2531
+ return texture;
2532
+ }
2533
+ /**
2534
+ * Clear all caches
2535
+ */
2536
+ clearCache() {
2537
+ this.textureCache.forEach((texture) => {
2538
+ texture.dispose();
2539
+ });
2540
+ this.modelCache.forEach((model) => {
2541
+ model.scene.traverse((child) => {
2542
+ if (child instanceof THREE.Mesh) {
2543
+ child.geometry.dispose();
2544
+ if (Array.isArray(child.material)) {
2545
+ child.material.forEach((m) => m.dispose());
2546
+ } else {
2547
+ child.material.dispose();
2548
+ }
2549
+ }
2550
+ });
2551
+ });
2552
+ this.modelCache.clear();
2553
+ this.textureCache.clear();
2554
+ this.loadingPromises.clear();
2555
+ }
2556
+ /**
2557
+ * Get cache statistics
2558
+ */
2559
+ getStats() {
2560
+ return {
2561
+ models: this.modelCache.size,
2562
+ textures: this.textureCache.size,
2563
+ loading: this.loadingPromises.size
2564
+ };
2565
+ }
2566
+ };
2567
+ new AssetLoader();
2568
+ function useAssetLoader(options = {}) {
2569
+ const { preloadUrls = [], loader: customLoader } = options;
2570
+ const loaderRef = useRef(customLoader || new AssetLoader());
2571
+ const [state, setState] = useState({
2572
+ isLoading: false,
2573
+ progress: 0,
2574
+ loaded: 0,
2575
+ total: 0,
2576
+ errors: []
2577
+ });
2578
+ useEffect(() => {
2579
+ if (preloadUrls.length > 0) {
2580
+ preload(preloadUrls);
2581
+ }
2582
+ }, []);
2583
+ const updateProgress = useCallback((loaded, total) => {
2584
+ setState((prev) => ({
2585
+ ...prev,
2586
+ loaded,
2587
+ total,
2588
+ progress: total > 0 ? Math.round(loaded / total * 100) : 0
2589
+ }));
2590
+ }, []);
2591
+ const loadModel = useCallback(
2592
+ async (url) => {
2593
+ setState((prev) => ({ ...prev, isLoading: true }));
2594
+ try {
2595
+ const model = await loaderRef.current.loadModel(url);
2596
+ setState((prev) => ({
2597
+ ...prev,
2598
+ isLoading: false,
2599
+ loaded: prev.loaded + 1
2600
+ }));
2601
+ return model;
2602
+ } catch (error) {
2603
+ const errorMsg = error instanceof Error ? error.message : String(error);
2604
+ setState((prev) => ({
2605
+ ...prev,
2606
+ isLoading: false,
2607
+ errors: [...prev.errors, errorMsg]
2608
+ }));
2609
+ throw error;
2610
+ }
2611
+ },
2612
+ []
2613
+ );
2614
+ const loadOBJ = useCallback(
2615
+ async (url) => {
2616
+ setState((prev) => ({ ...prev, isLoading: true }));
2617
+ try {
2618
+ const model = await loaderRef.current.loadOBJ(url);
2619
+ setState((prev) => ({
2620
+ ...prev,
2621
+ isLoading: false,
2622
+ loaded: prev.loaded + 1
2623
+ }));
2624
+ return model;
2625
+ } catch (error) {
2626
+ const errorMsg = error instanceof Error ? error.message : String(error);
2627
+ setState((prev) => ({
2628
+ ...prev,
2629
+ isLoading: false,
2630
+ errors: [...prev.errors, errorMsg]
2631
+ }));
2632
+ throw error;
2633
+ }
2634
+ },
2635
+ []
2636
+ );
2637
+ const loadTexture = useCallback(
2638
+ async (url) => {
2639
+ setState((prev) => ({ ...prev, isLoading: true }));
2640
+ try {
2641
+ const texture = await loaderRef.current.loadTexture(url);
2642
+ setState((prev) => ({
2643
+ ...prev,
2644
+ isLoading: false,
2645
+ loaded: prev.loaded + 1
2646
+ }));
2647
+ return texture;
2648
+ } catch (error) {
2649
+ const errorMsg = error instanceof Error ? error.message : String(error);
2650
+ setState((prev) => ({
2651
+ ...prev,
2652
+ isLoading: false,
2653
+ errors: [...prev.errors, errorMsg]
2654
+ }));
2655
+ throw error;
2656
+ }
2657
+ },
2658
+ []
2659
+ );
2660
+ const preload = useCallback(
2661
+ async (urls) => {
2662
+ setState((prev) => ({
2663
+ ...prev,
2664
+ isLoading: true,
2665
+ total: urls.length,
2666
+ loaded: 0,
2667
+ errors: []
2668
+ }));
2669
+ let completed = 0;
2670
+ const errors = [];
2671
+ await Promise.all(
2672
+ urls.map(async (url) => {
2673
+ try {
2674
+ if (url.endsWith(".glb") || url.endsWith(".gltf")) {
2675
+ await loaderRef.current.loadModel(url);
2676
+ } else if (url.endsWith(".obj")) {
2677
+ await loaderRef.current.loadOBJ(url);
2678
+ } else if (/\.(png|jpg|jpeg|webp)$/i.test(url)) {
2679
+ await loaderRef.current.loadTexture(url);
2680
+ }
2681
+ completed++;
2682
+ updateProgress(completed, urls.length);
2683
+ } catch (error) {
2684
+ const errorMsg = error instanceof Error ? error.message : String(error);
2685
+ errors.push(`${url}: ${errorMsg}`);
2686
+ completed++;
2687
+ updateProgress(completed, urls.length);
2688
+ }
2689
+ })
2690
+ );
2691
+ setState((prev) => ({
2692
+ ...prev,
2693
+ isLoading: false,
2694
+ errors
2695
+ }));
2696
+ },
2697
+ [updateProgress]
2698
+ );
2699
+ const hasModel = useCallback((url) => {
2700
+ return loaderRef.current.hasModel(url);
2701
+ }, []);
2702
+ const hasTexture = useCallback((url) => {
2703
+ return loaderRef.current.hasTexture(url);
2704
+ }, []);
2705
+ const getModel = useCallback((url) => {
2706
+ try {
2707
+ return loaderRef.current.getModel(url);
2708
+ } catch {
2709
+ return void 0;
2710
+ }
2711
+ }, []);
2712
+ const getTexture = useCallback((url) => {
2713
+ try {
2714
+ return loaderRef.current.getTexture(url);
2715
+ } catch {
2716
+ return void 0;
2717
+ }
2718
+ }, []);
2719
+ const clearCache = useCallback(() => {
2720
+ loaderRef.current.clearCache();
2721
+ setState({
2722
+ isLoading: false,
2723
+ progress: 0,
2724
+ loaded: 0,
2725
+ total: 0,
2726
+ errors: []
2727
+ });
2728
+ }, []);
2729
+ return {
2730
+ ...state,
2731
+ loadModel,
2732
+ loadOBJ,
2733
+ loadTexture,
2734
+ preload,
2735
+ hasModel,
2736
+ hasTexture,
2737
+ getModel,
2738
+ getTexture,
2739
+ clearCache
2740
+ };
2741
+ }
2742
+ function useGameCanvas3DEvents(options) {
2743
+ const {
2744
+ tileClickEvent,
2745
+ unitClickEvent,
2746
+ featureClickEvent,
2747
+ canvasClickEvent,
2748
+ tileHoverEvent,
2749
+ tileLeaveEvent,
2750
+ unitAnimationEvent,
2751
+ cameraChangeEvent,
2752
+ onTileClick,
2753
+ onUnitClick,
2754
+ onFeatureClick,
2755
+ onCanvasClick,
2756
+ onTileHover,
2757
+ onUnitAnimation
2758
+ } = options;
2759
+ const emit = useEmitEvent();
2760
+ const optionsRef = useRef(options);
2761
+ optionsRef.current = options;
2762
+ const handleTileClick = useCallback(
2763
+ (tile, event) => {
2764
+ if (tileClickEvent) {
2765
+ emit(tileClickEvent, {
2766
+ tileId: tile.id,
2767
+ x: tile.x,
2768
+ z: tile.z ?? tile.y ?? 0,
2769
+ type: tile.type,
2770
+ terrain: tile.terrain,
2771
+ elevation: tile.elevation
2772
+ });
2773
+ }
2774
+ optionsRef.current.onTileClick?.(tile, event);
2775
+ },
2776
+ [tileClickEvent, emit]
2777
+ );
2778
+ const handleUnitClick = useCallback(
2779
+ (unit, event) => {
2780
+ if (unitClickEvent) {
2781
+ emit(unitClickEvent, {
2782
+ unitId: unit.id,
2783
+ x: unit.x,
2784
+ z: unit.z ?? unit.y ?? 0,
2785
+ unitType: unit.unitType,
2786
+ name: unit.name,
2787
+ team: unit.team,
2788
+ faction: unit.faction,
2789
+ health: unit.health,
2790
+ maxHealth: unit.maxHealth
2791
+ });
2792
+ }
2793
+ optionsRef.current.onUnitClick?.(unit, event);
2794
+ },
2795
+ [unitClickEvent, emit]
2796
+ );
2797
+ const handleFeatureClick = useCallback(
2798
+ (feature, event) => {
2799
+ if (featureClickEvent) {
2800
+ emit(featureClickEvent, {
2801
+ featureId: feature.id,
2802
+ x: feature.x,
2803
+ z: feature.z ?? feature.y ?? 0,
2804
+ type: feature.type,
2805
+ elevation: feature.elevation
2806
+ });
2807
+ }
2808
+ optionsRef.current.onFeatureClick?.(feature, event);
2809
+ },
2810
+ [featureClickEvent, emit]
2811
+ );
2812
+ const handleCanvasClick = useCallback(
2813
+ (event) => {
2814
+ if (canvasClickEvent) {
2815
+ emit(canvasClickEvent, {
2816
+ clientX: event.clientX,
2817
+ clientY: event.clientY,
2818
+ button: event.button
2819
+ });
2820
+ }
2821
+ optionsRef.current.onCanvasClick?.(event);
2822
+ },
2823
+ [canvasClickEvent, emit]
2824
+ );
2825
+ const handleTileHover = useCallback(
2826
+ (tile, event) => {
2827
+ if (tile) {
2828
+ if (tileHoverEvent) {
2829
+ emit(tileHoverEvent, {
2830
+ tileId: tile.id,
2831
+ x: tile.x,
2832
+ z: tile.z ?? tile.y ?? 0,
2833
+ type: tile.type
2834
+ });
2835
+ }
2836
+ } else {
2837
+ if (tileLeaveEvent) {
2838
+ emit(tileLeaveEvent, {});
2839
+ }
2840
+ }
2841
+ optionsRef.current.onTileHover?.(tile, event);
2842
+ },
2843
+ [tileHoverEvent, tileLeaveEvent, emit]
2844
+ );
2845
+ const handleUnitAnimation = useCallback(
2846
+ (unitId, state) => {
2847
+ if (unitAnimationEvent) {
2848
+ emit(unitAnimationEvent, {
2849
+ unitId,
2850
+ state,
2851
+ timestamp: Date.now()
2852
+ });
2853
+ }
2854
+ optionsRef.current.onUnitAnimation?.(unitId, state);
2855
+ },
2856
+ [unitAnimationEvent, emit]
2857
+ );
2858
+ const handleCameraChange = useCallback(
2859
+ (position) => {
2860
+ if (cameraChangeEvent) {
2861
+ emit(cameraChangeEvent, {
2862
+ position,
2863
+ timestamp: Date.now()
2864
+ });
2865
+ }
2866
+ },
2867
+ [cameraChangeEvent, emit]
2868
+ );
2869
+ return {
2870
+ handleTileClick,
2871
+ handleUnitClick,
2872
+ handleFeatureClick,
2873
+ handleCanvasClick,
2874
+ handleTileHover,
2875
+ handleUnitAnimation,
2876
+ handleCameraChange
2877
+ };
2878
+ }
2879
+ function detectAssetRoot3(modelUrl) {
2880
+ const idx = modelUrl.indexOf("/3d/");
2881
+ if (idx !== -1) {
2882
+ return modelUrl.substring(0, idx + 4);
2883
+ }
2884
+ return modelUrl.substring(0, modelUrl.lastIndexOf("/") + 1);
2885
+ }
2886
+ function useGLTFModel2(url, resourceBasePath) {
2887
+ const [state, setState] = useState({
2888
+ model: null,
2889
+ isLoading: false,
2890
+ error: null
2891
+ });
2892
+ useEffect(() => {
2893
+ if (!url) {
2894
+ setState({ model: null, isLoading: false, error: null });
2895
+ return;
2896
+ }
2897
+ console.log("[ModelLoader] Loading:", url);
2898
+ setState((prev) => ({ ...prev, isLoading: true, error: null }));
2899
+ const assetRoot = resourceBasePath || detectAssetRoot3(url);
2900
+ const loader = new GLTFLoader$1();
2901
+ loader.setResourcePath(assetRoot);
2902
+ loader.load(
2903
+ url,
2904
+ (gltf) => {
2905
+ console.log("[ModelLoader] Loaded:", url);
2906
+ setState({
2907
+ model: gltf.scene,
2908
+ isLoading: false,
2909
+ error: null
2910
+ });
2911
+ },
2912
+ void 0,
2913
+ (err) => {
2914
+ const errorMsg = err instanceof Error ? err.message : String(err);
2915
+ console.warn("[ModelLoader] Failed:", url, errorMsg);
2916
+ setState({
2917
+ model: null,
2918
+ isLoading: false,
2919
+ error: err instanceof Error ? err : new Error(String(err))
2920
+ });
2921
+ }
2922
+ );
2923
+ }, [url, resourceBasePath]);
2924
+ return state;
2925
+ }
2926
+ function ModelLoader({
2927
+ url,
2928
+ position = [0, 0, 0],
2929
+ scale = 1,
2930
+ rotation = [0, 0, 0],
2931
+ isSelected = false,
2932
+ isHovered = false,
2933
+ onClick,
2934
+ onHover,
2935
+ fallbackGeometry = "box",
2936
+ castShadow = true,
2937
+ receiveShadow = true,
2938
+ resourceBasePath
2939
+ }) {
2940
+ const { model: loadedModel, isLoading, error } = useGLTFModel2(url, resourceBasePath);
2941
+ const model = useMemo(() => {
2942
+ if (!loadedModel) return null;
2943
+ const cloned = loadedModel.clone();
2944
+ cloned.traverse((child) => {
2945
+ if (child instanceof THREE.Mesh) {
2946
+ child.castShadow = castShadow;
2947
+ child.receiveShadow = receiveShadow;
2948
+ }
2949
+ });
2950
+ return cloned;
2951
+ }, [loadedModel, castShadow, receiveShadow]);
2952
+ const scaleArray = useMemo(() => {
2953
+ if (typeof scale === "number") {
2954
+ return [scale, scale, scale];
2955
+ }
2956
+ return scale;
2957
+ }, [scale]);
2958
+ const rotationRad = useMemo(() => {
2959
+ return [
2960
+ rotation[0] * Math.PI / 180,
2961
+ rotation[1] * Math.PI / 180,
2962
+ rotation[2] * Math.PI / 180
2963
+ ];
2964
+ }, [rotation]);
2965
+ if (isLoading) {
2966
+ return /* @__PURE__ */ jsx("group", { position, children: /* @__PURE__ */ jsxs("mesh", { rotation: [Math.PI / 2, 0, 0], children: [
2967
+ /* @__PURE__ */ jsx("ringGeometry", { args: [0.3, 0.35, 16] }),
2968
+ /* @__PURE__ */ jsx("meshBasicMaterial", { color: "#4a90d9", transparent: true, opacity: 0.8 })
2969
+ ] }) });
2970
+ }
2971
+ if (error || !model) {
2972
+ if (fallbackGeometry === "none") {
2973
+ return /* @__PURE__ */ jsx("group", { position });
2974
+ }
2975
+ const fallbackProps = {
2976
+ onClick,
2977
+ onPointerOver: () => onHover?.(true),
2978
+ onPointerOut: () => onHover?.(false)
2979
+ };
2980
+ return /* @__PURE__ */ jsxs("group", { position, children: [
2981
+ (isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
2982
+ /* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
2983
+ /* @__PURE__ */ jsx(
2984
+ "meshBasicMaterial",
2985
+ {
2986
+ color: isSelected ? 16755200 : 16777215,
2987
+ transparent: true,
2988
+ opacity: 0.5
2989
+ }
2990
+ )
2991
+ ] }),
2992
+ fallbackGeometry === "box" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
2993
+ /* @__PURE__ */ jsx("boxGeometry", { args: [0.8, 0.8, 0.8] }),
2994
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
2995
+ ] }),
2996
+ fallbackGeometry === "sphere" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
2997
+ /* @__PURE__ */ jsx("sphereGeometry", { args: [0.4, 16, 16] }),
2998
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
2999
+ ] }),
3000
+ fallbackGeometry === "cylinder" && /* @__PURE__ */ jsxs("mesh", { ...fallbackProps, position: [0, 0.5, 0], children: [
3001
+ /* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.8, 16] }),
3002
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color: error ? 16729156 : 8947848 })
3003
+ ] })
3004
+ ] });
3005
+ }
3006
+ return /* @__PURE__ */ jsxs(
3007
+ "group",
3008
+ {
3009
+ position,
3010
+ rotation: rotationRad,
3011
+ onClick,
3012
+ onPointerOver: () => onHover?.(true),
3013
+ onPointerOut: () => onHover?.(false),
3014
+ children: [
3015
+ (isSelected || isHovered) && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.02, 0], rotation: [-Math.PI / 2, 0, 0], children: [
3016
+ /* @__PURE__ */ jsx("ringGeometry", { args: [0.6, 0.7, 32] }),
3017
+ /* @__PURE__ */ jsx(
3018
+ "meshBasicMaterial",
3019
+ {
3020
+ color: isSelected ? 16755200 : 16777215,
3021
+ transparent: true,
3022
+ opacity: 0.5
3023
+ }
3024
+ )
3025
+ ] }),
3026
+ /* @__PURE__ */ jsx("primitive", { object: model, scale: scaleArray })
3027
+ ]
3028
+ }
3029
+ );
3030
+ }
3031
+ var DEFAULT_GRID_CONFIG = {
3032
+ cellSize: 1,
3033
+ offsetX: 0,
3034
+ offsetZ: 0
3035
+ };
3036
+ function CameraController({
3037
+ onCameraChange
3038
+ }) {
3039
+ const { camera } = useThree();
3040
+ useEffect(() => {
3041
+ if (onCameraChange) {
3042
+ onCameraChange({
3043
+ x: camera.position.x,
3044
+ y: camera.position.y,
3045
+ z: camera.position.z
3046
+ });
3047
+ }
3048
+ }, [camera.position, onCameraChange]);
3049
+ return null;
3050
+ }
3051
+ var GameCanvas3D = forwardRef(
3052
+ ({
3053
+ tiles = [],
3054
+ units = [],
3055
+ features = [],
3056
+ events: events2 = [],
3057
+ orientation = "standard",
3058
+ cameraMode = "isometric",
3059
+ showGrid = true,
3060
+ showCoordinates = false,
3061
+ showTileInfo = false,
3062
+ overlay = "default",
3063
+ shadows = true,
3064
+ backgroundColor = "#1a1a2e",
3065
+ onTileClick,
3066
+ onUnitClick,
3067
+ onFeatureClick,
3068
+ onCanvasClick,
3069
+ onTileHover,
3070
+ onUnitAnimation,
3071
+ assetLoader: customAssetLoader,
3072
+ tileRenderer: CustomTileRenderer,
3073
+ unitRenderer: CustomUnitRenderer,
3074
+ featureRenderer: CustomFeatureRenderer,
3075
+ className,
3076
+ isLoading: externalLoading,
3077
+ error: externalError,
3078
+ entity,
3079
+ preloadAssets = [],
3080
+ tileClickEvent,
3081
+ unitClickEvent,
3082
+ featureClickEvent,
3083
+ canvasClickEvent,
3084
+ tileHoverEvent,
3085
+ tileLeaveEvent,
3086
+ unitAnimationEvent,
3087
+ cameraChangeEvent,
3088
+ loadingMessage = "Loading 3D Scene...",
3089
+ useInstancing = true,
3090
+ validMoves = [],
3091
+ attackTargets = [],
3092
+ selectedTileIds = [],
3093
+ selectedUnitId = null,
3094
+ children
3095
+ }, ref) => {
3096
+ const containerRef = useRef(null);
3097
+ const controlsRef = useRef(null);
3098
+ const [hoveredTile, setHoveredTile] = useState(null);
3099
+ const [internalError, setInternalError] = useState(null);
3100
+ const { isLoading: assetsLoading, progress, loaded, total } = useAssetLoader({
3101
+ preloadUrls: preloadAssets,
3102
+ loader: customAssetLoader
3103
+ });
3104
+ const eventHandlers = useGameCanvas3DEvents({
3105
+ tileClickEvent,
3106
+ unitClickEvent,
3107
+ featureClickEvent,
3108
+ canvasClickEvent,
3109
+ tileHoverEvent,
3110
+ tileLeaveEvent,
3111
+ unitAnimationEvent,
3112
+ cameraChangeEvent,
3113
+ onTileClick,
3114
+ onUnitClick,
3115
+ onFeatureClick,
3116
+ onCanvasClick,
3117
+ onTileHover,
3118
+ onUnitAnimation
3119
+ });
3120
+ const gridBounds = useMemo(() => {
3121
+ if (tiles.length === 0) {
3122
+ return { minX: 0, maxX: 10, minZ: 0, maxZ: 10 };
3123
+ }
3124
+ const xs = tiles.map((t) => t.x);
3125
+ const zs = tiles.map((t) => t.z || t.y || 0);
3126
+ return {
3127
+ minX: Math.min(...xs),
3128
+ maxX: Math.max(...xs),
3129
+ minZ: Math.min(...zs),
3130
+ maxZ: Math.max(...zs)
3131
+ };
3132
+ }, [tiles]);
3133
+ const cameraTarget = useMemo(() => {
3134
+ return [
3135
+ (gridBounds.minX + gridBounds.maxX) / 2,
3136
+ 0,
3137
+ (gridBounds.minZ + gridBounds.maxZ) / 2
3138
+ ];
3139
+ }, [gridBounds]);
3140
+ const gridConfig = useMemo(
3141
+ () => ({
3142
+ ...DEFAULT_GRID_CONFIG,
3143
+ offsetX: -(gridBounds.maxX - gridBounds.minX) / 2,
3144
+ offsetZ: -(gridBounds.maxZ - gridBounds.minZ) / 2
3145
+ }),
3146
+ [gridBounds]
3147
+ );
3148
+ const gridToWorld = useCallback(
3149
+ (x, z, y = 0) => {
3150
+ const worldX = (x - gridBounds.minX) * gridConfig.cellSize;
3151
+ const worldZ = (z - gridBounds.minZ) * gridConfig.cellSize;
3152
+ return [worldX, y * gridConfig.cellSize, worldZ];
3153
+ },
3154
+ [gridBounds, gridConfig]
3155
+ );
3156
+ useImperativeHandle(ref, () => ({
3157
+ getCameraPosition: () => {
3158
+ if (controlsRef.current) {
3159
+ const pos = controlsRef.current.object.position;
3160
+ return new THREE.Vector3(pos.x, pos.y, pos.z);
3161
+ }
3162
+ return null;
3163
+ },
3164
+ setCameraPosition: (x, y, z) => {
3165
+ if (controlsRef.current) {
3166
+ controlsRef.current.object.position.set(x, y, z);
3167
+ controlsRef.current.update();
3168
+ }
3169
+ },
3170
+ lookAt: (x, y, z) => {
3171
+ if (controlsRef.current) {
3172
+ controlsRef.current.target.set(x, y, z);
3173
+ controlsRef.current.update();
3174
+ }
3175
+ },
3176
+ resetCamera: () => {
3177
+ if (controlsRef.current) {
3178
+ controlsRef.current.reset();
3179
+ }
3180
+ },
3181
+ screenshot: () => {
3182
+ const canvas = containerRef.current?.querySelector("canvas");
3183
+ if (canvas) {
3184
+ return canvas.toDataURL("image/png");
3185
+ }
3186
+ return null;
3187
+ },
3188
+ export: () => ({
3189
+ tiles,
3190
+ units,
3191
+ features
3192
+ })
3193
+ }));
3194
+ const handleTileClick = useCallback(
3195
+ (tile, event) => {
3196
+ eventHandlers.handleTileClick(tile, event);
3197
+ },
3198
+ [eventHandlers]
3199
+ );
3200
+ const handleUnitClick = useCallback(
3201
+ (unit, event) => {
3202
+ eventHandlers.handleUnitClick(unit, event);
3203
+ },
3204
+ [eventHandlers]
3205
+ );
3206
+ const handleFeatureClick = useCallback(
3207
+ (feature, event) => {
3208
+ if (event) {
3209
+ eventHandlers.handleFeatureClick(feature, event);
3210
+ }
3211
+ },
3212
+ [eventHandlers]
3213
+ );
3214
+ const handleTileHover = useCallback(
3215
+ (tile, event) => {
3216
+ setHoveredTile(tile);
3217
+ if (event) {
3218
+ eventHandlers.handleTileHover(tile, event);
3219
+ }
3220
+ },
3221
+ [eventHandlers]
3222
+ );
3223
+ const cameraConfig = useMemo(() => {
3224
+ const size = Math.max(
3225
+ gridBounds.maxX - gridBounds.minX,
3226
+ gridBounds.maxZ - gridBounds.minZ
3227
+ );
3228
+ const distance = size * 1.5;
3229
+ switch (cameraMode) {
3230
+ case "isometric":
3231
+ return {
3232
+ position: [distance, distance * 0.8, distance],
3233
+ fov: 45
3234
+ };
3235
+ case "top-down":
3236
+ return {
3237
+ position: [0, distance * 2, 0],
3238
+ fov: 45
3239
+ };
3240
+ case "perspective":
3241
+ default:
3242
+ return {
3243
+ position: [distance, distance, distance],
3244
+ fov: 45
3245
+ };
3246
+ }
3247
+ }, [cameraMode, gridBounds]);
3248
+ const DefaultTileRenderer = useCallback(
3249
+ ({ tile, position }) => {
3250
+ const isSelected = tile.id ? selectedTileIds.includes(tile.id) : false;
3251
+ const isHovered = hoveredTile?.id === tile.id;
3252
+ const isValidMove = validMoves.some(
3253
+ (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
3254
+ );
3255
+ const isAttackTarget = attackTargets.some(
3256
+ (m) => m.x === tile.x && m.z === (tile.z ?? tile.y ?? 0)
3257
+ );
3258
+ let color = 8421504;
3259
+ if (tile.type === "water") color = 4491468;
3260
+ else if (tile.type === "grass") color = 4500036;
3261
+ else if (tile.type === "sand") color = 14535816;
3262
+ else if (tile.type === "rock") color = 8947848;
3263
+ else if (tile.type === "snow") color = 15658734;
3264
+ let emissive = 0;
3265
+ if (isSelected) emissive = 4473924;
3266
+ else if (isAttackTarget) emissive = 4456448;
3267
+ else if (isValidMove) emissive = 17408;
3268
+ else if (isHovered) emissive = 2236962;
3269
+ return /* @__PURE__ */ jsxs(
3270
+ "mesh",
3271
+ {
3272
+ position,
3273
+ onClick: (e) => handleTileClick(tile, e),
3274
+ onPointerEnter: (e) => handleTileHover(tile, e),
3275
+ onPointerLeave: (e) => handleTileHover(null, e),
3276
+ userData: { type: "tile", tileId: tile.id, gridX: tile.x, gridZ: tile.z ?? tile.y },
3277
+ children: [
3278
+ /* @__PURE__ */ jsx("boxGeometry", { args: [0.95, 0.2, 0.95] }),
3279
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color, emissive })
3280
+ ]
3281
+ }
3282
+ );
3283
+ },
3284
+ [selectedTileIds, hoveredTile, validMoves, attackTargets, handleTileClick, handleTileHover]
3285
+ );
3286
+ const DefaultUnitRenderer = useCallback(
3287
+ ({ unit, position }) => {
3288
+ const isSelected = selectedUnitId === unit.id;
3289
+ const color = unit.faction === "player" ? 4491519 : unit.faction === "enemy" ? 16729156 : 16777028;
3290
+ return /* @__PURE__ */ jsxs(
3291
+ "group",
3292
+ {
3293
+ position,
3294
+ onClick: (e) => handleUnitClick(unit, e),
3295
+ userData: { type: "unit", unitId: unit.id },
3296
+ children: [
3297
+ isSelected && /* @__PURE__ */ jsxs("mesh", { position: [0, 0.05, 0], rotation: [-Math.PI / 2, 0, 0], children: [
3298
+ /* @__PURE__ */ jsx("ringGeometry", { args: [0.4, 0.5, 32] }),
3299
+ /* @__PURE__ */ jsx("meshBasicMaterial", { color: "#ffff00", transparent: true, opacity: 0.8 })
3300
+ ] }),
3301
+ /* @__PURE__ */ jsxs("mesh", { position: [0, 0.3, 0], children: [
3302
+ /* @__PURE__ */ jsx("cylinderGeometry", { args: [0.3, 0.3, 0.1, 8] }),
3303
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color })
3304
+ ] }),
3305
+ /* @__PURE__ */ jsxs("mesh", { position: [0, 0.6, 0], children: [
3306
+ /* @__PURE__ */ jsx("capsuleGeometry", { args: [0.2, 0.4, 4, 8] }),
3307
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color })
3308
+ ] }),
3309
+ /* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
3310
+ /* @__PURE__ */ jsx("sphereGeometry", { args: [0.12, 8, 8] }),
3311
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color })
3312
+ ] }),
3313
+ unit.health !== void 0 && unit.maxHealth !== void 0 && /* @__PURE__ */ jsxs("group", { position: [0, 1.2, 0], children: [
3314
+ /* @__PURE__ */ jsxs("mesh", { position: [-0.25, 0, 0], children: [
3315
+ /* @__PURE__ */ jsx("planeGeometry", { args: [0.5, 0.05] }),
3316
+ /* @__PURE__ */ jsx("meshBasicMaterial", { color: 3355443 })
3317
+ ] }),
3318
+ /* @__PURE__ */ jsxs(
3319
+ "mesh",
3320
+ {
3321
+ position: [
3322
+ -0.25 + 0.5 * (unit.health / unit.maxHealth) / 2,
3323
+ 0,
3324
+ 0.01
3325
+ ],
3326
+ children: [
3327
+ /* @__PURE__ */ jsx("planeGeometry", { args: [0.5 * (unit.health / unit.maxHealth), 0.05] }),
3328
+ /* @__PURE__ */ jsx(
3329
+ "meshBasicMaterial",
3330
+ {
3331
+ color: unit.health / unit.maxHealth > 0.5 ? 4500036 : unit.health / unit.maxHealth > 0.25 ? 11184708 : 16729156
3332
+ }
3333
+ )
3334
+ ]
3335
+ }
3336
+ )
3337
+ ] })
3338
+ ]
3339
+ }
3340
+ );
3341
+ },
3342
+ [selectedUnitId, handleUnitClick]
3343
+ );
3344
+ const DefaultFeatureRenderer = useCallback(
3345
+ ({
3346
+ feature,
3347
+ position
3348
+ }) => {
3349
+ if (feature.assetUrl) {
3350
+ return /* @__PURE__ */ jsx(
3351
+ ModelLoader,
3352
+ {
3353
+ url: feature.assetUrl,
3354
+ position,
3355
+ scale: 0.5,
3356
+ rotation: [0, feature.rotation ?? 0, 0],
3357
+ onClick: () => handleFeatureClick(feature, null),
3358
+ fallbackGeometry: "box"
3359
+ },
3360
+ feature.id
3361
+ );
3362
+ }
3363
+ if (feature.type === "tree") {
3364
+ return /* @__PURE__ */ jsxs(
3365
+ "group",
3366
+ {
3367
+ position,
3368
+ onClick: (e) => handleFeatureClick(feature, e),
3369
+ userData: { type: "feature", featureId: feature.id },
3370
+ children: [
3371
+ /* @__PURE__ */ jsxs("mesh", { position: [0, 0.4, 0], children: [
3372
+ /* @__PURE__ */ jsx("cylinderGeometry", { args: [0.1, 0.15, 0.8, 6] }),
3373
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color: 9127187 })
3374
+ ] }),
3375
+ /* @__PURE__ */ jsxs("mesh", { position: [0, 0.9, 0], children: [
3376
+ /* @__PURE__ */ jsx("coneGeometry", { args: [0.5, 0.8, 8] }),
3377
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color: 2263842 })
3378
+ ] })
3379
+ ]
3380
+ }
3381
+ );
3382
+ }
3383
+ if (feature.type === "rock") {
3384
+ return /* @__PURE__ */ jsxs(
3385
+ "mesh",
3386
+ {
3387
+ position: [position[0], position[1] + 0.3, position[2]],
3388
+ onClick: (e) => handleFeatureClick(feature, e),
3389
+ userData: { type: "feature", featureId: feature.id },
3390
+ children: [
3391
+ /* @__PURE__ */ jsx("dodecahedronGeometry", { args: [0.3, 0] }),
3392
+ /* @__PURE__ */ jsx("meshStandardMaterial", { color: 8421504 })
3393
+ ]
3394
+ }
3395
+ );
3396
+ }
3397
+ return null;
3398
+ },
3399
+ [handleFeatureClick]
3400
+ );
3401
+ if (externalLoading || assetsLoading && preloadAssets.length > 0) {
3402
+ return /* @__PURE__ */ jsx(
3403
+ Canvas3DLoadingState,
3404
+ {
3405
+ progress,
3406
+ loaded,
3407
+ total,
3408
+ message: loadingMessage,
3409
+ className
3410
+ }
3411
+ );
3412
+ }
3413
+ const displayError = externalError || internalError;
3414
+ if (displayError) {
3415
+ 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: [
3416
+ "Error: ",
3417
+ displayError
3418
+ ] }) }) });
3419
+ }
3420
+ return /* @__PURE__ */ jsx(
3421
+ Canvas3DErrorBoundary,
3422
+ {
3423
+ onError: (err) => setInternalError(err.message),
3424
+ onReset: () => setInternalError(null),
3425
+ children: /* @__PURE__ */ jsxs(
3426
+ "div",
3427
+ {
3428
+ ref: containerRef,
3429
+ className: `game-canvas-3d ${className || ""}`,
3430
+ "data-orientation": orientation,
3431
+ "data-camera-mode": cameraMode,
3432
+ "data-overlay": overlay,
3433
+ children: [
3434
+ /* @__PURE__ */ jsxs(
3435
+ Canvas,
3436
+ {
3437
+ shadows,
3438
+ camera: {
3439
+ position: cameraConfig.position,
3440
+ fov: cameraConfig.fov,
3441
+ near: 0.1,
3442
+ far: 1e3
3443
+ },
3444
+ style: { background: backgroundColor },
3445
+ onClick: (e) => {
3446
+ if (e.target === e.currentTarget) {
3447
+ eventHandlers.handleCanvasClick(e);
3448
+ }
3449
+ },
3450
+ children: [
3451
+ /* @__PURE__ */ jsx(CameraController, { onCameraChange: eventHandlers.handleCameraChange }),
3452
+ /* @__PURE__ */ jsx("ambientLight", { intensity: 0.6 }),
3453
+ /* @__PURE__ */ jsx(
3454
+ "directionalLight",
3455
+ {
3456
+ position: [10, 20, 10],
3457
+ intensity: 0.8,
3458
+ castShadow: shadows,
3459
+ "shadow-mapSize": [2048, 2048]
3460
+ }
3461
+ ),
3462
+ /* @__PURE__ */ jsx("hemisphereLight", { intensity: 0.3, color: "#87ceeb", groundColor: "#362d1d" }),
3463
+ showGrid && /* @__PURE__ */ jsx(
3464
+ Grid,
3465
+ {
3466
+ args: [
3467
+ Math.max(gridBounds.maxX - gridBounds.minX + 2, 10),
3468
+ Math.max(gridBounds.maxZ - gridBounds.minZ + 2, 10)
3469
+ ],
3470
+ position: [
3471
+ (gridBounds.maxX - gridBounds.minX) / 2 - 0.5,
3472
+ 0,
3473
+ (gridBounds.maxZ - gridBounds.minZ) / 2 - 0.5
3474
+ ],
3475
+ cellSize: 1,
3476
+ cellThickness: 1,
3477
+ cellColor: "#444444",
3478
+ sectionSize: 5,
3479
+ sectionThickness: 1.5,
3480
+ sectionColor: "#666666",
3481
+ fadeDistance: 50,
3482
+ fadeStrength: 1
3483
+ }
3484
+ ),
3485
+ tiles.map((tile, index) => {
3486
+ const position = gridToWorld(
3487
+ tile.x,
3488
+ tile.z ?? tile.y ?? 0,
3489
+ tile.elevation ?? 0
3490
+ );
3491
+ const Renderer = CustomTileRenderer || DefaultTileRenderer;
3492
+ return /* @__PURE__ */ jsx(Renderer, { tile, position }, tile.id ?? `tile-${index}`);
3493
+ }),
3494
+ features.map((feature, index) => {
3495
+ const position = gridToWorld(
3496
+ feature.x,
3497
+ feature.z ?? feature.y ?? 0,
3498
+ (feature.elevation ?? 0) + 0.5
3499
+ );
3500
+ const Renderer = CustomFeatureRenderer || DefaultFeatureRenderer;
3501
+ return /* @__PURE__ */ jsx(Renderer, { feature, position }, feature.id ?? `feature-${index}`);
3502
+ }),
3503
+ units.map((unit) => {
3504
+ const position = gridToWorld(
3505
+ unit.x ?? 0,
3506
+ unit.z ?? unit.y ?? 0,
3507
+ (unit.elevation ?? 0) + 0.5
3508
+ );
3509
+ const Renderer = CustomUnitRenderer || DefaultUnitRenderer;
3510
+ return /* @__PURE__ */ jsx(Renderer, { unit, position }, unit.id);
3511
+ }),
3512
+ children,
3513
+ /* @__PURE__ */ jsx(
3514
+ OrbitControls,
3515
+ {
3516
+ ref: controlsRef,
3517
+ target: cameraTarget,
3518
+ enableDamping: true,
3519
+ dampingFactor: 0.05,
3520
+ minDistance: 2,
3521
+ maxDistance: 100,
3522
+ maxPolarAngle: Math.PI / 2 - 0.1
3523
+ }
3524
+ )
3525
+ ]
3526
+ }
3527
+ ),
3528
+ showCoordinates && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__coordinates", children: [
3529
+ "X: ",
3530
+ hoveredTile.x,
3531
+ ", Z: ",
3532
+ hoveredTile.z ?? hoveredTile.y ?? 0
3533
+ ] }),
3534
+ showTileInfo && hoveredTile && /* @__PURE__ */ jsxs("div", { className: "game-canvas-3d__tile-info", children: [
3535
+ /* @__PURE__ */ jsx("div", { className: "tile-info__type", children: hoveredTile.type }),
3536
+ hoveredTile.terrain && /* @__PURE__ */ jsx("div", { className: "tile-info__terrain", children: hoveredTile.terrain })
3537
+ ] })
3538
+ ]
3539
+ }
3540
+ )
3541
+ }
3542
+ );
3543
+ }
3544
+ );
3545
+ GameCanvas3D.displayName = "GameCanvas3D";
3546
+
3547
+ // lib/traitRegistry.ts
3548
+ var traits = /* @__PURE__ */ new Map();
3549
+ var listeners2 = /* @__PURE__ */ new Set();
3550
+ function notifyListeners2() {
3551
+ listeners2.forEach((listener) => listener());
3552
+ }
3553
+ function registerTrait(info) {
3554
+ traits.set(info.id, info);
3555
+ notifyListeners2();
3556
+ }
3557
+ function updateTraitState(id, newState) {
3558
+ const trait = traits.get(id);
3559
+ if (trait) {
3560
+ trait.currentState = newState;
3561
+ trait.transitionCount++;
3562
+ notifyListeners2();
3563
+ }
3564
+ }
3565
+ function unregisterTrait(id) {
3566
+ traits.delete(id);
3567
+ notifyListeners2();
3568
+ }
3569
+ createContext({ enabled: false });
3570
+ createContext(false);
3571
+ createContext(null);
20
3572
 
21
3573
  // runtime/createClientEffectHandlers.ts
22
3574
  function createClientEffectHandlers(options) {
@@ -467,6 +4019,50 @@ function useTraitStateMachine(traitBindings, slotsActions, options) {
467
4019
  fetchedDataContext.setData({ [linkedEntity]: updated });
468
4020
  }
469
4021
  }
4022
+ if (fetchedDataContext) {
4023
+ for (const effect of result.effects) {
4024
+ if (!Array.isArray(effect) || effect[0] !== "persist") continue;
4025
+ const action = effect[1];
4026
+ const entityType = effect[2] || linkedEntity;
4027
+ if (!entityType) continue;
4028
+ const records = fetchedDataContext.getData(entityType);
4029
+ if (action === "create") {
4030
+ const evalCtx = createContextFromBindings(bindingCtx);
4031
+ const rawData = effect[3];
4032
+ const newRecord = { id: `${entityType}-${Date.now()}` };
4033
+ if (rawData) {
4034
+ for (const [k, v] of Object.entries(rawData)) {
4035
+ newRecord[k] = interpolateValue(v, evalCtx);
4036
+ }
4037
+ }
4038
+ for (const [k, v] of entityMutations) {
4039
+ newRecord[k] = v;
4040
+ }
4041
+ fetchedDataContext.setData({ [entityType]: [...records, newRecord] });
4042
+ } else if (action === "delete") {
4043
+ const deleteId = effect[3];
4044
+ if (deleteId) {
4045
+ const filtered = records.filter((r) => r.id !== deleteId);
4046
+ fetchedDataContext.setData({ [entityType]: filtered });
4047
+ }
4048
+ } else if (action === "update") {
4049
+ const updateId = effect[3];
4050
+ const updateData = effect[4];
4051
+ if (updateId && updateData) {
4052
+ const evalCtx = createContextFromBindings(bindingCtx);
4053
+ const updated = records.map((r) => {
4054
+ if (r.id !== updateId) return r;
4055
+ const patched = { ...r };
4056
+ for (const [k, v] of Object.entries(updateData)) {
4057
+ patched[k] = interpolateValue(v, evalCtx);
4058
+ }
4059
+ return patched;
4060
+ });
4061
+ fetchedDataContext.setData({ [entityType]: updated });
4062
+ }
4063
+ }
4064
+ }
4065
+ }
470
4066
  } catch (error) {
471
4067
  console.error(
472
4068
  "[TraitStateMachine] Effect execution error:",
@@ -630,7 +4226,7 @@ function useResolvedSchema(schema, pageName) {
630
4226
  }
631
4227
  const page = getPage(ir, pageName);
632
4228
  console.log("[useResolvedSchema] Resolved page:", page?.name, "| path:", page?.path, "| traits:", page?.traits.length);
633
- const traits = page?.traits || [];
4229
+ const traits2 = page?.traits || [];
634
4230
  const entities = /* @__PURE__ */ new Map();
635
4231
  if (page) {
636
4232
  for (const binding of page.entityBindings) {
@@ -639,7 +4235,7 @@ function useResolvedSchema(schema, pageName) {
639
4235
  }
640
4236
  return {
641
4237
  page,
642
- traits,
4238
+ traits: traits2,
643
4239
  entities,
644
4240
  allEntities: ir.entities,
645
4241
  allTraits: ir.traits,