@almadar/ui 5.12.0 → 5.13.2

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.
@@ -14619,7 +14619,7 @@ var init_MapView = __esm({
14619
14619
  shadowSize: [41, 41]
14620
14620
  });
14621
14621
  L.Marker.prototype.options.icon = defaultIcon;
14622
- const { useEffect: useEffect89, useRef: useRef88, useCallback: useCallback130, useState: useState124 } = React98__namespace.default;
14622
+ const { useEffect: useEffect89, useRef: useRef88, useCallback: useCallback130, useState: useState125 } = React98__namespace.default;
14623
14623
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
14624
14624
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
14625
14625
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -14664,7 +14664,7 @@ var init_MapView = __esm({
14664
14664
  showAttribution = true
14665
14665
  }) {
14666
14666
  const eventBus = useEventBus3();
14667
- const [clickedPosition, setClickedPosition] = useState124(null);
14667
+ const [clickedPosition, setClickedPosition] = useState125(null);
14668
14668
  const handleMapClick = useCallback130((lat, lng) => {
14669
14669
  if (showClickedPin) {
14670
14670
  setClickedPosition({ lat, lng });
@@ -21491,6 +21491,7 @@ function CalendarGrid({
21491
21491
  swipeRightEvent,
21492
21492
  dayWindow = "auto"
21493
21493
  }) {
21494
+ const evs = Array.isArray(events2) ? events2 : events2 ? [events2] : [];
21494
21495
  const eventBus = useEventBus();
21495
21496
  const longPressTimer = React98.useRef(null);
21496
21497
  const resolvedWeekStart = React98.useMemo(
@@ -21539,7 +21540,7 @@ function CalendarGrid({
21539
21540
  [onEventClick]
21540
21541
  );
21541
21542
  const eventsForDayCount = React98.useCallback(
21542
- (day) => events2.filter(
21543
+ (day) => evs.filter(
21543
21544
  (ev) => new Date(ev.startTime).toDateString() === day.toDateString()
21544
21545
  ).length,
21545
21546
  [events2]
@@ -21654,7 +21655,7 @@ function CalendarGrid({
21654
21655
  }
21655
21656
  ) }),
21656
21657
  visibleDays.map((day) => {
21657
- const slotEvents = events2.filter(
21658
+ const slotEvents = evs.filter(
21658
21659
  (ev) => eventInSlot(ev, day, time)
21659
21660
  );
21660
21661
  const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
@@ -30441,8 +30442,16 @@ function GameCanvas2D({
30441
30442
  drawEventRef.current = drawEvent;
30442
30443
  const emitRef = React98__namespace.useRef(emit);
30443
30444
  emitRef.current = emit;
30445
+ const assetBaseUrlRef = React98__namespace.useRef(assetBaseUrl);
30446
+ assetBaseUrlRef.current = assetBaseUrl;
30447
+ const backgroundImageRef = React98__namespace.useRef(backgroundImage);
30448
+ backgroundImageRef.current = backgroundImage;
30449
+ const widthRef = React98__namespace.useRef(width);
30450
+ widthRef.current = width;
30451
+ const heightRef = React98__namespace.useRef(height);
30452
+ heightRef.current = height;
30444
30453
  const loadImage = React98__namespace.useCallback((url) => {
30445
- const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
30454
+ const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
30446
30455
  const cached = imageCache.current.get(fullUrl);
30447
30456
  if (cached?.complete && cached.naturalWidth > 0) return cached;
30448
30457
  if (!cached) {
@@ -30452,7 +30461,7 @@ function GameCanvas2D({
30452
30461
  imageCache.current.set(fullUrl, img);
30453
30462
  }
30454
30463
  return null;
30455
- }, [assetBaseUrl]);
30464
+ }, []);
30456
30465
  React98__namespace.useEffect(() => {
30457
30466
  const canvas = canvasRef.current;
30458
30467
  if (!canvas) return;
@@ -30474,10 +30483,10 @@ function GameCanvas2D({
30474
30483
  if (tickEventRef.current) {
30475
30484
  emitRef.current(tickEventRef.current, { dt, frame });
30476
30485
  }
30477
- if (backgroundImage) {
30478
- const bgImg = loadImage(backgroundImage);
30486
+ if (backgroundImageRef.current) {
30487
+ const bgImg = loadImage(backgroundImageRef.current);
30479
30488
  if (bgImg) {
30480
- ctx.drawImage(bgImg, 0, 0, width, height);
30489
+ ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
30481
30490
  }
30482
30491
  }
30483
30492
  onDrawRef.current?.(ctx, frame);
@@ -30493,7 +30502,7 @@ function GameCanvas2D({
30493
30502
  running = false;
30494
30503
  cancelAnimationFrame(rafRef.current);
30495
30504
  };
30496
- }, [fps]);
30505
+ }, [fps, loadImage]);
30497
30506
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("inline-block", className), children: /* @__PURE__ */ jsxRuntime.jsx(
30498
30507
  "canvas",
30499
30508
  {
@@ -31635,15 +31644,22 @@ function PlatformerCanvas({
31635
31644
  const eventBus = useEventBus();
31636
31645
  const keysRef = React98.useRef(/* @__PURE__ */ new Set());
31637
31646
  const imageCache = React98.useRef(/* @__PURE__ */ new Map());
31647
+ const [loadedImages, setLoadedImages] = React98.useState(/* @__PURE__ */ new Set());
31638
31648
  const loadImage = React98.useCallback((url) => {
31639
31649
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
31640
31650
  const cached = imageCache.current.get(fullUrl);
31641
- if (cached?.complete && cached.naturalWidth > 0) return cached;
31651
+ if (cached?.complete && cached.naturalWidth > 0) {
31652
+ if (!loadedImages.has(fullUrl)) {
31653
+ setLoadedImages((prev) => new Set(prev).add(fullUrl));
31654
+ }
31655
+ return cached;
31656
+ }
31642
31657
  if (!cached) {
31643
31658
  const img = new Image();
31644
31659
  img.crossOrigin = "anonymous";
31645
31660
  img.src = fullUrl;
31646
31661
  img.onload = () => {
31662
+ setLoadedImages((prev) => new Set(prev).add(fullUrl));
31647
31663
  updateAssetStatus(fullUrl, "loaded");
31648
31664
  };
31649
31665
  img.onerror = () => {
@@ -31653,7 +31669,7 @@ function PlatformerCanvas({
31653
31669
  updateAssetStatus(fullUrl, "pending");
31654
31670
  }
31655
31671
  return null;
31656
- }, [assetBaseUrl]);
31672
+ }, [assetBaseUrl, loadedImages]);
31657
31673
  React98.useEffect(() => {
31658
31674
  if (typeof window === "undefined") return;
31659
31675
  const canvas = canvasRef.current;
@@ -31835,7 +31851,7 @@ function PlatformerCanvas({
31835
31851
  ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
31836
31852
  ctx.fill();
31837
31853
  }
31838
- });
31854
+ }, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
31839
31855
  return /* @__PURE__ */ jsxRuntime.jsx(
31840
31856
  "canvas",
31841
31857
  {
@@ -33864,7 +33880,7 @@ function useSafeEventBus10() {
33864
33880
  }
33865
33881
  }
33866
33882
  function SortableListInner({
33867
- items: initialItems = EMPTY_ITEMS,
33883
+ items: initialItemsProp = EMPTY_ITEMS,
33868
33884
  renderItem,
33869
33885
  reorderEvent,
33870
33886
  reorderPayload,
@@ -33872,6 +33888,7 @@ function SortableListInner({
33872
33888
  className
33873
33889
  }) {
33874
33890
  const eventBus = useSafeEventBus10();
33891
+ const initialItems = Array.isArray(initialItemsProp) ? initialItemsProp : initialItemsProp ? [initialItemsProp] : [];
33875
33892
  const handleReorder = React98.useCallback(
33876
33893
  (fromIndex, toIndex, item) => {
33877
33894
  eventBus.emit(`UI:${reorderEvent}`, {
@@ -37368,9 +37385,10 @@ var init_ReplyTree = __esm({
37368
37385
  showActions = true,
37369
37386
  className
37370
37387
  }) => {
37388
+ const nodeList = Array.isArray(nodes) ? nodes : nodes ? [nodes] : [];
37371
37389
  const [collapsedSet, setCollapsedSet] = React98.useState(() => {
37372
37390
  const acc = /* @__PURE__ */ new Set();
37373
- collectInitiallyCollapsed(nodes, acc);
37391
+ collectInitiallyCollapsed(nodeList, acc);
37374
37392
  return acc;
37375
37393
  });
37376
37394
  const toggleCollapse = React98.useCallback((id) => {
@@ -37384,10 +37402,10 @@ var init_ReplyTree = __esm({
37384
37402
  return next;
37385
37403
  });
37386
37404
  }, []);
37387
- if (nodes.length === 0) {
37405
+ if (nodeList.length === 0) {
37388
37406
  return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("text-sm text-muted-foreground", className), children: "No replies yet." });
37389
37407
  }
37390
- return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("flex flex-col gap-2 min-w-0", className), children: nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
37408
+ return /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("flex flex-col gap-2 min-w-0", className), children: nodeList.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
37391
37409
  ReplyTreeNode,
37392
37410
  {
37393
37411
  node,
package/dist/avl/index.js CHANGED
@@ -14570,7 +14570,7 @@ var init_MapView = __esm({
14570
14570
  shadowSize: [41, 41]
14571
14571
  });
14572
14572
  L.Marker.prototype.options.icon = defaultIcon;
14573
- const { useEffect: useEffect89, useRef: useRef88, useCallback: useCallback130, useState: useState124 } = React98__default;
14573
+ const { useEffect: useEffect89, useRef: useRef88, useCallback: useCallback130, useState: useState125 } = React98__default;
14574
14574
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
14575
14575
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
14576
14576
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -14615,7 +14615,7 @@ var init_MapView = __esm({
14615
14615
  showAttribution = true
14616
14616
  }) {
14617
14617
  const eventBus = useEventBus3();
14618
- const [clickedPosition, setClickedPosition] = useState124(null);
14618
+ const [clickedPosition, setClickedPosition] = useState125(null);
14619
14619
  const handleMapClick = useCallback130((lat, lng) => {
14620
14620
  if (showClickedPin) {
14621
14621
  setClickedPosition({ lat, lng });
@@ -21442,6 +21442,7 @@ function CalendarGrid({
21442
21442
  swipeRightEvent,
21443
21443
  dayWindow = "auto"
21444
21444
  }) {
21445
+ const evs = Array.isArray(events2) ? events2 : events2 ? [events2] : [];
21445
21446
  const eventBus = useEventBus();
21446
21447
  const longPressTimer = useRef(null);
21447
21448
  const resolvedWeekStart = useMemo(
@@ -21490,7 +21491,7 @@ function CalendarGrid({
21490
21491
  [onEventClick]
21491
21492
  );
21492
21493
  const eventsForDayCount = useCallback(
21493
- (day) => events2.filter(
21494
+ (day) => evs.filter(
21494
21495
  (ev) => new Date(ev.startTime).toDateString() === day.toDateString()
21495
21496
  ).length,
21496
21497
  [events2]
@@ -21605,7 +21606,7 @@ function CalendarGrid({
21605
21606
  }
21606
21607
  ) }),
21607
21608
  visibleDays.map((day) => {
21608
- const slotEvents = events2.filter(
21609
+ const slotEvents = evs.filter(
21609
21610
  (ev) => eventInSlot(ev, day, time)
21610
21611
  );
21611
21612
  const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
@@ -30392,8 +30393,16 @@ function GameCanvas2D({
30392
30393
  drawEventRef.current = drawEvent;
30393
30394
  const emitRef = React98.useRef(emit);
30394
30395
  emitRef.current = emit;
30396
+ const assetBaseUrlRef = React98.useRef(assetBaseUrl);
30397
+ assetBaseUrlRef.current = assetBaseUrl;
30398
+ const backgroundImageRef = React98.useRef(backgroundImage);
30399
+ backgroundImageRef.current = backgroundImage;
30400
+ const widthRef = React98.useRef(width);
30401
+ widthRef.current = width;
30402
+ const heightRef = React98.useRef(height);
30403
+ heightRef.current = height;
30395
30404
  const loadImage = React98.useCallback((url) => {
30396
- const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
30405
+ const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
30397
30406
  const cached = imageCache.current.get(fullUrl);
30398
30407
  if (cached?.complete && cached.naturalWidth > 0) return cached;
30399
30408
  if (!cached) {
@@ -30403,7 +30412,7 @@ function GameCanvas2D({
30403
30412
  imageCache.current.set(fullUrl, img);
30404
30413
  }
30405
30414
  return null;
30406
- }, [assetBaseUrl]);
30415
+ }, []);
30407
30416
  React98.useEffect(() => {
30408
30417
  const canvas = canvasRef.current;
30409
30418
  if (!canvas) return;
@@ -30425,10 +30434,10 @@ function GameCanvas2D({
30425
30434
  if (tickEventRef.current) {
30426
30435
  emitRef.current(tickEventRef.current, { dt, frame });
30427
30436
  }
30428
- if (backgroundImage) {
30429
- const bgImg = loadImage(backgroundImage);
30437
+ if (backgroundImageRef.current) {
30438
+ const bgImg = loadImage(backgroundImageRef.current);
30430
30439
  if (bgImg) {
30431
- ctx.drawImage(bgImg, 0, 0, width, height);
30440
+ ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
30432
30441
  }
30433
30442
  }
30434
30443
  onDrawRef.current?.(ctx, frame);
@@ -30444,7 +30453,7 @@ function GameCanvas2D({
30444
30453
  running = false;
30445
30454
  cancelAnimationFrame(rafRef.current);
30446
30455
  };
30447
- }, [fps]);
30456
+ }, [fps, loadImage]);
30448
30457
  return /* @__PURE__ */ jsx(Box, { className: cn("inline-block", className), children: /* @__PURE__ */ jsx(
30449
30458
  "canvas",
30450
30459
  {
@@ -31586,15 +31595,22 @@ function PlatformerCanvas({
31586
31595
  const eventBus = useEventBus();
31587
31596
  const keysRef = useRef(/* @__PURE__ */ new Set());
31588
31597
  const imageCache = useRef(/* @__PURE__ */ new Map());
31598
+ const [loadedImages, setLoadedImages] = useState(/* @__PURE__ */ new Set());
31589
31599
  const loadImage = useCallback((url) => {
31590
31600
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
31591
31601
  const cached = imageCache.current.get(fullUrl);
31592
- if (cached?.complete && cached.naturalWidth > 0) return cached;
31602
+ if (cached?.complete && cached.naturalWidth > 0) {
31603
+ if (!loadedImages.has(fullUrl)) {
31604
+ setLoadedImages((prev) => new Set(prev).add(fullUrl));
31605
+ }
31606
+ return cached;
31607
+ }
31593
31608
  if (!cached) {
31594
31609
  const img = new Image();
31595
31610
  img.crossOrigin = "anonymous";
31596
31611
  img.src = fullUrl;
31597
31612
  img.onload = () => {
31613
+ setLoadedImages((prev) => new Set(prev).add(fullUrl));
31598
31614
  updateAssetStatus(fullUrl, "loaded");
31599
31615
  };
31600
31616
  img.onerror = () => {
@@ -31604,7 +31620,7 @@ function PlatformerCanvas({
31604
31620
  updateAssetStatus(fullUrl, "pending");
31605
31621
  }
31606
31622
  return null;
31607
- }, [assetBaseUrl]);
31623
+ }, [assetBaseUrl, loadedImages]);
31608
31624
  useEffect(() => {
31609
31625
  if (typeof window === "undefined") return;
31610
31626
  const canvas = canvasRef.current;
@@ -31786,7 +31802,7 @@ function PlatformerCanvas({
31786
31802
  ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
31787
31803
  ctx.fill();
31788
31804
  }
31789
- });
31805
+ }, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
31790
31806
  return /* @__PURE__ */ jsx(
31791
31807
  "canvas",
31792
31808
  {
@@ -33815,7 +33831,7 @@ function useSafeEventBus10() {
33815
33831
  }
33816
33832
  }
33817
33833
  function SortableListInner({
33818
- items: initialItems = EMPTY_ITEMS,
33834
+ items: initialItemsProp = EMPTY_ITEMS,
33819
33835
  renderItem,
33820
33836
  reorderEvent,
33821
33837
  reorderPayload,
@@ -33823,6 +33839,7 @@ function SortableListInner({
33823
33839
  className
33824
33840
  }) {
33825
33841
  const eventBus = useSafeEventBus10();
33842
+ const initialItems = Array.isArray(initialItemsProp) ? initialItemsProp : initialItemsProp ? [initialItemsProp] : [];
33826
33843
  const handleReorder = useCallback(
33827
33844
  (fromIndex, toIndex, item) => {
33828
33845
  eventBus.emit(`UI:${reorderEvent}`, {
@@ -37319,9 +37336,10 @@ var init_ReplyTree = __esm({
37319
37336
  showActions = true,
37320
37337
  className
37321
37338
  }) => {
37339
+ const nodeList = Array.isArray(nodes) ? nodes : nodes ? [nodes] : [];
37322
37340
  const [collapsedSet, setCollapsedSet] = useState(() => {
37323
37341
  const acc = /* @__PURE__ */ new Set();
37324
- collectInitiallyCollapsed(nodes, acc);
37342
+ collectInitiallyCollapsed(nodeList, acc);
37325
37343
  return acc;
37326
37344
  });
37327
37345
  const toggleCollapse = useCallback((id) => {
@@ -37335,10 +37353,10 @@ var init_ReplyTree = __esm({
37335
37353
  return next;
37336
37354
  });
37337
37355
  }, []);
37338
- if (nodes.length === 0) {
37356
+ if (nodeList.length === 0) {
37339
37357
  return /* @__PURE__ */ jsx(Box, { className: cn("text-sm text-muted-foreground", className), children: "No replies yet." });
37340
37358
  }
37341
- return /* @__PURE__ */ jsx(Box, { className: cn("flex flex-col gap-2 min-w-0", className), children: nodes.map((node) => /* @__PURE__ */ jsx(
37359
+ return /* @__PURE__ */ jsx(Box, { className: cn("flex flex-col gap-2 min-w-0", className), children: nodeList.map((node) => /* @__PURE__ */ jsx(
37342
37360
  ReplyTreeNode,
37343
37361
  {
37344
37362
  node,
@@ -34,4 +34,4 @@ export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElem
34
34
  /** onChange handler - accepts events from input, select, or textarea */
35
35
  onChange?: React.ChangeEventHandler<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>;
36
36
  }
37
- export declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>>;
37
+ export declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLSelectElement | HTMLInputElement | HTMLTextAreaElement>>;
@@ -8676,7 +8676,7 @@ var init_MapView = __esm({
8676
8676
  shadowSize: [41, 41]
8677
8677
  });
8678
8678
  L.Marker.prototype.options.icon = defaultIcon;
8679
- const { useEffect: useEffect72, useRef: useRef66, useCallback: useCallback128, useState: useState110 } = React80__namespace.default;
8679
+ const { useEffect: useEffect72, useRef: useRef66, useCallback: useCallback128, useState: useState111 } = React80__namespace.default;
8680
8680
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
8681
8681
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
8682
8682
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -8721,7 +8721,7 @@ var init_MapView = __esm({
8721
8721
  showAttribution = true
8722
8722
  }) {
8723
8723
  const eventBus = useEventBus2();
8724
- const [clickedPosition, setClickedPosition] = useState110(null);
8724
+ const [clickedPosition, setClickedPosition] = useState111(null);
8725
8725
  const handleMapClick = useCallback128((lat, lng) => {
8726
8726
  if (showClickedPin) {
8727
8727
  setClickedPosition({ lat, lng });
@@ -16427,6 +16427,7 @@ function CalendarGrid({
16427
16427
  swipeRightEvent,
16428
16428
  dayWindow = "auto"
16429
16429
  }) {
16430
+ const evs = Array.isArray(events2) ? events2 : events2 ? [events2] : [];
16430
16431
  const eventBus = useEventBus();
16431
16432
  const longPressTimer = React80.useRef(null);
16432
16433
  const resolvedWeekStart = React80.useMemo(
@@ -16475,7 +16476,7 @@ function CalendarGrid({
16475
16476
  [onEventClick]
16476
16477
  );
16477
16478
  const eventsForDayCount = React80.useCallback(
16478
- (day) => events2.filter(
16479
+ (day) => evs.filter(
16479
16480
  (ev) => new Date(ev.startTime).toDateString() === day.toDateString()
16480
16481
  ).length,
16481
16482
  [events2]
@@ -16590,7 +16591,7 @@ function CalendarGrid({
16590
16591
  }
16591
16592
  ) }),
16592
16593
  visibleDays.map((day) => {
16593
- const slotEvents = events2.filter(
16594
+ const slotEvents = evs.filter(
16594
16595
  (ev) => eventInSlot(ev, day, time)
16595
16596
  );
16596
16597
  const isToday = day.toDateString() === (/* @__PURE__ */ new Date()).toDateString();
@@ -25826,8 +25827,16 @@ function GameCanvas2D({
25826
25827
  drawEventRef.current = drawEvent;
25827
25828
  const emitRef = React80__namespace.useRef(emit);
25828
25829
  emitRef.current = emit;
25830
+ const assetBaseUrlRef = React80__namespace.useRef(assetBaseUrl);
25831
+ assetBaseUrlRef.current = assetBaseUrl;
25832
+ const backgroundImageRef = React80__namespace.useRef(backgroundImage);
25833
+ backgroundImageRef.current = backgroundImage;
25834
+ const widthRef = React80__namespace.useRef(width);
25835
+ widthRef.current = width;
25836
+ const heightRef = React80__namespace.useRef(height);
25837
+ heightRef.current = height;
25829
25838
  const loadImage = React80__namespace.useCallback((url) => {
25830
- const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
25839
+ const fullUrl = url.startsWith("http") ? url : `${assetBaseUrlRef.current}${url}`;
25831
25840
  const cached = imageCache.current.get(fullUrl);
25832
25841
  if (cached?.complete && cached.naturalWidth > 0) return cached;
25833
25842
  if (!cached) {
@@ -25837,7 +25846,7 @@ function GameCanvas2D({
25837
25846
  imageCache.current.set(fullUrl, img);
25838
25847
  }
25839
25848
  return null;
25840
- }, [assetBaseUrl]);
25849
+ }, []);
25841
25850
  React80__namespace.useEffect(() => {
25842
25851
  const canvas = canvasRef.current;
25843
25852
  if (!canvas) return;
@@ -25859,10 +25868,10 @@ function GameCanvas2D({
25859
25868
  if (tickEventRef.current) {
25860
25869
  emitRef.current(tickEventRef.current, { dt, frame });
25861
25870
  }
25862
- if (backgroundImage) {
25863
- const bgImg = loadImage(backgroundImage);
25871
+ if (backgroundImageRef.current) {
25872
+ const bgImg = loadImage(backgroundImageRef.current);
25864
25873
  if (bgImg) {
25865
- ctx.drawImage(bgImg, 0, 0, width, height);
25874
+ ctx.drawImage(bgImg, 0, 0, widthRef.current, heightRef.current);
25866
25875
  }
25867
25876
  }
25868
25877
  onDrawRef.current?.(ctx, frame);
@@ -25878,7 +25887,7 @@ function GameCanvas2D({
25878
25887
  running = false;
25879
25888
  cancelAnimationFrame(rafRef.current);
25880
25889
  };
25881
- }, [fps]);
25890
+ }, [fps, loadImage]);
25882
25891
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("inline-block", className), children: /* @__PURE__ */ jsxRuntime.jsx(
25883
25892
  "canvas",
25884
25893
  {
@@ -27072,15 +27081,22 @@ function PlatformerCanvas({
27072
27081
  const eventBus = useEventBus();
27073
27082
  const keysRef = React80.useRef(/* @__PURE__ */ new Set());
27074
27083
  const imageCache = React80.useRef(/* @__PURE__ */ new Map());
27084
+ const [loadedImages, setLoadedImages] = React80.useState(/* @__PURE__ */ new Set());
27075
27085
  const loadImage = React80.useCallback((url) => {
27076
27086
  const fullUrl = url.startsWith("http") ? url : `${assetBaseUrl}${url}`;
27077
27087
  const cached = imageCache.current.get(fullUrl);
27078
- if (cached?.complete && cached.naturalWidth > 0) return cached;
27088
+ if (cached?.complete && cached.naturalWidth > 0) {
27089
+ if (!loadedImages.has(fullUrl)) {
27090
+ setLoadedImages((prev) => new Set(prev).add(fullUrl));
27091
+ }
27092
+ return cached;
27093
+ }
27079
27094
  if (!cached) {
27080
27095
  const img = new Image();
27081
27096
  img.crossOrigin = "anonymous";
27082
27097
  img.src = fullUrl;
27083
27098
  img.onload = () => {
27099
+ setLoadedImages((prev) => new Set(prev).add(fullUrl));
27084
27100
  updateAssetStatus(fullUrl, "loaded");
27085
27101
  };
27086
27102
  img.onerror = () => {
@@ -27090,7 +27106,7 @@ function PlatformerCanvas({
27090
27106
  updateAssetStatus(fullUrl, "pending");
27091
27107
  }
27092
27108
  return null;
27093
- }, [assetBaseUrl]);
27109
+ }, [assetBaseUrl, loadedImages]);
27094
27110
  React80.useEffect(() => {
27095
27111
  if (typeof window === "undefined") return;
27096
27112
  const canvas = canvasRef.current;
@@ -27272,7 +27288,7 @@ function PlatformerCanvas({
27272
27288
  ctx.arc(ppx + eyeOffsetX + 7, eyeY, eyeSize, 0, Math.PI * 2);
27273
27289
  ctx.fill();
27274
27290
  }
27275
- });
27291
+ }, [player, platforms, worldWidth, worldHeight, canvasWidth, canvasHeight, followCamera, bgColor, playerSprite, tileSprites, backgroundImage, assetBaseUrl, loadedImages]);
27276
27292
  return /* @__PURE__ */ jsxRuntime.jsx(
27277
27293
  "canvas",
27278
27294
  {
@@ -29323,7 +29339,7 @@ function useSafeEventBus10() {
29323
29339
  }
29324
29340
  }
29325
29341
  function SortableListInner({
29326
- items: initialItems = EMPTY_ITEMS,
29342
+ items: initialItemsProp = EMPTY_ITEMS,
29327
29343
  renderItem,
29328
29344
  reorderEvent,
29329
29345
  reorderPayload,
@@ -29331,6 +29347,7 @@ function SortableListInner({
29331
29347
  className
29332
29348
  }) {
29333
29349
  const eventBus = useSafeEventBus10();
29350
+ const initialItems = Array.isArray(initialItemsProp) ? initialItemsProp : initialItemsProp ? [initialItemsProp] : [];
29334
29351
  const handleReorder = React80.useCallback(
29335
29352
  (fromIndex, toIndex, item) => {
29336
29353
  eventBus.emit(`UI:${reorderEvent}`, {
@@ -32827,9 +32844,10 @@ var init_ReplyTree = __esm({
32827
32844
  showActions = true,
32828
32845
  className
32829
32846
  }) => {
32847
+ const nodeList = Array.isArray(nodes) ? nodes : nodes ? [nodes] : [];
32830
32848
  const [collapsedSet, setCollapsedSet] = React80.useState(() => {
32831
32849
  const acc = /* @__PURE__ */ new Set();
32832
- collectInitiallyCollapsed(nodes, acc);
32850
+ collectInitiallyCollapsed(nodeList, acc);
32833
32851
  return acc;
32834
32852
  });
32835
32853
  const toggleCollapse = React80.useCallback((id) => {
@@ -32843,10 +32861,10 @@ var init_ReplyTree = __esm({
32843
32861
  return next;
32844
32862
  });
32845
32863
  }, []);
32846
- if (nodes.length === 0) {
32864
+ if (nodeList.length === 0) {
32847
32865
  return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("text-sm text-muted-foreground", className), children: "No replies yet." });
32848
32866
  }
32849
- return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("flex flex-col gap-2 min-w-0", className), children: nodes.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
32867
+ return /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("flex flex-col gap-2 min-w-0", className), children: nodeList.map((node) => /* @__PURE__ */ jsxRuntime.jsx(
32850
32868
  ReplyTreeNode,
32851
32869
  {
32852
32870
  node,