@almadar/ui 1.0.20 → 1.0.21

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.
@@ -11,7 +11,7 @@ export { DEFAULT_SLOTS, useUISlotManager } from '../chunk-7NEWMNNU.js';
11
11
  export { clearEntities, getAllEntities, getByType, getEntity, getSingleton, removeEntity, spawnEntity, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
12
12
  import '../chunk-PKBMQBKP.js';
13
13
  import * as React37 from 'react';
14
- import React37__default, { useMemo, useState, useEffect, useCallback, useRef } from 'react';
14
+ import React37__default, { useCallback, useMemo, useState, useEffect, useRef } from 'react';
15
15
  import * as LucideIcons from 'lucide-react';
16
16
  import { Loader2, ChevronDown, X, User, Sun, Moon, FileQuestion, Inbox, Search, Info, AlertCircle, XCircle, CheckCircle, AlertTriangle, ChevronRight, Filter, Plus, ChevronLeft, Check, ChevronUp, MoreHorizontal, TrendingUp, TrendingDown, Minus, ArrowLeft, Menu, ArrowUp, ArrowDown, MoreVertical, Package, Trash2, Circle, Clock, CheckCircle2, Image as Image$1, Upload, ZoomIn, Eraser, FileText, ZoomOut, Download, Printer, RotateCcw, Code, WrapText, Copy, Settings, Bell, LogOut, Pause, Play, RefreshCw, Eye, Edit, Calendar, Pencil, Undo2, Save, Tag, DollarSign, Send, ListTodo } from 'lucide-react';
17
17
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -88,11 +88,22 @@ var Button = React37__default.forwardRef(
88
88
  rightIcon,
89
89
  icon: IconComponent,
90
90
  iconRight: IconRightComponent,
91
+ action,
92
+ actionPayload,
93
+ label,
91
94
  children,
95
+ onClick,
92
96
  ...props
93
97
  }, ref) => {
98
+ const eventBus = useEventBus();
94
99
  const resolvedLeftIcon = leftIcon || IconComponent && /* @__PURE__ */ jsx(IconComponent, { className: iconSizeStyles[size] });
95
100
  const resolvedRightIcon = rightIcon || IconRightComponent && /* @__PURE__ */ jsx(IconRightComponent, { className: iconSizeStyles[size] });
101
+ const handleClick = (e) => {
102
+ if (action) {
103
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
104
+ }
105
+ onClick?.(e);
106
+ };
96
107
  return /* @__PURE__ */ jsxs(
97
108
  "button",
98
109
  {
@@ -109,10 +120,11 @@ var Button = React37__default.forwardRef(
109
120
  sizeStyles[size],
110
121
  className
111
122
  ),
123
+ onClick: handleClick,
112
124
  ...props,
113
125
  children: [
114
126
  isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }) : resolvedLeftIcon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedLeftIcon }),
115
- children,
127
+ children || label,
116
128
  resolvedRightIcon && !isLoading && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: resolvedRightIcon })
117
129
  ]
118
130
  }
