@almadar/ui 2.2.0 → 2.5.0

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.
@@ -2,9 +2,9 @@ import { useAuthContext } from '../chunk-42WRQA7T.js';
2
2
  export { ENTITY_EVENTS, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useCreateEntity, useDeepAgentGeneration, useDeleteEntity, useDisconnectGitHub, useEntities, useEntitiesByType, useEntity as useEntityById, useEntityMutations, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInput, useOrbitalHistory, useOrbitalMutations, usePhysics, usePlayer, usePreview, useResolvedEntity, useSelectedEntity, useSendOrbitalEvent, useSingletonEntity, useUIEvents, useUpdateEntity, useValidation } from '../chunk-42WRQA7T.js';
3
3
  import { DEFAULT_CONFIG, renderStateMachineToDomData, parseContentSegments } from '../chunk-N6DJVKZ6.js';
4
4
  import '../chunk-3HJHHULT.js';
5
- import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, EntityDisplayEvents, HealthBar, ScoreDisplay, StateIndicator, Container } from '../chunk-CC3UOKHI.js';
6
- export { Accordion, Card2 as ActionCard, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DataTable, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FloatingActionButton, Form, FormField, FormSectionHeader, Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LoadingState, MarkdownContent, MasterDetail, Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatCard, StateIndicator, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite } from '../chunk-CC3UOKHI.js';
7
- import '../chunk-DKQN5FVU.js';
5
+ import { VStack, HStack, Typography, Button, Icon, Box, Card, Avatar, Badge, SearchInput, Checkbox, Menu as Menu$1, Pagination, LoadingState, EmptyState, Modal, ErrorState, QuizBlock, CodeBlock, ScaledDiagram, MarkdownContent, Divider, ProgressBar, StatBadge, Stack, Select, Drawer, Toast, Tabs, Input, ThemeToggle, EntityDisplayEvents, StateIndicator, Container } from '../chunk-FYYU3CHN.js';
6
+ export { Accordion, ActionButtons, Card2 as ActionCard, Alert, Avatar, Badge, Box, Breadcrumb, Button, ButtonGroup, CalendarGrid, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Center, ChartLegend, Checkbox, CodeBlock, ConditionalWrapper, Container, ControlButton, DPad, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DetailPanel, Divider, Drawer, EmptyState, EntityDisplayEvents, ErrorBoundary, ErrorState, FilterGroup, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormField, FormSectionHeader, GraphView, Grid, HStack, Heading, HealthBar, Icon, Input, InputGroup, Label, LawReferenceTooltip, LineChart, LoadingState, MapView, MarkdownContent, MasterDetail, Menu, Modal, Overlay, PageHeader, Pagination, Popover, ProgressBar, ProgressDots, QuizBlock, Radio, RelationSelect, RepeatableFormSection, ScaledDiagram, ScoreDisplay, SearchInput, Select, SidePanel, SimpleGrid, Skeleton, SlotContentRenderer, Spacer, Spinner, Sprite, Stack, StatBadge, StatCard, StateIndicator, Switch, Tabs, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Toast, Tooltip, Typography, UISlotComponent, UISlotRenderer, VStack, ViolationAlert, WizardNavigation, WizardProgress, drawSprite } from '../chunk-FYYU3CHN.js';
7
+ import '../chunk-YLKXEXBP.js';
8
8
  import { useTranslate } from '../chunk-GOZKH7QW.js';
9
9
  export { EntityDataProvider, I18nProvider, createTranslate, entityDataKeys, parseQueryBinding, useEntity, useEntityDataAdapter, useEntityDetail, useEntityList, useEntityListSuspense, useEntitySuspense, useQuerySingleton, useTranslate } from '../chunk-GOZKH7QW.js';
10
10
  import { useEventBus, useEventListener } from '../chunk-YXZM3WCF.js';
@@ -13,6 +13,7 @@ export { DEFAULT_SLOTS, useUISlotManager } from '../chunk-3JGAROCW.js';
13
13
  import { cn, getNestedValue } from '../chunk-KKCVDUK7.js';
14
14
  export { cn } from '../chunk-KKCVDUK7.js';
15
15
  import '../chunk-TSETXL2E.js';
16
+ import '../chunk-K2D5D3WK.js';
16
17
  export { clearEntities, getAllEntities, getByType, getEntity, getSingleton, removeEntity, spawnEntity, updateEntity, updateSingleton } from '../chunk-N7MVUW4R.js';
17
18
  import { __publicField } from '../chunk-PKBMQBKP.js';
18
19
  import * as React from 'react';