@@ -567,13 +579,23 @@ var Avatar = ({
567
579
  status,
568
580
  badge,
569
581
  className,
570
- onClick
582
+ onClick,
583
+ action,
584
+ actionPayload
571
585
  }) => {
586
+ const eventBus = useEventBus();
572
587
  const initials = providedInitials ?? (name ? generateInitials(name) : void 0);
573
588
  const hasImage = !!src;
574
589
  const hasInitials = !!initials;
575
590
  const hasIcon = !!Icon2;
576
591
  const getInitialsBackground = () => "bg-[var(--color-primary)] text-[var(--color-primary-foreground)]";
592
+ const isClickable = action || onClick;
593
+ const handleClick = () => {
594
+ if (action) {
595
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
596
+ }
597
+ onClick?.();
598
+ };
577
599
  return /* @__PURE__ */ jsxs("div", { className: "relative inline-block", children: [
578
600
  /* @__PURE__ */ jsx(
579
601
  "div",
@@ -583,12 +605,12 @@ var Avatar = ({
583
605
  "bg-[var(--color-muted)] border-[length:var(--border-width)] border-[var(--color-border)]",
584
606
  "overflow-hidden",
585
607
  sizeClasses[size],
586
- onClick && "cursor-pointer hover:bg-[var(--color-surface-hover)] transition-colors",
608
+ isClickable && "cursor-pointer hover:bg-[var(--color-surface-hover)] transition-colors",
587
609
  className
588
610
  ),
589
- onClick,
590
- role: onClick ? "button" : void 0,
591
- tabIndex: onClick ? 0 : void 0,
611
+ onClick: isClickable ? handleClick : void 0,
612
+ role: isClickable ? "button" : void 0,
613
+ tabIndex: isClickable ? 0 : void 0,
592
614
  children: hasImage ? /* @__PURE__ */ jsx(
593
615
  "img",
594
616
  {
@@ -777,9 +799,34 @@ var Box = React37__default.forwardRef(
777
799
  className,
778
800
  children,
779
801
  as: Component = "div",
802
+ action,
803
+ actionPayload,
804
+ hoverEvent,
780
805
  onClick,
806
+ onMouseEnter,
807
+ onMouseLeave,
781
808
  ...rest
782
809
  }, ref) => {
810
+ const eventBus = useEventBus();
811
+ const handleClick = useCallback((e) => {
812
+ if (action) {
813
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
814
+ }
815
+ onClick?.(e);
816
+ }, [action, actionPayload, eventBus, onClick]);
817
+ const handleMouseEnter = useCallback((e) => {
818
+ if (hoverEvent) {
819
+ eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
820
+ }
821
+ onMouseEnter?.(e);
822
+ }, [hoverEvent, eventBus, onMouseEnter]);
823
+ const handleMouseLeave = useCallback((e) => {
824
+ if (hoverEvent) {
825
+ eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
826
+ }
827
+ onMouseLeave?.(e);
828
+ }, [hoverEvent, eventBus, onMouseLeave]);
829
+ const isClickable = action || onClick;
783
830
  return /* @__PURE__ */ jsx(
784
831
  Component,
785
832
  {
@@ -811,10 +858,12 @@ var Box = React37__default.forwardRef(
811
858
  // Position
812
859
  position && positionStyles[position],
813
860
  // Cursor for clickable
814
- onClick && "cursor-pointer",
861
+ isClickable && "cursor-pointer",
815
862
  className
816
863
  ),
817
- onClick,
864
+ onClick: isClickable ? handleClick : void 0,
865
+ onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
866
+ onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
818
867
  ...rest,
819
868
  children
820
869
  }
@@ -1474,8 +1523,17 @@ var Stack = ({
1474
1523
  onClick,
1475
1524
  onKeyDown,
1476
1525
  role,
1477
- tabIndex
1526
+ tabIndex,
1527
+ action,
1528
+ actionPayload
1478
1529
  }) => {
1530
+ const eventBus = useEventBus();
1531
+ const handleClick = (e) => {
1532
+ if (action) {
1533
+ eventBus.emit(`UI:${action}`, actionPayload ?? {});
1534
+ }
1535
+ onClick?.(e);
1536
+ };
1479
1537
  const directionClass = direction === "horizontal" ? reverse ? "flex-row-reverse" : "flex-row" : reverse ? "flex-col-reverse" : "flex-col";
1480
1538
  return /* @__PURE__ */ jsx(
1481
1539
  Component,
@@ -1491,7 +1549,7 @@ var Stack = ({
1491
1549
  className
1492
1550
  ),
1493
1551
  style,
1494
- onClick,
1552
+ onClick: action || onClick ? handleClick : void 0,
1495
1553
  onKeyDown,
1496
1554
  role,
1497
1555
  tabIndex,
@@ -1509,8 +1567,11 @@ var TextHighlight = ({
1509
1567
  onMouseLeave,
1510
1568
  annotationId,
1511
1569
  className,
1512
- children
1570
+ children,
1571
+ action,
1572
+ hoverEvent
1513
1573
  }) => {
1574
+ const eventBus = useEventBus();
1514
1575
  const baseStyles = "cursor-pointer transition-all duration-150";
1515
1576
  const typeStyles = {
1516
1577
  question: cn(
@@ -1533,14 +1594,24 @@ var TextHighlight = ({
1533
1594
  "data-highlight-type": highlightType,
1534
1595
  "data-annotation-id": annotationId,
1535
1596
  className: cn(baseStyles, typeStyles[highlightType], className),
1536
- onClick,
1537
- onMouseEnter,
1538
- onMouseLeave,
1597
+ onClick: () => {
1598
+ if (action) eventBus.emit(`UI:${action}`, { annotationId });
1599
+ onClick?.();
1600
+ },
1601
+ onMouseEnter: () => {
1602
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true, annotationId });
1603
+ onMouseEnter?.();
1604
+ },
1605
+ onMouseLeave: () => {
1606
+ if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false, annotationId });
1607
+ onMouseLeave?.();
1608
+ },
1539
1609
  role: "button",
1540
1610
  tabIndex: 0,
1541
1611
  onKeyDown: (e) => {
1542
1612
  if (e.key === "Enter" || e.key === " ") {
1543
1613
  e.preventDefault();
1614
+ if (action) eventBus.emit(`UI:${action}`, { annotationId });
1544
1615
  onClick?.();
1545
1616
  }
1546
1617
  },
@@ -1837,9 +1908,17 @@ var Overlay = ({
1837
1908
  isVisible = true,
1838
1909
  onClick,
1839
1910
  className,
1840
- blur = true
1911
+ blur = true,
1912
+ action
1841
1913
  }) => {
1914
+ const eventBus = useEventBus();
1842
1915
  if (!isVisible) return null;
1916
+ const handleClick = (e) => {
1917
+ if (action) {
1918
+ eventBus.emit(`UI:${action}`, {});
1919
+ }
1920
+ onClick?.(e);
1921
+ };
1843
1922
  return /* @__PURE__ */ jsx(
1844
1923
  "div",
1845
1924
  {
@@ -1848,7 +1927,7 @@ var Overlay = ({
1848
1927
  blur && "backdrop-blur-sm",
1849
1928
  className
1850
1929
  ),
1851
- onClick,
1930
+ onClick: action || onClick ? handleClick : void 0,
1852
1931
  "aria-hidden": "true"
1853
1932
  }
1854
1933
  );
@@ -2163,10 +2242,13 @@ function ControlButton({
2163
2242
  variant = "secondary",
2164
2243
  onPress,
2165
2244
  onRelease,
2245
+ pressEvent,
2246
+ releaseEvent,
2166
2247
  pressed,
2167
2248
  disabled,
2168
2249
  className
2169
2250
  }) {
2251
+ const eventBus = useEventBus();
2170
2252
  const [isPressed, setIsPressed] = React37.useState(false);
2171
2253
  const actualPressed = pressed ?? isPressed;
2172
2254
  const handlePointerDown = React37.useCallback(
@@ -2174,27 +2256,30 @@ function ControlButton({
2174
2256
  e.preventDefault();
2175
2257
  if (disabled) return;
2176
2258
  setIsPressed(true);
2259
+ if (pressEvent) eventBus.emit(`UI:${pressEvent}`, {});
2177
2260
  onPress?.();
2178
2261
  },
2179
- [disabled, onPress]
2262
+ [disabled, pressEvent, eventBus, onPress]
2180
2263
  );
2181
2264
  const handlePointerUp = React37.useCallback(
2182
2265
  (e) => {
2183
2266
  e.preventDefault();
2184
2267
  if (disabled) return;
2185
2268
  setIsPressed(false);
2269
+ if (releaseEvent) eventBus.emit(`UI:${releaseEvent}`, {});
2186
2270
  onRelease?.();
2187
2271
  },
2188
- [disabled, onRelease]
2272
+ [disabled, releaseEvent, eventBus, onRelease]
2189
2273
  );
2190
2274
  const handlePointerLeave = React37.useCallback(
2191
2275
  (e) => {
2192
2276
  if (isPressed) {
2193
2277
  setIsPressed(false);
2278
+ if (releaseEvent) eventBus.emit(`UI:${releaseEvent}`, {});
2194
2279
  onRelease?.();
2195
2280
  }
2196
2281
  },
2197
- [isPressed, onRelease]
2282
+ [isPressed, releaseEvent, eventBus, onRelease]
2198
2283
  );
2199
2284
  return /* @__PURE__ */ jsxs(
2200
2285
  "button",
@@ -2240,8 +2325,10 @@ function Sprite({
2240
2325
  zIndex = 0,
2241
2326
  columns = 16,
2242
2327
  className,
2243
- onClick
2328
+ onClick,
2329
+ action
2244
2330
  }) {
2331
+ const eventBus = useEventBus();
2245
2332
  const sourcePosition = useMemo(() => {
2246
2333
  const frameX = frame % columns;
2247
2334
  const frameY = Math.floor(frame / columns);
@@ -2266,11 +2353,15 @@ function Sprite({
2266
2353
  return transforms.join(" ");
2267
2354
  }, [x, y, scale, flipX, flipY, rotation]);
2268
2355
  const backgroundPosition = `-${sourcePosition.x}px -${sourcePosition.y}px`;
2356
+ const handleClick = () => {
2357
+ if (action) eventBus.emit(`UI:${action}`, {});
2358
+ onClick?.();
2359
+ };
2269
2360
  return /* @__PURE__ */ jsx(
2270
2361
  "div",
2271
2362
  {
2272
2363
  className,
2273
- onClick,
2364
+ onClick: action || onClick ? handleClick : void 0,
2274
2365
  style: {
2275
2366
  position: "absolute",
2276
2367
  width: frameWidth,
@@ -2283,7 +2374,7 @@ function Sprite({
2283
2374
  transformOrigin: "center center",
2284
2375
  opacity,
2285
2376
  zIndex,
2286
- pointerEvents: onClick ? "auto" : "none"
2377
+ pointerEvents: action || onClick ? "auto" : "none"
2287
2378
  }
2288
2379
  }
2289
2380
  );
@@ -2361,8 +2452,14 @@ var EmptyState = ({
2361
2452
  onAction,
2362
2453
  className,
2363
2454
  destructive,
2364
- variant
2455
+ variant,
2456
+ actionEvent
2365
2457
  }) => {
2458
+ const eventBus = useEventBus();
2459
+ const handleAction = () => {
2460
+ if (actionEvent) eventBus.emit(`UI:${actionEvent}`, {});
2461
+ onAction?.();
2462
+ };
2366
2463
  const Icon2 = typeof icon === "string" ? ICON_MAP[icon] : icon;
2367
2464
  const isDestructive = destructive || variant === "error";
2368
2465
  const isSuccess = variant === "success";
@@ -2404,12 +2501,12 @@ var EmptyState = ({
2404
2501
  }
2405
2502
  ),
2406
2503
  description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-[var(--color-muted-foreground)] max-w-sm", children: description }),
2407
- actionLabel && onAction && /* @__PURE__ */ jsx(
2504
+ actionLabel && (onAction || actionEvent) && /* @__PURE__ */ jsx(
2408
2505
  Button,
2409
2506
  {
2410
2507
  className: "mt-4",
2411
2508
  variant: isDestructive ? "danger" : "primary",
2412
- onClick: onAction,
2509
+ onClick: handleAction,
2413
2510
  children: actionLabel
2414
2511
  }
2415
2512
  )
@@ -2451,8 +2548,14 @@ var ErrorState = ({
2451
2548
  message,
2452
2549
  description,
2453
2550
  onRetry,
2454
- className
2551
+ className,
2552
+ retryEvent
2455
2553
  }) => {
2554
+ const eventBus = useEventBus();
2555
+ const handleRetry = () => {
2556
+ if (retryEvent) eventBus.emit(`UI:${retryEvent}`, {});
2557
+ onRetry?.();
2558
+ };
2456
2559
  const resolvedMessage = message ?? description ?? "An error occurred";
2457
2560
  return /* @__PURE__ */ jsxs(
2458
2561
  "div",
@@ -2465,7 +2568,7 @@ var ErrorState = ({
2465
2568
  /* @__PURE__ */ jsx("div", { 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)]" }) }),
2466
2569
  /* @__PURE__ */ jsx("h3", { className: "text-lg font-medium text-[var(--color-foreground)]", children: title }),
2467
2570
  /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-[var(--color-muted-foreground)] max-w-sm", children: resolvedMessage }),
2468
- onRetry && /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: onRetry, children: "Try again" })
2571
+ (onRetry || retryEvent) && /* @__PURE__ */ jsx(Button, { variant: "secondary", className: "mt-4", onClick: handleRetry, children: "Try again" })
2469
2572
  ]
2470
2573
  }
2471
2574
  );
@@ -2492,8 +2595,10 @@ var Accordion = ({
2492
2595
  defaultOpen,
2493
2596
  openItems: controlledOpenItems,
2494
2597
  onItemToggle,
2495
- className
2598
+ className,
2599
+ toggleEvent
2496
2600
  }) => {
2601
+ const eventBus = useEventBus();
2497
2602
  const normalizedItems = items.map(
2498
2603
  (item, index) => normalizeItem(item, index)
2499
2604
  );
@@ -2523,6 +2628,7 @@ var Accordion = ({
2523
2628
  setInternalOpenItems(newOpenItems);
2524
2629
  }
2525
2630
  onItemToggle?.(itemId, !isOpen);
2631
+ if (toggleEvent) eventBus.emit(`UI:${toggleEvent}`, { itemId, isOpen: !isOpen });
2526
2632
  };
2527
2633
  return /* @__PURE__ */ jsx("div", { className: cn("w-full", className), children: normalizedItems.map((item, index) => {
2528
2634
  const isOpen = openItemsSet.has(item.id);
@@ -2600,9 +2706,15 @@ var Alert = ({
2600
2706
  onDismiss,
2601
2707
  onClose,
2602
2708
  actions,
2603
- className
2709
+ className,
2710
+ dismissEvent
2604
2711
  }) => {
2605
- const handleDismiss = onDismiss || onClose;
2712
+ const eventBus = useEventBus();
2713
+ const handleDismissCallback = onDismiss || onClose;
2714
+ const handleDismiss = () => {
2715
+ if (dismissEvent) eventBus.emit(`UI:${dismissEvent}`, {});
2716
+ handleDismissCallback?.();
2717
+ };
2606
2718
  const content = children ?? message;
2607
2719
  return /* @__PURE__ */ jsx(
2608
2720
  Box,
@@ -2628,7 +2740,7 @@ var Alert = ({
2628
2740
  /* @__PURE__ */ jsx(Typography, { variant: "body2", children: content }),
2629
2741
  actions && /* @__PURE__ */ jsx("div", { className: "mt-3 flex gap-2", children: actions })
2630
2742
  ] }),
2631
- (dismissible || handleDismiss) && /* @__PURE__ */ jsx(
2743
+ (dismissible || dismissEvent || handleDismissCallback) && /* @__PURE__ */ jsx(
2632
2744
  "button",
2633
2745
  {
2634
2746
  type: "button",
@@ -2652,6 +2764,7 @@ var Breadcrumb = ({
2652
2764
  maxItems,
2653
2765
  className
2654
2766
  }) => {
2767
+ const eventBus = useEventBus();
2655
2768
  const displayItems = maxItems && items.length > maxItems ? [
2656
2769
  ...items.slice(0, 1),
2657
2770
  { label: "...", isCurrent: false },
@@ -2691,7 +2804,10 @@ var Breadcrumb = ({
2691
2804
  "button",
2692
2805
  {
2693
2806
  type: "button",
2694
- onClick: item.onClick,
2807
+ onClick: () => {
2808
+ if (item.event) eventBus.emit(`UI:${item.event}`, { label: item.label });
2809
+ item.onClick?.();
2810
+ },
2695
2811
  className: cn(
2696
2812
  "flex items-center gap-1.5 transition-colors",
2697
2813
  "focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)] focus:ring-offset-2",
@@ -3223,9 +3339,15 @@ function Card2({
3223
3339
  actions,
3224
3340
  children,
3225
3341
  onClick,
3226
- className = ""
3342
+ className = "",
3343
+ action
3227
3344
  }) {
3228
- const isClickable = !!onClick;
3345
+ const eventBus = useEventBus();
3346
+ const isClickable = !!onClick || !!action;
3347
+ const handleClick = () => {
3348
+ if (action) eventBus.emit(`UI:${action}`, {});
3349
+ onClick?.();
3350
+ };
3229
3351
  return /* @__PURE__ */ jsxs(
3230
3352
  "div",
3231
3353
  {
@@ -3236,10 +3358,10 @@ function Card2({
3236
3358
  ${isClickable ? "cursor-pointer hover:shadow-[var(--shadow-hover)] transition-shadow" : ""}
3237
3359
  ${className}
3238
3360
  `,
3239
- onClick,
3361
+ onClick: isClickable ? handleClick : void 0,
3240
3362
  role: isClickable ? "button" : void 0,
3241
3363
  tabIndex: isClickable ? 0 : void 0,
3242
- onKeyDown: isClickable ? (e) => e.key === "Enter" && onClick?.() : void 0,
3364
+ onKeyDown: isClickable ? (e) => e.key === "Enter" && handleClick() : void 0,
3243
3365
  children: [
3244
3366
  image && /* @__PURE__ */ jsx("div", { className: "aspect-video w-full overflow-hidden rounded-t-lg", children: /* @__PURE__ */ jsx(
3245
3367
  "img",
@@ -3255,21 +3377,22 @@ function Card2({
3255
3377
  subtitle && /* @__PURE__ */ jsx("p", { className: "text-sm text-[var(--color-muted-foreground)] mt-1", children: subtitle })
3256
3378
  ] }),
3257
3379
  children && /* @__PURE__ */ jsx("div", { className: "text-[var(--color-card-foreground)]", children }),
3258
- actions && actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 mt-4 pt-4 border-t border-[var(--color-border)]", children: actions.map((action, index) => /* @__PURE__ */ jsx(
3380
+ actions && actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 mt-4 pt-4 border-t border-[var(--color-border)]", children: actions.map((action2, index) => /* @__PURE__ */ jsx(
3259
3381
  "button",
3260
3382
  {
3261
3383
  onClick: (e) => {
3262
3384
  e.stopPropagation();
3263
- action.onClick();
3385
+ if (action2.event) eventBus.emit(`UI:${action2.event}`, { label: action2.label });
3386
+ action2.onClick?.();
3264
3387
  },
3265
- disabled: action.disabled,
3388
+ disabled: action2.disabled,
3266
3389
  className: `
3267
3390
  px-3 py-1.5 text-sm font-medium rounded-[var(--radius-sm)]
3268
3391
  transition-colors
3269
- ${action.variant === "primary" ? "bg-[var(--color-primary)] text-[var(--color-primary-foreground)] hover:bg-[var(--color-primary-hover)] disabled:opacity-50" : action.variant === "danger" ? "bg-[var(--color-error)] text-[var(--color-error-foreground)] hover:opacity-90 disabled:opacity-50" : "bg-[var(--color-muted)] text-[var(--color-foreground)] hover:bg-[var(--color-surface-hover)]"}
3392
+ ${action2.variant === "primary" ? "bg-[var(--color-primary)] text-[var(--color-primary-foreground)] hover:bg-[var(--color-primary-hover)] disabled:opacity-50" : action2.variant === "danger" ? "bg-[var(--color-error)] text-[var(--color-error-foreground)] hover:opacity-90 disabled:opacity-50" : "bg-[var(--color-muted)] text-[var(--color-foreground)] hover:bg-[var(--color-surface-hover)]"}
3270
3393
  disabled:cursor-not-allowed
3271
3394
  `,
3272
- children: action.label
3395
+ children: action2.label
3273
3396
  },
3274
3397
  index
3275
3398
  )) })
@@ -3418,6 +3541,7 @@ var FloatingActionButton = ({
3418
3541
  position = "bottom-right",
3419
3542
  className
3420
3543
  }) => {
3544
+ const eventBus = useEventBus();
3421
3545
  const resolvedAction = action ?? (icon ? {
3422
3546
  icon: resolveIcon2(icon),
3423
3547
  onClick: onClick ?? (() => {
@@ -3461,7 +3585,8 @@ var FloatingActionButton = ({
3461
3585
  if (actions && actions.length > 0) {
3462
3586
  const handleMainClick = () => {
3463
3587
  if (actions.length === 1) {
3464
- actions[0].onClick();
3588
+ if (actions[0].event) eventBus.emit(`UI:${actions[0].event}`, { actionId: actions[0].id });
3589
+ actions[0].onClick?.();
3465
3590
  } else {
3466
3591
  setIsExpanded(!isExpanded);
3467
3592
  }
@@ -3503,7 +3628,8 @@ var FloatingActionButton = ({
3503
3628
  icon: actionItem.icon,
3504
3629
  onClick: () => {
3505
3630
  setIsExpanded(false);
3506
- actionItem.onClick();
3631
+ if (actionItem.event) eventBus.emit(`UI:${actionItem.event}`, { actionId: actionItem.id });
3632
+ actionItem.onClick?.();
3507
3633
  },
3508
3634
  className: "rounded-[var(--radius-full)] shadow-[var(--shadow-lg)]",
3509
3635
  "aria-label": actionItem.label,
@@ -3717,6 +3843,7 @@ var Menu2 = ({
3717
3843
  position = "bottom-left",
3718
3844
  className
3719
3845
  }) => {
3846
+ const eventBus = useEventBus();
3720
3847
  const [isOpen, setIsOpen] = useState(false);
3721
3848
  const [activeSubMenu, setActiveSubMenu] = useState(null);
3722
3849
  const [triggerRect, setTriggerRect] = useState(null);
@@ -3739,6 +3866,7 @@ var Menu2 = ({
3739
3866
  if (item.subMenu && item.subMenu.length > 0) {
3740
3867
  setActiveSubMenu(item.id ?? null);
3741
3868
  } else {
3869
+ if (item.event) eventBus.emit(`UI:${item.event}`, { itemId: item.id, label: item.label });
3742
3870
  item.onClick?.();
3743
3871
  setIsOpen(false);
3744
3872
  }
@@ -3884,8 +4012,10 @@ var Modal = ({
3884
4012
  showCloseButton = true,
3885
4013
  closeOnOverlayClick = true,
3886
4014
  closeOnEscape = true,
3887
- className
4015
+ className,
4016
+ closeEvent
3888
4017
  }) => {
4018
+ const eventBus = useEventBus();
3889
4019
  const modalRef = useRef(null);
3890
4020
  const previousActiveElement = useRef(null);
3891
4021
  useEffect(() => {
@@ -3903,11 +4033,14 @@ var Modal = ({
3903
4033
  useEffect(() => {
3904
4034
  if (!isOpen || !closeOnEscape) return;
3905
4035
  const handleEscape = (e) => {
3906
- if (e.key === "Escape") onClose();
4036
+ if (e.key === "Escape") {
4037
+ if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
4038
+ onClose();
4039
+ }
3907
4040
  };
3908
4041
  document.addEventListener("keydown", handleEscape);
3909
4042
  return () => document.removeEventListener("keydown", handleEscape);
3910
- }, [isOpen, closeOnEscape, onClose]);
4043
+ }, [isOpen, closeOnEscape, onClose, closeEvent, eventBus]);
3911
4044
  useEffect(() => {
3912
4045
  if (isOpen) {
3913
4046
  document.body.style.overflow = "hidden";
@@ -3919,9 +4052,13 @@ var Modal = ({
3919
4052
  };
3920
4053
  }, [isOpen]);
3921
4054
  if (!isOpen) return null;
4055
+ const handleClose = () => {
4056
+ if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
4057
+ onClose();
4058
+ };
3922
4059
  const handleOverlayClick = (e) => {
3923
4060
  if (closeOnOverlayClick && e.target === e.currentTarget) {
3924
- onClose();
4061
+ handleClose();
3925
4062
  }
3926
4063
  };
3927
4064
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -3963,7 +4100,7 @@ var Modal = ({
3963
4100
  "button",
3964
4101
  {
3965
4102
  type: "button",
3966
- onClick: onClose,
4103
+ onClick: handleClose,
3967
4104
  className: cn(
3968
4105
  "p-1 transition-colors rounded-[var(--radius-sm)]",
3969
4106
  "hover:bg-[var(--color-muted)]"
@@ -4005,13 +4142,24 @@ var Pagination = ({
4005
4142
  showTotal = false,
4006
4143
  totalItems,
4007
4144
  maxVisiblePages = 7,
4008
- className
4145
+ className,
4146
+ pageChangeEvent,
4147
+ pageSizeChangeEvent
4009
4148
  }) => {
4149
+ const eventBus = useEventBus();
4010
4150
  const [jumpToPage, setJumpToPage] = useState("");
4151
+ const handlePageChange = (page) => {
4152
+ if (pageChangeEvent) eventBus.emit(`UI:${pageChangeEvent}`, { page });
4153
+ onPageChange(page);
4154
+ };
4155
+ const handlePageSizeChange = (size) => {
4156
+ if (pageSizeChangeEvent) eventBus.emit(`UI:${pageSizeChangeEvent}`, { pageSize: size });
4157
+ onPageSizeChange?.(size);
4158
+ };
4011
4159
  const handleJumpToPage = () => {
4012
4160
  const page = parseInt(jumpToPage, 10);
4013
4161
  if (page >= 1 && page <= totalPages) {
4014
- onPageChange(page);
4162
+ handlePageChange(page);
4015
4163
  setJumpToPage("");
4016
4164
  }
4017
4165
  };
@@ -4060,7 +4208,7 @@ var Pagination = ({
4060
4208
  "select",
4061
4209
  {
4062
4210
  value: pageSize,
4063
- onChange: (e) => onPageSizeChange(Number(e.target.value)),
4211
+ onChange: (e) => handlePageSizeChange(Number(e.target.value)),
4064
4212
  className: "px-2 py-1 text-sm border-[length:var(--border-width)] border-[var(--color-border)] bg-[var(--color-card)] text-[var(--color-foreground)] font-medium focus:outline-none focus:ring-2 focus:ring-[var(--color-ring)]",
4065
4213
  children: pageSizeOptions.map((size) => /* @__PURE__ */ jsx("option", { value: size, children: size }, size))
4066
4214
  }
@@ -4073,7 +4221,7 @@ var Pagination = ({
4073
4221
  {
4074
4222
  variant: "secondary",
4075
4223
  size: "sm",
4076
- onClick: () => onPageChange(currentPage - 1),
4224
+ onClick: () => handlePageChange(currentPage - 1),
4077
4225
  disabled: currentPage === 1,
4078
4226
  icon: ChevronLeft,
4079
4227
  children: "Previous"
@@ -4098,7 +4246,7 @@ var Pagination = ({
4098
4246
  {
4099
4247
  variant: isActive ? "primary" : "ghost",
4100
4248
  size: "sm",
4101
- onClick: () => onPageChange(page),
4249
+ onClick: () => handlePageChange(page),
4102
4250
  className: "min-w-[2.5rem]",
4103
4251
  children: page
4104
4252
  },
@@ -4110,7 +4258,7 @@ var Pagination = ({
4110
4258
  {
4111
4259
  variant: "secondary",
4112
4260
  size: "sm",
4113
- onClick: () => onPageChange(currentPage + 1),
4261
+ onClick: () => handlePageChange(currentPage + 1),
4114
4262
  disabled: currentPage === totalPages,
4115
4263
  iconRight: ChevronRight,
4116
4264
  children: "Next"
@@ -4551,15 +4699,21 @@ var SidePanel = ({
4551
4699
  width = "w-96",
4552
4700
  position = "right",
4553
4701
  showOverlay = true,
4554
- className
4702
+ className,
4703
+ closeEvent
4555
4704
  }) => {
4705
+ const eventBus = useEventBus();
4706
+ const handleClose = () => {
4707
+ if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
4708
+ onClose();
4709
+ };
4556
4710
  if (!isOpen) return null;
4557
4711
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4558
4712
  showOverlay && /* @__PURE__ */ jsx(
4559
4713
  "div",
4560
4714
  {
4561
4715
  className: "fixed inset-0 bg-white/80 backdrop-blur-sm z-40 lg:hidden",
4562
- onClick: onClose
4716
+ onClick: handleClose
4563
4717
  }
4564
4718
  ),
4565
4719
  /* @__PURE__ */ jsxs(
@@ -4585,7 +4739,7 @@ var SidePanel = ({
4585
4739
  variant: "ghost",
4586
4740
  size: "sm",
4587
4741
  icon: X,
4588
- onClick: onClose,
4742
+ onClick: handleClose,
4589
4743
  "aria-label": "Close panel",
4590
4744
  children: /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
4591
4745
  }
@@ -4794,17 +4948,28 @@ var Toast = ({
4794
4948
  actionLabel,
4795
4949
  onAction,
4796
4950
  badge,
4797
- className
4951
+ className,
4952
+ dismissEvent,
4953
+ actionEvent
4798
4954
  }) => {
4955
+ const eventBus = useEventBus();
4956
+ const handleDismiss = () => {
4957
+ if (dismissEvent) eventBus.emit(`UI:${dismissEvent}`, {});
4958
+ onDismiss?.();
4959
+ };
4960
+ const handleAction = () => {
4961
+ if (actionEvent) eventBus.emit(`UI:${actionEvent}`, {});
4962
+ onAction?.();
4963
+ };
4799
4964
  useEffect(() => {
4800
- if (duration <= 0 || !onDismiss) {
4965
+ if (duration <= 0 || !onDismiss && !dismissEvent) {
4801
4966
  return;
4802
4967
  }
4803
4968
  const timer = setTimeout(() => {
4804
- onDismiss();
4969
+ handleDismiss();
4805
4970
  }, duration);
4806
4971
  return () => clearTimeout(timer);
4807
- }, [duration, onDismiss]);
4972
+ }, [duration, onDismiss, dismissEvent]);
4808
4973
  return /* @__PURE__ */ jsx(
4809
4974
  "div",
4810
4975
  {
@@ -4827,7 +4992,7 @@ var Toast = ({
4827
4992
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
4828
4993
  title && /* @__PURE__ */ jsx(Typography, { variant: "h6", className: "mb-1", children: title }),
4829
4994
  /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-sm", children: message }),
4830
- actionLabel && onAction && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: onAction, children: actionLabel }) })
4995
+ actionLabel && (onAction || actionEvent) && /* @__PURE__ */ jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: handleAction, children: actionLabel }) })
4831
4996
  ] }),
4832
4997
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 flex-shrink-0", children: [
4833
4998
  badge !== void 0 && /* @__PURE__ */ jsx(Badge, { variant: "default", size: "sm", children: badge }),
@@ -4835,7 +5000,7 @@ var Toast = ({
4835
5000
  "button",
4836
5001
  {
4837
5002
  type: "button",
4838
- onClick: onDismiss,
5003
+ onClick: handleDismiss,
4839
5004
  className: cn(
4840
5005
  "flex-shrink-0 p-1 transition-colors rounded-[var(--radius-sm)]",
4841
5006
  "hover:bg-[var(--color-muted)]",
@@ -4982,8 +5147,10 @@ var Drawer = ({
4982
5147
  showCloseButton = true,
4983
5148
  closeOnOverlayClick = true,
4984
5149
  closeOnEscape = true,
4985
- className
5150
+ className,
5151
+ closeEvent
4986
5152
  }) => {
5153
+ const eventBus = useEventBus();
4987
5154
  const drawerRef = useRef(null);
4988
5155
  const previousActiveElement = useRef(null);
4989
5156
  useEffect(() => {
@@ -5002,12 +5169,13 @@ var Drawer = ({
5002
5169
  if (!isOpen || !closeOnEscape) return;
5003
5170
  const handleEscape = (e) => {
5004
5171
  if (e.key === "Escape") {
5172
+ if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
5005
5173
  onClose();
5006
5174
  }
5007
5175
  };
5008
5176
  document.addEventListener("keydown", handleEscape);
5009
5177
  return () => document.removeEventListener("keydown", handleEscape);
5010
- }, [isOpen, closeOnEscape, onClose]);
5178
+ }, [isOpen, closeOnEscape, onClose, closeEvent, eventBus]);
5011
5179
  useEffect(() => {
5012
5180
  if (isOpen) {
5013
5181
  document.body.style.overflow = "hidden";
@@ -5019,9 +5187,13 @@ var Drawer = ({
5019
5187
  };
5020
5188
  }, [isOpen]);
5021
5189
  if (!isOpen) return null;
5190
+ const handleClose = () => {
5191
+ if (closeEvent) eventBus.emit(`UI:${closeEvent}`, {});
5192
+ onClose();
5193
+ };
5022
5194
  const handleOverlayClick = (e) => {
5023
5195
  if (closeOnOverlayClick && e.target === e.currentTarget) {
5024
- onClose();
5196
+ handleClose();
5025
5197
  }
5026
5198
  };
5027
5199
  const widthClass = width in sizeWidths ? sizeWidths[width] : "";
@@ -5070,7 +5242,7 @@ var Drawer = ({
5070
5242
  "button",
5071
5243
  {
5072
5244
  type: "button",
5073
- onClick: onClose,
5245
+ onClick: handleClose,
5074
5246
  className: cn(
5075
5247
  "p-1 transition-colors rounded-[var(--radius-sm)]",
5076
5248
  "hover:bg-[var(--color-muted)]",
@@ -5130,13 +5302,16 @@ var WizardProgress = ({
5130
5302
  onStepClick,
5131
5303
  allowNavigation = true,
5132
5304
  compact = false,
5133
- className
5305
+ className,
5306
+ stepClickEvent
5134
5307
  }) => {
5308
+ const eventBus = useEventBus();
5135
5309
  const totalSteps = steps.length;
5136
5310
  const handleStepClick = (index) => {
5137
5311
  const isCompleted = index < currentStep;
5138
- if (isCompleted && allowNavigation && onStepClick) {
5139
- onStepClick(index);
5312
+ if (isCompleted && allowNavigation) {
5313
+ if (stepClickEvent) eventBus.emit(`UI:${stepClickEvent}`, { stepIndex: index });
5314
+ onStepClick?.(index);
5140
5315
  }
5141
5316
  };
5142
5317
  return /* @__PURE__ */ jsx(
@@ -10035,6 +10210,11 @@ function IsometricCanvas({
10035
10210
  onUnitClick,
10036
10211
  onTileHover,
10037
10212
  onTileLeave,
10213
+ // Declarative event props
10214
+ tileClickEvent,
10215
+ unitClickEvent,
10216
+ tileHoverEvent,
10217
+ tileLeaveEvent,
10038
10218
  // Rendering options
10039
10219
  scale = 0.4,
10040
10220
  debug: debug2 = false,
@@ -10054,6 +10234,7 @@ function IsometricCanvas({
10054
10234
  assetBaseUrl,
10055
10235
  assetManifest
10056
10236
  }) {
10237
+ const eventBus = useEventBus();
10057
10238
  const canvasRef = useRef(null);
10058
10239
  const containerRef = useRef(null);
10059
10240
  const minimapRef = useRef(null);
@@ -10590,20 +10771,22 @@ function IsometricCanvas({
10590
10771
  const wasPanning = handleMouseMove(e, () => draw(animTimeRef.current));
10591
10772
  if (wasPanning) return;
10592
10773
  }
10593
- if (!onTileHover || !canvasRef.current) return;
10774
+ if (!onTileHover && !tileHoverEvent || !canvasRef.current) return;
10594
10775
  const world = screenToWorld(e.clientX, e.clientY, canvasRef.current, viewportSize);
10595
10776
  const adjustedX = world.x - scaledTileWidth / 2;
10596
10777
  const adjustedY = world.y - (scaledTileHeight - scaledFloorHeight) - scaledFloorHeight / 2;
10597
10778
  const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
10598
10779
  const tileExists = tilesProp.some((t) => t.x === isoPos.x && t.y === isoPos.y);
10599
10780
  if (tileExists) {
10600
- onTileHover(isoPos.x, isoPos.y);
10781
+ if (tileHoverEvent) eventBus.emit(`UI:${tileHoverEvent}`, { x: isoPos.x, y: isoPos.y });
10782
+ onTileHover?.(isoPos.x, isoPos.y);
10601
10783
  }
10602
- }, [enableCamera, handleMouseMove, draw, onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledTileHeight, scaledFloorHeight, scale, baseOffsetX, tilesProp]);
10784
+ }, [enableCamera, handleMouseMove, draw, onTileHover, screenToWorld, viewportSize, scaledTileWidth, scaledTileHeight, scaledFloorHeight, scale, baseOffsetX, tilesProp, tileHoverEvent, eventBus]);
10603
10785
  const handleMouseLeaveWithCamera = useCallback(() => {
10604
10786
  handleMouseLeave();
10787
+ if (tileLeaveEvent) eventBus.emit(`UI:${tileLeaveEvent}`, {});
10605
10788
  onTileLeave?.();
10606
- }, [handleMouseLeave, onTileLeave]);
10789
+ }, [handleMouseLeave, onTileLeave, tileLeaveEvent, eventBus]);
10607
10790
  const handleWheelWithCamera = useCallback((e) => {
10608
10791
  if (enableCamera) {
10609
10792
  handleWheel(e, () => draw(animTimeRef.current));
@@ -10617,15 +10800,17 @@ function IsometricCanvas({
10617
10800
  const adjustedY = world.y - (scaledTileHeight - scaledFloorHeight) - scaledFloorHeight / 2;
10618
10801
  const isoPos = screenToIso(adjustedX, adjustedY, scale, baseOffsetX);
10619
10802
  const clickedUnit = units.find((u) => u.position.x === isoPos.x && u.position.y === isoPos.y);
10620
- if (clickedUnit && onUnitClick) {
10621
- onUnitClick(clickedUnit.id);
10622
- } else if (onTileClick) {
10803
+ if (clickedUnit && (onUnitClick || unitClickEvent)) {
10804
+ if (unitClickEvent) eventBus.emit(`UI:${unitClickEvent}`, { unitId: clickedUnit.id });
10805
+ onUnitClick?.(clickedUnit.id);
10806
+ } else if (onTileClick || tileClickEvent) {
10623
10807
  const tileExists = tilesProp.some((t) => t.x === isoPos.x && t.y === isoPos.y);
10624
10808
  if (tileExists) {
10625
- onTileClick(isoPos.x, isoPos.y);
10809
+ if (tileClickEvent) eventBus.emit(`UI:${tileClickEvent}`, { x: isoPos.x, y: isoPos.y });
10810
+ onTileClick?.(isoPos.x, isoPos.y);
10626
10811
  }
10627
10812
  }
10628
- }, [dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledTileHeight, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick]);
10813
+ }, [dragDistance, screenToWorld, viewportSize, scaledTileWidth, scaledTileHeight, scaledFloorHeight, scale, baseOffsetX, units, tilesProp, onUnitClick, onTileClick, unitClickEvent, tileClickEvent, eventBus]);
10629
10814
  if (error) {
10630
10815
  return /* @__PURE__ */ jsx(ErrorState, { title: "Canvas Error", message: error.message, className });
10631
10816
  }
@@ -11897,10 +12082,17 @@ function EmojiEffect({
11897
12082
  );
11898
12083
  }
11899
12084
  function CanvasEffect(props) {
12085
+ const eventBus = useEventBus();
12086
+ const { completeEvent, onComplete, ...rest } = props;
12087
+ const handleComplete = useCallback(() => {
12088
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
12089
+ onComplete?.();
12090
+ }, [completeEvent, eventBus, onComplete]);
12091
+ const enhancedProps = { ...rest, onComplete: handleComplete };
11900
12092
  if (props.assetManifest) {
11901
- return /* @__PURE__ */ jsx(CanvasEffectEngine, { ...props, assetManifest: props.assetManifest });
12093
+ return /* @__PURE__ */ jsx(CanvasEffectEngine, { ...enhancedProps, assetManifest: props.assetManifest });
11902
12094
  }
11903
- return /* @__PURE__ */ jsx(EmojiEffect, { ...props });
12095
+ return /* @__PURE__ */ jsx(EmojiEffect, { ...enhancedProps });
11904
12096
  }
11905
12097
  CanvasEffect.displayName = "CanvasEffect";
11906
12098
 
@@ -12465,10 +12657,14 @@ function InventoryPanel({
12465
12657
  onSelectSlot,
12466
12658
  onUseItem,
12467
12659
  onDropItem,
12660
+ selectSlotEvent,
12661
+ useItemEvent,
12662
+ dropItemEvent,
12468
12663
  showTooltips = true,
12469
12664
  className,
12470
12665
  slotSize = 48
12471
12666
  }) {
12667
+ const eventBus = useEventBus();
12472
12668
  const [hoveredSlot, setHoveredSlot] = useState(null);
12473
12669
  const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
12474
12670
  const slotArray = Array.from({ length: slots }, (_, index) => {
@@ -12476,49 +12672,53 @@ function InventoryPanel({
12476
12672
  });
12477
12673
  const rows = Math.ceil(slots / columns);
12478
12674
  const handleSlotClick = useCallback((index) => {
12479
- onSelectSlot(index);
12480
- }, [onSelectSlot]);
12675
+ if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
12676
+ onSelectSlot?.(index);
12677
+ }, [onSelectSlot, selectSlotEvent, eventBus]);
12481
12678
  const handleSlotDoubleClick = useCallback((index) => {
12482
12679
  const item = slotArray[index];
12483
- if (item && onUseItem) {
12484
- onUseItem(item);
12680
+ if (item) {
12681
+ if (useItemEvent) eventBus.emit(`UI:${useItemEvent}`, { item });
12682
+ onUseItem?.(item);
12485
12683
  }
12486
- }, [slotArray, onUseItem]);
12684
+ }, [slotArray, onUseItem, useItemEvent, eventBus]);
12487
12685
  const handleKeyDown = useCallback((e, index) => {
12488
12686
  const item = slotArray[index];
12489
12687
  switch (e.key) {
12490
12688
  case "Enter":
12491
12689
  case " ":
12492
- if (item && onUseItem) {
12690
+ if (item) {
12493
12691
  e.preventDefault();
12494
- onUseItem(item);
12692
+ if (useItemEvent) eventBus.emit(`UI:${useItemEvent}`, { item });
12693
+ onUseItem?.(item);
12495
12694
  }
12496
12695
  break;
12497
12696
  case "Delete":
12498
12697
  case "Backspace":
12499
- if (item && onDropItem) {
12698
+ if (item) {
12500
12699
  e.preventDefault();
12501
- onDropItem(item);
12700
+ if (dropItemEvent) eventBus.emit(`UI:${dropItemEvent}`, { item });
12701
+ onDropItem?.(item);
12502
12702
  }
12503
12703
  break;
12504
12704
  case "ArrowRight":
12505
12705
  e.preventDefault();
12506
- onSelectSlot(Math.min(index + 1, slots - 1));
12706
+ onSelectSlot?.(Math.min(index + 1, slots - 1));
12507
12707
  break;
12508
12708
  case "ArrowLeft":
12509
12709
  e.preventDefault();
12510
- onSelectSlot(Math.max(index - 1, 0));
12710
+ onSelectSlot?.(Math.max(index - 1, 0));
12511
12711
  break;
12512
12712
  case "ArrowDown":
12513
12713
  e.preventDefault();
12514
- onSelectSlot(Math.min(index + columns, slots - 1));
12714
+ onSelectSlot?.(Math.min(index + columns, slots - 1));
12515
12715
  break;
12516
12716
  case "ArrowUp":
12517
12717
  e.preventDefault();
12518
- onSelectSlot(Math.max(index - columns, 0));
12718
+ onSelectSlot?.(Math.max(index - columns, 0));
12519
12719
  break;
12520
12720
  }
12521
- }, [slotArray, onUseItem, onDropItem, onSelectSlot, columns, slots]);
12721
+ }, [slotArray, onUseItem, onDropItem, onSelectSlot, columns, slots, useItemEvent, dropItemEvent, eventBus]);
12522
12722
  const handleMouseEnter = useCallback((e, index) => {
12523
12723
  if (showTooltips && slotArray[index]) {
12524
12724
  setHoveredSlot(index);
@@ -12604,8 +12804,12 @@ function DialogueBox({
12604
12804
  onComplete,
12605
12805
  onChoice,
12606
12806
  onAdvance,
12807
+ completeEvent,
12808
+ choiceEvent,
12809
+ advanceEvent,
12607
12810
  className
12608
12811
  }) {
12812
+ const eventBus = useEventBus();
12609
12813
  const [displayedText, setDisplayedText] = useState("");
12610
12814
  const [isTyping, setIsTyping] = useState(false);
12611
12815
  const [selectedChoice, setSelectedChoice] = useState(0);
@@ -12620,6 +12824,7 @@ function DialogueBox({
12620
12824
  if (typewriterSpeed === 0) {
12621
12825
  setDisplayedText(dialogue.text);
12622
12826
  setIsTyping(false);
12827
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
12623
12828
  onComplete?.();
12624
12829
  } else {
12625
12830
  setIsTyping(true);
@@ -12639,9 +12844,11 @@ function DialogueBox({
12639
12844
  } else {
12640
12845
  setIsTyping(false);
12641
12846
  clearInterval(interval);
12847
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
12642
12848
  onComplete?.();
12643
12849
  if (dialogue.autoAdvance && !dialogue.choices?.length) {
12644
12850
  autoAdvanceTimerRef.current = setTimeout(() => {
12851
+ if (advanceEvent) eventBus.emit(`UI:${advanceEvent}`, {});
12645
12852
  onAdvance?.();
12646
12853
  }, dialogue.autoAdvance);
12647
12854
  }
@@ -12654,16 +12861,18 @@ function DialogueBox({
12654
12861
  charIndexRef.current = textRef.current.length;
12655
12862
  setDisplayedText(textRef.current);
12656
12863
  setIsTyping(false);
12864
+ if (completeEvent) eventBus.emit(`UI:${completeEvent}`, {});
12657
12865
  onComplete?.();
12658
12866
  }
12659
- }, [isTyping, onComplete]);
12867
+ }, [isTyping, onComplete, completeEvent, eventBus]);
12660
12868
  const handleClick = useCallback(() => {
12661
12869
  if (isTyping) {
12662
12870
  skipTypewriter();
12663
12871
  } else if (!dialogue.choices?.length) {
12872
+ if (advanceEvent) eventBus.emit(`UI:${advanceEvent}`, {});
12664
12873
  onAdvance?.();
12665
12874
  }
12666
- }, [isTyping, skipTypewriter, dialogue.choices, onAdvance]);
12875
+ }, [isTyping, skipTypewriter, dialogue.choices, onAdvance, advanceEvent, eventBus]);
12667
12876
  const handleKeyDown = useCallback((e) => {
12668
12877
  if (isTyping) {
12669
12878
  if (e.key === " " || e.key === "Enter") {
@@ -12688,6 +12897,7 @@ function DialogueBox({
12688
12897
  e.preventDefault();
12689
12898
  const choice = enabledChoices2[selectedChoice];
12690
12899
  if (choice) {
12900
+ if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
12691
12901
  onChoice?.(choice);
12692
12902
  }
12693
12903
  break;
@@ -12698,6 +12908,7 @@ function DialogueBox({
12698
12908
  const choiceIndex = parseInt(e.key) - 1;
12699
12909
  if (choiceIndex < enabledChoices2.length) {
12700
12910
  e.preventDefault();
12911
+ if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice: enabledChoices2[choiceIndex] });
12701
12912
  onChoice?.(enabledChoices2[choiceIndex]);
12702
12913
  }
12703
12914
  break;
@@ -12705,10 +12916,11 @@ function DialogueBox({
12705
12916
  } else {
12706
12917
  if (e.key === " " || e.key === "Enter") {
12707
12918
  e.preventDefault();
12919
+ if (advanceEvent) eventBus.emit(`UI:${advanceEvent}`, {});
12708
12920
  onAdvance?.();
12709
12921
  }
12710
12922
  }
12711
- }, [isTyping, skipTypewriter, dialogue.choices, selectedChoice, onChoice, onAdvance]);
12923
+ }, [isTyping, skipTypewriter, dialogue.choices, selectedChoice, onChoice, onAdvance, choiceEvent, advanceEvent, eventBus]);
12712
12924
  const enabledChoices = dialogue.choices?.filter((c) => !c.disabled) ?? [];
12713
12925
  return /* @__PURE__ */ jsx(
12714
12926
  "div",
@@ -12750,6 +12962,7 @@ function DialogueBox({
12750
12962
  ),
12751
12963
  onClick: (e) => {
12752
12964
  e.stopPropagation();
12965
+ if (choiceEvent) eventBus.emit(`UI:${choiceEvent}`, { choice });
12753
12966
  onChoice?.(choice);
12754
12967
  },
12755
12968
  children: [