@@ -832,7 +833,7 @@ var Table = ({
832
833
  Table.displayName = "Table";
833
834
  function normalizeFields(fields) {
834
835
  if (!fields) return [];
835
- return fields.map((f) => typeof f === "string" ? f : f.key);
836
+ return fields.map((f) => typeof f === "string" ? f : f.key ?? f.name ?? "");
836
837
  }
837
838
  var STATUS_STYLES = {
838
839
  complete: {
@@ -4526,6 +4527,17 @@ function IsometricCanvas({
4526
4527
  if (isLoading) {
4527
4528
  return /* @__PURE__ */ jsx(LoadingState, { className });
4528
4529
  }
4530
+ if (sortedTiles.length === 0) {
4531
+ return /* @__PURE__ */ jsx(
4532
+ EmptyState,
4533
+ {
4534
+ title: t("canvas.emptyTitle"),
4535
+ message: t("canvas.emptyMessage"),
4536
+ icon: "map",
4537
+ className
4538
+ }
4539
+ );
4540
+ }
4529
4541
  return /* @__PURE__ */ jsxs(
4530
4542
  Box,
4531
4543
  {
@@ -4536,6 +4548,7 @@ function IsometricCanvas({
4536
4548
  "canvas",
4537
4549
  {
4538
4550
  ref: canvasRef,
4551
+ "data-testid": "game-canvas",
4539
4552
  onClick: handleClick,
4540
4553
  onMouseDown: enableCamera ? handleMouseDown : void 0,
4541
4554
  onMouseMove: handleMouseMoveWithCamera,
@@ -4550,6 +4563,27 @@ function IsometricCanvas({
4550
4563
  }
4551
4564
  }
4552
4565
  ),
4566
+ process.env.NODE_ENV !== "production" && /* @__PURE__ */ jsxs("div", { "data-game-actions": "", className: "sr-only", "aria-hidden": "true", children: [
4567
+ tileClickEvent && /* @__PURE__ */ jsx(
4568
+ "button",
4569
+ {
4570
+ "data-event": tileClickEvent,
4571
+ "data-x": "0",
4572
+ "data-y": "0",
4573
+ onClick: () => eventBus.emit(`UI:${tileClickEvent}`, { x: 0, y: 0 }),
4574
+ children: tileClickEvent
4575
+ }
4576
+ ),
4577
+ unitClickEvent && units && units.length > 0 && /* @__PURE__ */ jsx(
4578
+ "button",
4579
+ {
4580
+ "data-event": unitClickEvent,
4581
+ "data-unit-id": units[0].id,
4582
+ onClick: () => eventBus.emit(`UI:${unitClickEvent}`, { unitId: units[0].id }),
4583
+ children: unitClickEvent
4584
+ }
4585
+ )
4586
+ ] }),
4553
4587
  showMinimap && /* @__PURE__ */ jsx(
4554
4588
  "canvas",
4555
4589
  {
@@ -4564,6 +4598,193 @@ function IsometricCanvas({
4564
4598
  }
4565
4599
  IsometricCanvas.displayName = "IsometricCanvas";
4566
4600
  var IsometricCanvas_default = IsometricCanvas;
4601
+ var PLATFORM_COLORS = {
4602
+ ground: "#4a7c59",
4603
+ platform: "#7c6b4a",
4604
+ hazard: "#c0392b",
4605
+ goal: "#f1c40f"
4606
+ };
4607
+ var PLAYER_COLOR = "#3498db";
4608
+ var PLAYER_EYE_COLOR = "#ffffff";
4609
+ var SKY_GRADIENT_TOP = "#1a1a2e";
4610
+ var SKY_GRADIENT_BOTTOM = "#16213e";
4611
+ var GRID_COLOR = "rgba(255, 255, 255, 0.03)";
4612
+ function PlatformerCanvas({
4613
+ player,
4614
+ platforms = [],
4615
+ worldWidth = 800,
4616
+ worldHeight = 400,
4617
+ canvasWidth = 800,
4618
+ canvasHeight = 400,
4619
+ followCamera = true,
4620
+ bgColor,
4621
+ leftEvent = "MOVE_LEFT",
4622
+ rightEvent = "MOVE_RIGHT",
4623
+ jumpEvent = "JUMP",
4624
+ stopEvent = "STOP",
4625
+ className,
4626
+ entity
4627
+ }) {
4628
+ const canvasRef = useRef(null);
4629
+ const eventBus = useEventBus();
4630
+ const keysRef = useRef(/* @__PURE__ */ new Set());
4631
+ const resolvedPlayer = player ?? {
4632
+ x: entity?.x ?? 50,
4633
+ y: entity?.y ?? 300,
4634
+ width: entity?.width ?? 24,
4635
+ height: entity?.height ?? 32,
4636
+ vx: entity?.vx ?? 0,
4637
+ vy: entity?.vy ?? 0,
4638
+ grounded: entity?.grounded ?? false,
4639
+ facingRight: entity?.facingRight ?? true
4640
+ };
4641
+ const handleKeyDown = useCallback((e) => {
4642
+ if (keysRef.current.has(e.code)) return;
4643
+ keysRef.current.add(e.code);
4644
+ switch (e.code) {
4645
+ case "ArrowLeft":
4646
+ case "KeyA":
4647
+ eventBus.emit(`UI:${leftEvent}`, { direction: -1 });
4648
+ break;
4649
+ case "ArrowRight":
4650
+ case "KeyD":
4651
+ eventBus.emit(`UI:${rightEvent}`, { direction: 1 });
4652
+ break;
4653
+ case "ArrowUp":
4654
+ case "KeyW":
4655
+ case "Space":
4656
+ eventBus.emit(`UI:${jumpEvent}`, {});
4657
+ e.preventDefault();
4658
+ break;
4659
+ }
4660
+ }, [eventBus, leftEvent, rightEvent, jumpEvent]);
4661
+ const handleKeyUp = useCallback((e) => {
4662
+ keysRef.current.delete(e.code);
4663
+ switch (e.code) {
4664
+ case "ArrowLeft":
4665
+ case "KeyA":
4666
+ case "ArrowRight":
4667
+ case "KeyD":
4668
+ eventBus.emit(`UI:${stopEvent}`, {});
4669
+ break;
4670
+ }
4671
+ }, [eventBus, stopEvent]);
4672
+ useEffect(() => {
4673
+ window.addEventListener("keydown", handleKeyDown);
4674
+ window.addEventListener("keyup", handleKeyUp);
4675
+ return () => {
4676
+ window.removeEventListener("keydown", handleKeyDown);
4677
+ window.removeEventListener("keyup", handleKeyUp);
4678
+ };
4679
+ }, [handleKeyDown, handleKeyUp]);
4680
+ useEffect(() => {
4681
+ const canvas = canvasRef.current;
4682
+ if (!canvas) return;
4683
+ const ctx = canvas.getContext("2d");
4684
+ if (!ctx) return;
4685
+ const dpr = window.devicePixelRatio || 1;
4686
+ canvas.width = canvasWidth * dpr;
4687
+ canvas.height = canvasHeight * dpr;
4688
+ ctx.scale(dpr, dpr);
4689
+ let camX = 0;
4690
+ let camY = 0;
4691
+ if (followCamera) {
4692
+ camX = Math.max(0, Math.min(resolvedPlayer.x - canvasWidth / 2, worldWidth - canvasWidth));
4693
+ camY = Math.max(0, Math.min(resolvedPlayer.y - canvasHeight / 2 - 50, worldHeight - canvasHeight));
4694
+ }
4695
+ if (bgColor) {
4696
+ ctx.fillStyle = bgColor;
4697
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
4698
+ } else {
4699
+ const grad = ctx.createLinearGradient(0, 0, 0, canvasHeight);
4700
+ grad.addColorStop(0, SKY_GRADIENT_TOP);
4701
+ grad.addColorStop(1, SKY_GRADIENT_BOTTOM);
4702
+ ctx.fillStyle = grad;
4703
+ ctx.fillRect(0, 0, canvasWidth, canvasHeight);
4704
+ }
4705
+ ctx.strokeStyle = GRID_COLOR;
4706
+ ctx.lineWidth = 1;
4707
+ const gridSize = 32;
4708
+ for (let gx = -camX % gridSize; gx < canvasWidth; gx += gridSize) {
4709
+ ctx.beginPath();
4710
+ ctx.moveTo(gx, 0);
4711
+ ctx.lineTo(gx, canvasHeight);
4712
+ ctx.stroke();
4713
+ }
4714
+ for (let gy = -camY % gridSize; gy < canvasHeight; gy += gridSize) {
4715
+ ctx.beginPath();
4716
+ ctx.moveTo(0, gy);
4717
+ ctx.lineTo(canvasWidth, gy);
4718
+ ctx.stroke();
4719
+ }
4720
+ for (const plat of platforms) {
4721
+ const px = plat.x - camX;
4722
+ const py = plat.y - camY;
4723
+ const color = PLATFORM_COLORS[plat.type ?? "ground"] ?? PLATFORM_COLORS.ground;
4724
+ ctx.fillStyle = color;
4725
+ ctx.fillRect(px, py, plat.width, plat.height);
4726
+ ctx.fillStyle = "rgba(255, 255, 255, 0.15)";
4727
+ ctx.fillRect(px, py, plat.width, 3);
4728
+ ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
4729
+ ctx.fillRect(px, py + plat.height - 2, plat.width, 2);
4730
+ if (plat.type === "hazard") {
4731
+ ctx.strokeStyle = "#e74c3c";
4732
+ ctx.lineWidth = 2;
4733
+ for (let sx = px; sx < px + plat.width; sx += 12) {
4734
+ ctx.beginPath();
4735
+ ctx.moveTo(sx, py);
4736
+ ctx.lineTo(sx + 6, py + plat.height);
4737
+ ctx.stroke();
4738
+ }
4739
+ }
4740
+ if (plat.type === "goal") {
4741
+ ctx.fillStyle = "rgba(241, 196, 15, 0.5)";
4742
+ ctx.beginPath();
4743
+ ctx.arc(px + plat.width / 2, py - 10, 8, 0, Math.PI * 2);
4744
+ ctx.fill();
4745
+ }
4746
+ }
4747
+ const pw = resolvedPlayer.width ?? 24;
4748
+ const ph = resolvedPlayer.height ?? 32;
4749
+ const ppx = resolvedPlayer.x - camX;
4750
+ const ppy = resolvedPlayer.y - camY;
4751
+ ctx.fillStyle = PLAYER_COLOR;
4752
+ const radius = Math.min(pw, ph) * 0.25;
4753
+ ctx.beginPath();
4754
+ ctx.moveTo(ppx + radius, ppy);
4755
+ ctx.lineTo(ppx + pw - radius, ppy);
4756
+ ctx.quadraticCurveTo(ppx + pw, ppy, ppx + pw, ppy + radius);
4757
+ ctx.lineTo(ppx + pw, ppy + ph - radius);
4758
+ ctx.quadraticCurveTo(ppx + pw, ppy + ph, ppx + pw - radius, ppy + ph);
4759
+ ctx.lineTo(ppx + radius, ppy + ph);
4760
+ ctx.quadraticCurveTo(ppx, ppy + ph, ppx, ppy + ph - radius);
4761
+ ctx.lineTo(ppx, ppy + radius);
4762
+ ctx.quadraticCurveTo(ppx, ppy, ppx + radius, ppy);
4763
+ ctx.fill();
4764
+ const eyeY = ppy + ph * 0.3;
4765
+ const eyeSize = 3;
4766
+ const facingRight = resolvedPlayer.facingRight ?? true;
4767
+ const eyeOffsetX = facingRight ? pw * 0.55 : pw * 0.2;
4768
+ ctx.fillStyle = PLAYER_EYE_COLOR;
4769
+ ctx.beginPath();
4770
+ ctx.arc(ppx + eyeOffsetX, eyeY, eyeSize, 0, Math.PI * 2);
4771
+ ctx.fill();
4772
+ ctx.beginPath();
4773
+ ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
4774
+ ctx.fill();
4775
+ });
4776
+ return /* @__PURE__ */ jsx(
4777
+ "canvas",
4778
+ {
4779
+ ref: canvasRef,
4780
+ style: { width: canvasWidth, height: canvasHeight },
4781
+ className: cn("block rounded-lg border border-white/10", className),
4782
+ "data-testid": "platformer-canvas",
4783
+ tabIndex: 0
4784
+ }
4785
+ );
4786
+ }
4787
+ PlatformerCanvas.displayName = "PlatformerCanvas";
4567
4788
 
4568
4789
  // components/organisms/game/types/effects.ts
4569
4790
  var EMPTY_EFFECT_STATE = {
@@ -6610,76 +6831,6 @@ function usePhysics2D(options = {}) {
6610
6831
  reset
6611
6832
  };
6612
6833
  }
6613
- var sizeMap = {
6614
- sm: "text-xs px-2 py-1",
6615
- md: "text-sm px-3 py-1.5",
6616
- lg: "text-base px-4 py-2"
6617
- };
6618
- var variantMap = {
6619
- default: "bg-gray-800/80 border-gray-700",
6620
- primary: "bg-blue-900/80 border-blue-700",
6621
- success: "bg-green-900/80 border-green-700",
6622
- warning: "bg-yellow-900/80 border-yellow-700",
6623
- danger: "bg-red-900/80 border-red-700"
6624
- };
6625
- function StatBadge({
6626
- label,
6627
- value = 0,
6628
- max,
6629
- format = "number",
6630
- icon,
6631
- size = "md",
6632
- variant = "default",
6633
- className,
6634
- // Ignored config props (used for schema binding)
6635
- source: _source,
6636
- field: _field
6637
- }) {
6638
- const numValue = typeof value === "number" ? value : parseInt(String(value), 10) || 0;
6639
- return /* @__PURE__ */ jsxs(
6640
- "div",
6641
- {
6642
- className: cn(
6643
- "inline-flex items-center gap-2 rounded-lg border backdrop-blur-sm",
6644
- sizeMap[size] ?? sizeMap.md,
6645
- variantMap[variant] ?? variantMap.default,
6646
- className
6647
- ),
6648
- children: [
6649
- icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-lg", children: icon }),
6650
- /* @__PURE__ */ jsx("span", { className: "text-gray-400 font-medium", children: label }),
6651
- format === "hearts" && max && /* @__PURE__ */ jsx(
6652
- HealthBar,
6653
- {
6654
- current: numValue,
6655
- max,
6656
- format: "hearts",
6657
- size: size === "lg" ? "md" : "sm"
6658
- }
6659
- ),
6660
- format === "bar" && max && /* @__PURE__ */ jsx(
6661
- HealthBar,
6662
- {
6663
- current: numValue,
6664
- max,
6665
- format: "bar",
6666
- size: size === "lg" ? "md" : "sm"
6667
- }
6668
- ),
6669
- format === "number" && /* @__PURE__ */ jsx(
6670
- ScoreDisplay,
6671
- {
6672
- value: numValue,
6673
- size: size === "lg" ? "md" : "sm",
6674
- animated: true
6675
- }
6676
- ),
6677
- format === "text" && /* @__PURE__ */ jsx("span", { className: "font-bold text-white", children: value })
6678
- ]
6679
- }
6680
- );
6681
- }
6682
- StatBadge.displayName = "StatBadge";
6683
6834
  var positionMap = {
6684
6835
  top: "top-0 left-0 right-0 flex justify-between items-start p-4",
6685
6836
  bottom: "bottom-0 left-0 right-0 flex justify-between items-end p-4",
@@ -6695,9 +6846,14 @@ function convertElementsToStats(elements) {
6695
6846
  timer: "Time"
6696
6847
  };
6697
6848
  return {
6698
- label: el.label || labelMap[el.type] || el.type,
6849
+ label: el.label || labelMap[el.type ?? ""] || el.type || "",
6699
6850
  source,
6700
- field
6851
+ field,
6852
+ // Pass through direct values from compiled render-ui effects
6853
+ ...el.value !== void 0 && { value: el.value },
6854
+ ...el.icon !== void 0 && { icon: el.icon },
6855
+ ...el.format !== void 0 && { format: el.format },
6856
+ ...el.max !== void 0 && { max: el.max }
6701
6857
  };
6702
6858
  });
6703
6859
  }
@@ -6710,7 +6866,8 @@ function GameHud({
6710
6866
  className,
6711
6867
  transparent = true
6712
6868
  }) {
6713
- const stats = propStats ?? items ?? (elements ? convertElementsToStats(elements) : []);
6869
+ const rawStats = propStats ?? items ?? (elements && Array.isArray(elements) ? convertElementsToStats(elements) : []);
6870
+ const stats = Array.isArray(rawStats) ? rawStats : [];
6714
6871
  const position = propPosition ?? "corners";
6715
6872
  if (position === "corners") {
6716
6873
  const leftStats = stats.slice(0, Math.ceil(stats.length / 2));
@@ -6735,7 +6892,7 @@ function GameHud({
6735
6892
  );
6736
6893
  }
6737
6894
  GameHud.displayName = "GameHud";
6738
- var variantMap2 = {
6895
+ var variantMap = {
6739
6896
  primary: "bg-blue-600 hover:bg-blue-500 text-white border-blue-400 shadow-lg shadow-blue-500/25",
6740
6897
  secondary: "bg-gray-700 hover:bg-gray-600 text-white border-gray-500",
6741
6898
  ghost: "bg-transparent hover:bg-white/10 text-white border-white/20"
@@ -6814,7 +6971,7 @@ function GameMenu({
6814
6971
  "transition-all duration-200 transform",
6815
6972
  "hover:scale-105 active:scale-95",
6816
6973
  "focus:outline-none focus:ring-4 focus:ring-white/25",
6817
- variantMap2[option.variant ?? "secondary"] ?? variantMap2.secondary,
6974
+ variantMap[option.variant ?? "secondary"] ?? variantMap.secondary,
6818
6975
  option.disabled && "opacity-50 cursor-not-allowed hover:scale-100"
6819
6976
  ),
6820
6977
  style: {
@@ -6980,10 +7137,13 @@ function InventoryPanel({
6980
7137
  const eventBus = useEventBus();
6981
7138
  const [hoveredSlot, setHoveredSlot] = useState(null);
6982
7139
  const [tooltipPosition, setTooltipPosition] = useState({ x: 0, y: 0 });
6983
- const slotArray = Array.from({ length: slots }, (_, index) => {
6984
- return items[index] ?? null;
7140
+ const safeItems = Array.isArray(items) ? items : [];
7141
+ const safeSlots = typeof slots === "number" && slots > 0 ? slots : 0;
7142
+ const safeColumns = typeof columns === "number" && columns > 0 ? columns : 1;
7143
+ const slotArray = Array.from({ length: safeSlots }, (_, index) => {
7144
+ return safeItems[index] ?? null;
6985
7145
  });
6986
- const rows = Math.ceil(slots / columns);
7146
+ const rows = Math.ceil(safeSlots / safeColumns);
6987
7147
  const handleSlotClick = useCallback((index) => {
6988
7148
  if (selectSlotEvent) eventBus.emit(`UI:${selectSlotEvent}`, { index });
6989
7149
  onSelectSlot?.(index);
@@ -7016,7 +7176,7 @@ function InventoryPanel({
7016
7176
  break;
7017
7177
  case "ArrowRight":
7018
7178
  e.preventDefault();
7019
- onSelectSlot?.(Math.min(index + 1, slots - 1));
7179
+ onSelectSlot?.(Math.min(index + 1, safeSlots - 1));
7020
7180
  break;
7021
7181
  case "ArrowLeft":
7022
7182
  e.preventDefault();
@@ -7024,14 +7184,14 @@ function InventoryPanel({
7024
7184
  break;
7025
7185
  case "ArrowDown":
7026
7186
  e.preventDefault();
7027
- onSelectSlot?.(Math.min(index + columns, slots - 1));
7187
+ onSelectSlot?.(Math.min(index + safeColumns, safeSlots - 1));
7028
7188
  break;
7029
7189
  case "ArrowUp":
7030
7190
  e.preventDefault();
7031
- onSelectSlot?.(Math.max(index - columns, 0));
7191
+ onSelectSlot?.(Math.max(index - safeColumns, 0));
7032
7192
  break;
7033
7193
  }
7034
- }, [slotArray, onUseItem, onDropItem, onSelectSlot, columns, slots, useItemEvent, dropItemEvent, eventBus]);
7194
+ }, [slotArray, onUseItem, onDropItem, onSelectSlot, safeColumns, safeSlots, useItemEvent, dropItemEvent, eventBus]);
7035
7195
  const handleMouseEnter = useCallback((e, index) => {
7036
7196
  if (showTooltips && slotArray[index]) {
7037
7197
  setHoveredSlot(index);
@@ -7051,7 +7211,7 @@ function InventoryPanel({
7051
7211
  {
7052
7212
  className: "grid gap-1 bg-gray-900 p-2 rounded-lg border border-gray-700",
7053
7213
  style: {
7054
- gridTemplateColumns: `repeat(${columns}, ${slotSize}px)`,
7214
+ gridTemplateColumns: `repeat(${safeColumns}, ${slotSize}px)`,
7055
7215
  gridTemplateRows: `repeat(${rows}, ${slotSize}px)`
7056
7216
  },
7057
7217
  children: slotArray.map((item, index) => /* @__PURE__ */ jsx(
@@ -11224,6 +11384,55 @@ var ToastSlot = ({
11224
11384
  ) });
11225
11385
  };
11226
11386
  ToastSlot.displayName = "ToastSlot";
11387
+ var nextId = 0;
11388
+ function NotifyListener() {
11389
+ const eventBus = useEventBus();
11390
+ const [items, setItems] = useState([]);
11391
+ const [portalRoot, setPortalRoot] = useState(null);
11392
+ useEffect(() => {
11393
+ let root = document.getElementById("ui-notify-portal-root");
11394
+ if (!root) {
11395
+ root = document.createElement("div");
11396
+ root.id = "ui-notify-portal-root";
11397
+ document.body.appendChild(root);
11398
+ }
11399
+ setPortalRoot(root);
11400
+ }, []);
11401
+ const handleDismiss = useCallback((id) => {
11402
+ setItems((prev) => prev.filter((item) => item.id !== id));
11403
+ }, []);
11404
+ useEffect(() => {
11405
+ const unsubscribe = eventBus.on("UI:NOTIFY", (event) => {
11406
+ const payload = event.payload ?? event;
11407
+ const message = typeof payload.message === "string" ? payload.message : "Notification";
11408
+ const severityMap = {
11409
+ success: "success",
11410
+ error: "error",
11411
+ warning: "warning",
11412
+ info: "info"
11413
+ };
11414
+ const variant = severityMap[String(payload.severity)] || "info";
11415
+ const id = ++nextId;
11416
+ setItems((prev) => [...prev, { id, message, variant }]);
11417
+ });
11418
+ return unsubscribe;
11419
+ }, [eventBus]);
11420
+ if (!portalRoot || items.length === 0) return null;
11421
+ return createPortal(
11422
+ /* @__PURE__ */ jsx(Box, { className: "fixed bottom-4 right-4 z-50 pointer-events-auto flex flex-col gap-2", children: items.map((item) => /* @__PURE__ */ jsx(
11423
+ Toast,
11424
+ {
11425
+ variant: item.variant,
11426
+ message: item.message,
11427
+ duration: 5e3,
11428
+ onDismiss: () => handleDismiss(item.id)
11429
+ },
11430
+ item.id
11431
+ )) }),
11432
+ portalRoot
11433
+ );
11434
+ }
11435
+ NotifyListener.displayName = "NotifyListener";
11227
11436
  var CHART_COLORS = [
11228
11437
  "var(--color-primary)",
11229
11438
  "var(--color-success)",
@@ -11344,7 +11553,7 @@ var PieChart = ({ data, height, showValues, donut = false }) => {
11344
11553
  ] }, idx)) })
11345
11554
  ] });
11346
11555
  };
11347
- var LineChart = ({ data, height, showValues, fill = false }) => {
11556
+ var LineChart2 = ({ data, height, showValues, fill = false }) => {
11348
11557
  const maxValue = Math.max(...data.map((d) => d.value), 1);
11349
11558
  const width = 400;
11350
11559
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
@@ -11460,8 +11669,8 @@ var Chart = ({
11460
11669
  ] }),
11461
11670
  /* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
11462
11671
  chartType === "bar" && /* @__PURE__ */ jsx(BarChart, { data: normalizedData, height, showValues }),
11463
- chartType === "line" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues }),
11464
- chartType === "area" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
11672
+ chartType === "line" && /* @__PURE__ */ jsx(LineChart2, { data: normalizedData, height, showValues }),
11673
+ chartType === "area" && /* @__PURE__ */ jsx(LineChart2, { data: normalizedData, height, showValues, fill: true }),
11465
11674
  chartType === "pie" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
11466
11675
  chartType === "donut" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
11467
11676
  ] }),
@@ -13844,4 +14053,4 @@ function WorldMapTemplate({
13844
14053
  }
13845
14054
  WorldMapTemplate.displayName = "WorldMapTemplate";
13846
14055
 
13847
- export { ALL_PRESETS, AR_BOOK_FIELDS, ActionPalette, ActionTile, AuthLayout, BattleBoard, BattleTemplate, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, BuilderBoard, CanvasEffect, CastleBoard, CastleTemplate, Chart, ClassifierBoard, CodeView, CodeViewer, CollapsibleSection, CombatLog, ConfirmDialog, ContentRenderer, CounterTemplate, DIAMOND_TOP_Y, DashboardGrid, DashboardLayout, DebuggerBoard, DialogueBox, DocumentViewer, StateMachineView as DomStateMachineVisualizer, DrawerSlot, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FormActions, FormLayout, FormSection, GameAudioContext, GameAudioProvider, GameAudioToggle, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GraphCanvas, Header, IDENTITY_BOOK_FIELDS, InventoryPanel, IsometricCanvas, JazariStateMachine, List, MediaGallery, Meter, ModalSlot, Navigation, NegotiatorBoard, ObjectRulePanel, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, PhysicsManager, RuleEditor, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, Section, SequenceBar, SequencerBoard, Sidebar, SignaturePad, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Split, SplitPane, StateArchitectBoard, StateMachineView, StateNode2 as StateNode, StatusBar, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, Table, TerrainPalette, Timeline, ToastSlot, TraitSlot, TraitStateViewer, TransitionArrow, UncontrolledBattleBoard, VariablePanel, WizardContainer, WorldMapBoard, WorldMapTemplate, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, generateCombatMessage, getCurrentFrame, inferDirection, isoToScreen, mapBookData, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, transitionAnimation, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };
14056
+ export { ALL_PRESETS, AR_BOOK_FIELDS, ActionPalette, ActionTile, AuthLayout, BattleBoard, BattleTemplate, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, BuilderBoard, CanvasEffect, CastleBoard, CastleTemplate, Chart, ClassifierBoard, CodeView, CodeViewer, CollapsibleSection, CombatLog, ConfirmDialog, ContentRenderer, CounterTemplate, DIAMOND_TOP_Y, DashboardGrid, DashboardLayout, DebuggerBoard, DialogueBox, DocumentViewer, StateMachineView as DomStateMachineVisualizer, DrawerSlot, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FormActions, FormLayout, FormSection, GameAudioContext, GameAudioProvider, GameAudioToggle, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GraphCanvas, Header, IDENTITY_BOOK_FIELDS, InventoryPanel, IsometricCanvas, JazariStateMachine, List, MediaGallery, Meter, ModalSlot, Navigation, NegotiatorBoard, NotifyListener, ObjectRulePanel, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, PhysicsManager, PlatformerCanvas, RuleEditor, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, Section, SequenceBar, SequencerBoard, Sidebar, SignaturePad, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Split, SplitPane, StateArchitectBoard, StateMachineView, StateNode2 as StateNode, StatusBar, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, Table, TerrainPalette, Timeline, ToastSlot, TraitSlot, TraitStateViewer, TransitionArrow, UncontrolledBattleBoard, VariablePanel, WizardContainer, WorldMapBoard, WorldMapTemplate, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, combatAnimations, combatClasses, combatEffects, createInitialGameState, createUnitAnimationState, generateCombatMessage, getCurrentFrame, inferDirection, isoToScreen, mapBookData, pendulum, projectileMotion, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, springOscillator, tickAnimationState, transitionAnimation, useBattleState, useCamera, useGameAudio, useGameAudioContext, useImageCache, usePhysics2D, useSpriteAnimations };
@@ -1,5 +1,5 @@
1
- import { ThemeProvider, useTheme } from '../chunk-DKQN5FVU.js';
2
- export { BUILT_IN_THEMES, ThemeContext_default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, useSlotContent, useSlotHasContent, useTheme, useUISlots } from '../chunk-DKQN5FVU.js';
1
+ import { ThemeProvider, useTheme } from '../chunk-YLKXEXBP.js';
2
+ export { BUILT_IN_THEMES, ThemeContext_default as ThemeContext, ThemeProvider, UISlotContext, UISlotProvider, useSlotContent, useSlotHasContent, useTheme, useUISlots } from '../chunk-YLKXEXBP.js';
3
3
  import '../chunk-3JGAROCW.js';
4
4
  import '../chunk-PKBMQBKP.js';
5
5
  import { createContext, useCallback, useMemo, useContext } from 'react';
@@ -1,5 +1,5 @@
1
- import { SuspenseConfigProvider } from '../chunk-CC3UOKHI.js';
2
- import { ThemeProvider } from '../chunk-DKQN5FVU.js';
1
+ import { SuspenseConfigProvider } from '../chunk-FYYU3CHN.js';
2
+ import { ThemeProvider } from '../chunk-YLKXEXBP.js';
3
3
  import { SelectionProvider, EntityDataProvider } from '../chunk-GOZKH7QW.js';
4
4
  export { SelectionContext, SelectionProvider, useSelection, useSelectionOptional } from '../chunk-GOZKH7QW.js';
5
5
  import { useEventBus, EventBusProvider } from '../chunk-YXZM3WCF.js';
@@ -8,7 +8,7 @@ import '../chunk-3JGAROCW.js';
8
8
  import { recordTransition, registerCheck, bindEventBus, bindTraitStateGetter } from '../chunk-45CTDYBT.js';
9
9
  import '../chunk-KKCVDUK7.js';
10
10
  import '../chunk-TSETXL2E.js';
11
- import { useOfflineExecutor } from '../chunk-PL7MD6GF.js';
11
+ import { useOfflineExecutor } from '../chunk-K2D5D3WK.js';
12
12
  import '../chunk-PKBMQBKP.js';
13
13
  import { createContext, useState, useCallback, useMemo, useContext, useRef, useEffect } from 'react';
14
14
  import { jsx, Fragment } from 'react/jsx-runtime';
@@ -344,7 +344,7 @@ declare function getSlotDefinition(slot: UISlot): SlotDefinition;
344
344
  /**
345
345
  * Check if a slot is a portal slot.
346
346
  */
347
- declare function isPortalSlot(slot: UISlot): boolean;
347
+ declare function isPortalSlot(slot: string): boolean;
348
348
  /**
349
349
  * Check if a slot is an inline slot.
350
350
  */